diff --git a/.config/example.yml b/.config/example.yml index 9082dfb868..17149f6c3a 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -178,19 +178,13 @@ logLevel: [ # Media Proxy #mediaProxy: https://example.com/proxy -# Proxy remote files (default: false) +# Proxy remote files (default: true) #proxyRemoteFiles: true #allowedPrivateNetworks: [ # '127.0.0.1/32' #] -# TWA -#twa: -# nameSpace: android_app -# packageName: tld.domain.twa -# sha256CertFingerprints: ['AB:CD:EF'] - # Upload or download file size limits (bytes) #maxFileSize: 262144000 diff --git a/.dockerignore b/.dockerignore index f1c6bfd84a..3819d675c8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,7 +10,7 @@ node_modules report.*.json # Rust -packages/backend-rs/target +/target # Coverage coverage diff --git a/.gitignore b/.gitignore index 8ad525d636..beb0b8df5c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,9 @@ packages/backend/.idea/vcs.xml node_modules report.*.json +# Cargo +/target + # Cypress cypress/screenshots cypress/videos diff --git a/.gitlab/issue_templates/bug.md b/.gitlab/issue_templates/bug.md index b02cf3b4d0..f96bdec01e 100644 --- a/.gitlab/issue_templates/bug.md +++ b/.gitlab/issue_templates/bug.md @@ -3,27 +3,47 @@ 🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md) 🤝 By submitting this issue, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) --> -**What happened?** _(Please give us a brief description of what happened.)_ +## What happened? -**What did you expect to happen?** _(Please give us a brief description of what you expected to happen.)_ -**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_ +## What did you expect to happen? -**Instance** _(What instance of firefish are you using?)_ -**What type of issue is this?** _(If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side.)_ +## Version -**What browser are you using? (Client-side issues only)** -**What operating system are you using? (Client-side issues only)** +## What type of issue is this? -**How do you deploy Firefish on your server? (Server-side issues only)** +- [ ] server-side +- [ ] client-side +- [ ] not sure -**What operating system are you using? (Server-side issues only)** +
-**Relevant log output** _(Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks.)_ +### Instance -**Contribution Guidelines** + +### What browser are you using? (client-side issues only) + + +### What operating system are you using? (client-side issues only) + + +### How do you deploy Firefish on your server? (server-side issues only) + + +### What operating system are you using? (Server-side issues only) + + +### Relevant log output + + +
+ +## Contribution Guidelines By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) - [ ] I agree to follow this project's Contribution Guidelines - [ ] I have searched the issue tracker for similar issues, and this is not a duplicate. + +## Are you willing to fix this bug? (optional) +- [ ] Yes. I will fix this bug and open a merge request if the change is agreed upon. diff --git a/.gitlab/issue_templates/feature.md b/.gitlab/issue_templates/feature.md index 0593b5f61a..4c9ee56226 100644 --- a/.gitlab/issue_templates/feature.md +++ b/.gitlab/issue_templates/feature.md @@ -3,15 +3,22 @@ 🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md) 🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) --> -**What feature would you like implemented?** _(Please give us a brief description of what you'd like.)_ +## What feature would you like implemented? -**Why should we add this feature?** _(Please give us a brief description of why your feature is important.)_ -**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_ +## Why should we add this feature? -**Instance** _(What instance of firefish are you using?)_ -**Contribution Guidelines** +## Version + + +## Instance + + +## Contribution Guidelines By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) - [ ] I agree to follow this project's Contribution Guidelines - [ ] I have searched the issue tracker for similar requests, and this is not a duplicate. + +## Are you willing to implement this feature? (optional) +- [ ] Yes. I will implement this feature and open a merge request if the change is agreed upon. diff --git a/.gitlab/merge_request_templates/default.md b/.gitlab/merge_request_templates/default.md index 4672f6a30c..d13a146da0 100644 --- a/.gitlab/merge_request_templates/default.md +++ b/.gitlab/merge_request_templates/default.md @@ -1,9 +1,11 @@ -**What does this PR do?** _(Please give us a brief description of what this PR does.)_ +## What does this PR do? -**Contribution Guidelines** + +## Contribution Guidelines By submitting this merge request, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) +- [ ] This change is reviewed in an issue / This is a minor bug fix - [ ] I agree to follow this project's Contribution Guidelines - [ ] I have made sure to test this pull request - [ ] I have made sure to run `pnpm run format` before submitting this pull request @@ -12,4 +14,4 @@ If this merge request makes changes to the Firefish API, please update `docs/api - [ ] I updated the document / This merge request doesn't include API changes - + diff --git a/.gitlab/merge_request_templates/release.md b/.gitlab/merge_request_templates/release.md index b16db00212..ea40f38813 100644 --- a/.gitlab/merge_request_templates/release.md +++ b/.gitlab/merge_request_templates/release.md @@ -10,6 +10,7 @@ I have updated... - [ ] `docs/changelog.md` - [ ] `docs/notice-for-admins.md` - [ ] `docs/api-change.md` +- [ ] `packages/backend-rs/index.js` - [ ] OCI container image diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0083604d44..de0385be2a 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -12,6 +12,7 @@ "esbenp.prettier-vscode", "redhat.vscode-yaml", "yoavbls.pretty-ts-errors", - "biomejs.biome" + "biomejs.biome", + "rust-lang.rust-analyzer" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 64b14985cd..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rust-analyzer.linkedProjects": [ - "packages/backend-rs/Cargo.toml" - ] -} diff --git a/COPYING b/COPYING index 5b35f69f26..0621b4a8e6 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,7 @@ Unless specified otherwise, the entirety of this repository is subject to the following: Copyright © 2014-2023 syuilo and contributors Copyright © 2022-2023 Kainoa Kanter and contributors +Copyright © 2024 Firefish contributors And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE. @@ -13,6 +14,7 @@ These specific configuration directories: and their contents are Copyright © 2022-2023 Kainoa Kanter and contributors +Copyright © 2024 Firefish contributors And are distributed under The Apache License, Version 2.0, you should have received a copy of the license file as LICENSE in each specified directory. diff --git a/packages/backend-rs/Cargo.lock b/Cargo.lock similarity index 89% rename from packages/backend-rs/Cargo.lock rename to Cargo.lock index 02d294df58..c6ba96e683 100644 --- a/packages/backend-rs/Cargo.lock +++ b/Cargo.lock @@ -59,9 +59,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-tzdata" @@ -128,9 +128,21 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] [[package]] name = "arrayvec" @@ -157,18 +169,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -190,12 +202,17 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" name = "backend-rs" version = "0.0.0" dependencies = [ + "argon2", "async-trait", "basen", + "bcrypt", "cfg-if", "chrono", "cuid2", + "emojis", + "idna", "jsonschema", + "macro_rs", "napi", "napi-build", "napi-derive", @@ -203,12 +220,16 @@ dependencies = [ "parse-display", "pretty_assertions", "rand", + "regex", "schemars", "sea-orm", "serde", "serde_json", + "serde_yaml", "thiserror", "tokio", + "url", + "urlencoding", ] [[package]] @@ -232,6 +253,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "base64ct" version = "1.6.0" @@ -244,6 +271,19 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dbe4bb73fd931c4d1aaf53b35d1286c8a948ad00ec92c8e3c856f15fd027f43" +[[package]] +name = "bcrypt" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7" +dependencies = [ + "base64 0.22.0", + "blowfish", + "getrandom", + "subtle", + "zeroize", +] + [[package]] name = "bigdecimal" version = "0.3.1" @@ -297,6 +337,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -307,10 +356,20 @@ dependencies = [ ] [[package]] -name = "borsh" -version = "1.3.1" +name = "blowfish" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "borsh" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6" dependencies = [ "borsh-derive", "cfg_aliases", @@ -318,23 +377,23 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" +checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "syn_derive", ] [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytecheck" @@ -378,9 +437,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" [[package]] name = "cfg-if" @@ -396,9 +455,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -406,7 +465,17 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.5", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", ] [[package]] @@ -440,7 +509,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -497,9 +566,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.0.1" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] @@ -542,7 +611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c" dependencies = [ "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -565,9 +634,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -627,18 +696,27 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" dependencies = [ "serde", ] [[package]] -name = "encoding_rs" -version = "0.8.33" +name = "emojis" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "4ee61eb945bff65ee7d19d157d39c67c33290ff0742907413fd5eefd29edc979" +dependencies = [ + "phf", +] + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -839,9 +917,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "js-sys", @@ -858,9 +936,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -1066,7 +1144,16 @@ checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", ] [[package]] @@ -1116,7 +1203,7 @@ checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978" dependencies = [ "ahash 0.8.11", "anyhow", - "base64", + "base64 0.21.7", "bytecount", "clap", "fancy-regex", @@ -1169,7 +1256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1211,6 +1298,18 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "macro_rs" +version = "0.0.0" +dependencies = [ + "convert_case", + "napi", + "proc-macro2", + "quote", + "syn 2.0.58", + "thiserror", +] + [[package]] name = "md-5" version = "0.10.6" @@ -1223,9 +1322,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mime" @@ -1261,43 +1360,46 @@ dependencies = [ [[package]] name = "napi" -version = "2.16.1" +version = "2.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ca998356d8ff9fba7a070dae4508a2298439c98c9f3bc9c07669538b999e8f" +checksum = "70d04890ef4ec001fad791be785b8b920e2a3f5a6b1188e7a81dfa6197c0dee4" dependencies = [ "bitflags 2.5.0", + "chrono", "ctor", "napi-derive", "napi-sys", "once_cell", + "serde", + "serde_json", "tokio", ] [[package]] name = "napi-build" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9130fccc5f763cf2069b34a089a18f0d0883c66aceb81f2fad541a3d823c43" +checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" [[package]] name = "napi-derive" -version = "2.16.1" +version = "2.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b138cecf1141ae0ff5d62f4aa0e2f269aec339f66070f346ba6fb4279f1fc178" +checksum = "aff4a63f26a7aa9fa25df6ea36675890115972b207ae516e86bd0c47e31eba39" dependencies = [ "cfg-if", "convert_case", "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] name = "napi-derive-backend" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5126b64f6ad9e28e30e6d15213dd378626b38f556454afebc42f7f02a90902" +checksum = "e5e76afe642e2424ebe465406e328e4316d82af1f79256231d4b0f184c67550a" dependencies = [ "convert_case", "once_cell", @@ -1305,14 +1407,14 @@ dependencies = [ "quote", "regex", "semver", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] name = "napi-sys" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2503fa6af34dc83fb74888df8b22afe933b58d37daf7d80424b1c60c68196b8b" +checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" dependencies = [ "libloading", ] @@ -1329,9 +1431,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" dependencies = [ "num-bigint", "num-complex", @@ -1487,7 +1589,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -1515,28 +1617,38 @@ dependencies = [ [[package]] name = "parse-display" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6509d08722b53e8dafe97f2027b22ccbe3a5db83cb352931e9716b0aa44bc5c" +checksum = "06af5f9333eb47bd9ba8462d612e37a8328a5cb80b13f0af4de4c3b89f52dee5" dependencies = [ - "once_cell", "parse-display-derive", "regex", + "regex-syntax", ] [[package]] name = "parse-display-derive" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68517892c8daf78da08c0db777fcc17e07f2f63ef70041718f8a7630ad84f341" +checksum = "dc9252f259500ee570c75adcc4e317fa6f57a1e47747d622e0bf838002a7b790" dependencies = [ - "once_cell", "proc-macro2", "quote", "regex", - "regex-syntax 0.7.5", + "regex-syntax", "structmeta", - "syn 2.0.55", + "syn 2.0.58", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", ] [[package]] @@ -1561,10 +1673,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] -name = "pin-project-lite" -version = "0.2.13" +name = "phf" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1685,9 +1815,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1746,7 +1876,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.2", + "regex-syntax", ] [[package]] @@ -1757,20 +1887,14 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rend" @@ -1787,7 +1911,7 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -1883,9 +2007,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.34.3" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39449a79f45e8da28c57c341891b69a183044b29518bb8f86dbac9df60bb7df" +checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" dependencies = [ "arrayvec", "borsh", @@ -1933,7 +2057,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", ] [[package]] @@ -2003,7 +2127,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -2044,7 +2168,7 @@ dependencies = [ "proc-macro2", "quote", "sea-bae", - "syn 2.0.55", + "syn 2.0.58", "unicode-ident", ] @@ -2110,7 +2234,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -2147,6 +2271,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1" version = "0.10.6" @@ -2204,6 +2341,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -2371,7 +2514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", - "base64", + "base64 0.21.7", "bigdecimal", "bitflags 2.5.0", "byteorder", @@ -2418,7 +2561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", - "base64", + "base64 0.21.7", "bigdecimal", "bitflags 2.5.0", "byteorder", @@ -2500,31 +2643,31 @@ dependencies = [ [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "structmeta" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ad9e09554f0456d67a69c1584c9798ba733a5b50349a6c0d0948710523922d" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] name = "structmeta-derive" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -2552,9 +2695,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -2570,7 +2713,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -2635,14 +2778,14 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -2661,9 +2804,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", @@ -2686,9 +2829,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -2711,7 +2854,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -2782,7 +2925,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] @@ -2839,6 +2982,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -2931,7 +3080,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -2965,7 +3114,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3008,7 +3157,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -3026,7 +3175,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -3046,17 +3195,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -3067,9 +3217,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -3079,9 +3229,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -3091,9 +3241,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -3103,9 +3259,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -3115,9 +3271,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -3127,9 +3283,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -3139,9 +3295,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" @@ -3194,7 +3350,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.58", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..7ca43c960b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,42 @@ +[workspace] +members = ["packages/backend-rs", "packages/macro-rs"] +resolver = "2" + +[workspace.dependencies] +macro_rs = { path = "packages/macro-rs" } + +napi = { version = "2.16.2", default-features = false } +napi-derive = "2.16.2" +napi-build = "2.1.3" + +argon2 = "0.5.3" +async-trait = "0.1.80" +basen = "0.1.0" +bcrypt = "0.15.1" +cfg-if = "1.0.0" +chrono = "0.4.37" +convert_case = "0.6.0" +cuid2 = "0.1.2" +emojis = "0.6.1" +idna = "0.5.0" +jsonschema = "0.17.1" +once_cell = "1.19.0" +parse-display = "0.9.0" +pretty_assertions = "1.4.0" +proc-macro2 = "1.0.79" +quote = "1.0.36" +rand = "0.8.5" +regex = "1.10.4" +schemars = "0.8.16" +sea-orm = "0.12.15" +serde = "1.0.197" +serde_json = "1.0.115" +serde_yaml = "0.9.34" +syn = "2.0.58" +thiserror = "1.0.58" +tokio = "1.37.0" +url = "2.5.0" +urlencoding = "2.1.3" + +[profile.release] +lto = true diff --git a/Dockerfile b/Dockerfile index b19001772a..65c37e32b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,12 @@ RUN curl --proto '=https' --tlsv1.2 --silent --show-error --fail https://sh.rust ENV PATH="/root/.cargo/bin:${PATH}" # Copy only the cargo dependency-related files first, to cache efficiently +COPY Cargo.toml Cargo.toml +COPY Cargo.lock Cargo.lock COPY packages/backend-rs/Cargo.toml packages/backend-rs/Cargo.toml -COPY packages/backend-rs/Cargo.lock packages/backend-rs/Cargo.lock COPY packages/backend-rs/src/lib.rs packages/backend-rs/src/ +COPY packages/macro-rs/Cargo.toml packages/macro-rs/Cargo.toml +COPY packages/macro-rs/src/lib.rs packages/macro-rs/src/ # Install cargo dependencies RUN cargo fetch --locked --manifest-path /firefish/packages/backend-rs/Cargo.toml diff --git a/Makefile b/Makefile index 37dc019648..55c711855c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ export .PHONY: pre-commit -pre-commit: format entities update-index-js +pre-commit: format entities napi-index .PHONY: format format: @@ -14,9 +14,9 @@ entities: pnpm run migrate $(MAKE) -C ./packages/backend-rs regenerate-entities -.PHONY: update-index-js -update-index-js: - $(MAKE) -C ./packages/backend-rs index.js +.PHONY: napi-index +napi-index: + $(MAKE) -C ./packages/backend-rs update-index .PHONY: build @@ -27,13 +27,13 @@ build: pnpm run migrate -.PHONY: db.init db.up db.down -db.init: - $(MAKE) -C ./dev/db-container init +.PHONY: db.up db.down db.init db.up: $(MAKE) -C ./dev/db-container up db.down: $(MAKE) -C ./dev/db-container down +db.init: + $(MAKE) -C ./dev/db-container init .PHONY: psql redis-cli psql: diff --git a/biome.json b/biome.json index 2fa6846b64..21b711f457 100644 --- a/biome.json +++ b/biome.json @@ -1,12 +1,31 @@ { - "$schema": "https://biomejs.dev/schemas/1.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/1.6.4/schema.json", "organizeImports": { - "enabled": true + "enabled": false }, "linter": { "enabled": true, "rules": { - "recommended": true + "recommended": true, + "style": { + "noUselessElse": "off" + } } - } + }, + "overrides": [ + { + "include": ["*.vue"], + "linter": { + "rules": { + "style": { + "useImportType": "warn", + "useShorthandFunctionType": "warn", + "useTemplate": "warn", + "noNonNullAssertion": "off", + "useNodejsImportProtocol": "off" + } + } + } + } + ] } diff --git a/dev/db-container/Makefile b/dev/db-container/Makefile index 0238308de4..a762e95110 100644 --- a/dev/db-container/Makefile +++ b/dev/db-container/Makefile @@ -1,9 +1,11 @@ -.PHONY: init up down -init: down up +.PHONY: up down init up: $(COMPOSE) up --detach down: $(COMPOSE) down +init: + $(COMPOSE) down --volumes + $(COMPOSE) up --detach .PHONY: psql redis-cli psql: diff --git a/dev/db-container/docker-compose.yml b/dev/db-container/docker-compose.yml index 4cd121d2d4..770d8fb18d 100644 --- a/dev/db-container/docker-compose.yml +++ b/dev/db-container/docker-compose.yml @@ -5,6 +5,8 @@ services: image: docker.io/redis:7-alpine ports: - "26379:6379" + volumes: + - "redis-data:/data" db: image: docker.io/groonga/pgroonga:3.1.8-alpine-12 env_file: @@ -13,3 +15,10 @@ services: - "25432:5432" volumes: - "./install.sql:/docker-entrypoint-initdb.d/install.sql:ro" + - "postgres-data:/var/lib/postgresql/data" + +volumes: + redis-data: + name: redis-data + postgres-data: + name: postgres-data diff --git a/dev/docs/local-installation.md b/dev/docs/local-installation.md index 154f768037..15c7dad7d4 100644 --- a/dev/docs/local-installation.md +++ b/dev/docs/local-installation.md @@ -42,6 +42,8 @@ cargo --version ### PostgreSQL and PGroonga +Firefish requires PostgreSQL v12 or later. We recommend that you install v12.x for the same reason as Node.js. + PostgreSQL install instructions can be found at [this page](https://www.postgresql.org/download/). ```sh diff --git a/docker-compose.example.yml b/docker-compose.example.yml index fc6c0268a2..9cd6d1cdce 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -17,6 +17,7 @@ services: # - web environment: NODE_ENV: production + NODE_OPTIONS: --max-old-space-size=3072 volumes: - ./custom:/firefish/custom:ro - ./files:/firefish/files diff --git a/docs/api-change.md b/docs/api-change.md index fdda2e78b4..dcd4329a27 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -2,6 +2,18 @@ Breaking changes are indicated by the :warning: icon. +## Unreleased + +- Added `antennaLimit` field to the response of `meta` and `admin/meta`, and the request of `admin/update-meta` (optional). + +## v20240413 + +- :warning: Removed `patrons` endpoint. + +## v20240405 + +- Added `notes/history` endpoint. + ## v20240319 - :warning: `followingCount` and `followersCount` in `users/show` will be `null` (instead of 0) if these values are unavailable. diff --git a/docs/changelog.md b/docs/changelog.md index cd553ea014..70f8b34fbe 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,6 +5,27 @@ Critical security updates are indicated by the :warning: icon. - Server administrators should check [notice-for-admins.md](./notice-for-admins.md) as well. - Third-party client/bot developers may want to check [api-change.md](./api-change.md) as well. +## [v20240421](https://firefish.dev/firefish/firefish/-/merge_requests/10756/commits) + +- Fix bugs + +## [v20240413](https://firefish.dev/firefish/firefish/-/merge_requests/10741/commits) + +- Add "Media" tab to user page +- Improve federation and rendering of mathematical expressions +- Remove donor information from the web client + - See also: https://info.firefish.dev/notes/9s1n283sb10rh869 +- Fix bugs + +## [v20240405](https://firefish.dev/firefish/firefish/-/merge_requests/10733/commits) + +- Add ability to view the history of post edits (!10714) +- Fix bugs + +## [v20240401](https://firefish.dev/firefish/firefish/-/merge_requests/10724/commits) + +- Fix bugs + ## :warning: [v20240330](https://firefish.dev/firefish/firefish/-/merge_requests/10719/commits) - Fix bugs (including a critical security issue) diff --git a/docs/downgrade.sql b/docs/downgrade.sql index 88e08c40ad..44222f818f 100644 --- a/docs/downgrade.sql +++ b/docs/downgrade.sql @@ -1,6 +1,11 @@ BEGIN; DELETE FROM "migrations" WHERE name IN ( + 'AddDriveFileUsage1713451569342', + 'ConvertCwVarcharToText1713225866247', + 'FixChatFileConstraint1712855579316', + 'DropTimeZone1712425488543', + 'ExpandNoteEdit1711936358554', 'markLocalFilesNsfwByDefault1709305200000', 'FixMutingIndices1710690239308', 'NoteFile1710304584214', @@ -19,6 +24,99 @@ DELETE FROM "migrations" WHERE name IN ( 'RemoveNativeUtilsMigration1705877093218' ); +-- AddDriveFileUsage +ALTER TABLE "drive_file" DROP COLUMN "usageHint"; +DROP TYPE "drive_file_usage_hint_enum"; + +-- convert-cw-varchar-to-text +DROP INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f"; +ALTER TABLE "note" ALTER COLUMN "cw" TYPE character varying(512); +CREATE INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f" ON "note" USING "pgroonga" ("cw" pgroonga_varchar_full_text_search_ops_v2); + +-- fix-chat-file-constraint +ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_535def119223ac05ad3fa9ef64b"; +ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_535def119223ac05ad3fa9ef64b" FOREIGN KEY ("fileId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION; + +-- drop-time-zone +ALTER TABLE "abuse_user_report" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "access_token" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "access_token" ALTER "lastUsedAt" TYPE timestamp with time zone; +ALTER TABLE "ad" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "ad" ALTER "expiresAt" TYPE timestamp with time zone; +ALTER TABLE "announcement" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "announcement" ALTER "updatedAt" TYPE timestamp with time zone; +ALTER TABLE "announcement_read" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "antenna" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "app" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "attestation_challenge" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "auth_session" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "blocking" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "channel" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "channel" ALTER "lastNotedAt" TYPE timestamp with time zone; +ALTER TABLE "channel_following" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "channel_note_pining" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "clip" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "drive_file" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "drive_folder" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "emoji" ALTER "updatedAt" TYPE timestamp with time zone; +ALTER TABLE "following" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "follow_request" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "gallery_like" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "gallery_post" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "gallery_post" ALTER "updatedAt" TYPE timestamp with time zone; +ALTER TABLE "instance" ALTER "caughtAt" TYPE timestamp with time zone; +ALTER TABLE "instance" ALTER "infoUpdatedAt" TYPE timestamp with time zone; +ALTER TABLE "instance" ALTER "lastCommunicatedAt" TYPE timestamp with time zone; +ALTER TABLE "instance" ALTER "latestRequestReceivedAt" TYPE timestamp with time zone; +ALTER TABLE "instance" ALTER "latestRequestSentAt" TYPE timestamp with time zone; +ALTER TABLE "messaging_message" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "moderation_log" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "muting" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "muting" ALTER "expiresAt" TYPE timestamp with time zone; +ALTER TABLE "note" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "note" ALTER "updatedAt" TYPE timestamp with time zone; +ALTER TABLE "note_edit" ALTER "updatedAt" TYPE timestamp with time zone; +ALTER TABLE "note_favorite" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "note_reaction" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "note_thread_muting" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "note_watching" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "notification" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "page" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "page" ALTER "updatedAt" TYPE timestamp with time zone; +ALTER TABLE "page_like" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "password_reset_request" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "poll" ALTER "expiresAt" TYPE timestamp with time zone; +ALTER TABLE "poll_vote" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "promo_note" ALTER "expiresAt" TYPE timestamp with time zone; +ALTER TABLE "promo_read" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "registration_ticket" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "registry_item" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "registry_item" ALTER "updatedAt" TYPE timestamp with time zone; +ALTER TABLE "renote_muting" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "reply_muting" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "signin" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "sw_subscription" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "used_username" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user" ALTER "lastActiveDate" TYPE timestamp with time zone; +ALTER TABLE "user" ALTER "lastFetchedAt" TYPE timestamp with time zone; +ALTER TABLE "user" ALTER "updatedAt" TYPE timestamp with time zone; +ALTER TABLE "user_group" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_group_invitation" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_group_invite" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_group_joining" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_ip" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_list" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_list_joining" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_note_pining" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_pending" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "user_security_key" ALTER "lastUsed" TYPE timestamp with time zone; +ALTER TABLE "webhook" ALTER "createdAt" TYPE timestamp with time zone; +ALTER TABLE "webhook" ALTER "latestSentAt" TYPE timestamp with time zone; + +-- expand-note-edit +ALTER TABLE "note_edit" DROP COLUMN "emojis"; + -- markLocalFilesNsfwByDefault ALTER TABLE "meta" DROP COLUMN "markLocalFilesNsfwByDefault"; diff --git a/docs/install.md b/docs/install.md index 061000fa32..0e850e2545 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,9 +1,36 @@ # Install Firefish -This document shows an example procedure for installing Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation. +Firefish depends on the following software. + +## Runtime dependencies + +- At least [NodeJS](https://nodejs.org/en/) v18.17.0 (v20/v21 recommended) +- At least [PostgreSQL](https://www.postgresql.org/) v12 (v16 recommended) with [PGroonga](https://pgroonga.github.io/) extension +- At least [Redis](https://redis.io/) v7 +- Web Proxy (one of the following) + - Caddy (recommended) + - Nginx (recommended) + - Apache +- [FFmpeg](https://ffmpeg.org/) for video transcoding (**optional**) +- Caching server (**optional**, one of the following) + - [DragonflyDB](https://www.dragonflydb.io/) + - [KeyDB](https://keydb.dev/) + - Another [Redis](https://redis.io/) server + +## Build dependencies + +- At least [Rust](https://www.rust-lang.org/) v1.74 +- C/C++ compiler & build tools + - `build-essential` on Debian/Ubuntu Linux + - `base-devel` on Arch Linux +- [Python 3](https://www.python.org/) + +This document shows an example procedure for installing these dependencies and Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation. If you want to use the pre-built container image, please refer to [`install-container.md`](./install-container.md). +If you do not prepare your environment as document, be sure to meet the minimum dependencies given at the bottom of the page. + Make sure that you can use the `sudo` command before proceeding. ## 1. Install dependencies @@ -154,7 +181,7 @@ sudo apt install ffmpeg 1. Build ```sh pnpm install --frozen-lockfile - NODE_ENV=production pnpm run build + NODE_ENV=production NODE_OPTIONS='--max-old-space-size=3072' pnpm run build ``` 1. Execute database migrations ```sh @@ -242,6 +269,7 @@ In this instruction, we use [Caddy](https://caddyserver.com/) to make the Firefi WorkingDirectory=/home/firefish/firefish Environment="NODE_ENV=production" Environment="npm_config_cache=/tmp" + Environment="NODE_OPTIONS=--max-old-space-size=3072" # uncomment the following line if you use jemalloc (note that the path varies on different environments) # Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2" StandardOutput=journal diff --git a/docs/notice-for-admins.md b/docs/notice-for-admins.md index 5c2eb9b966..9bff40a65c 100644 --- a/docs/notice-for-admins.md +++ b/docs/notice-for-admins.md @@ -2,6 +2,33 @@ You can skip intermediate versions when upgrading from an old version, but please read the notices and follow the instructions for each intermediate version before [upgrading](./upgrade.md). +## v20240413 + +### For all users + +Upgrading may take a long time due to the large changes in the database. Please make sure to perform the operations when you have time. + +The time required to upgrade varies greatly depending on the database size and the environment. For reference, we have checked that the database migration takes + +- 70 seconds if the database stores 600,000 posts +- 28 minutes if the database stores 12,000,000 posts + +(i.e., it takes roughly (𝑛 / 470,000) minutes where 𝑛 is the number of posts) on a server with 2 GB of RAM. You may want to tweak your database configuration (`postgres.conf`) if the process is significantly slower than our experimental result. + +The number of posts stored on your database can be found at `https://yourserver.example.com/admin/database` (or `notesCount` of `stats` API response). + +### For systemd/pm2 users + +- Please remove `packages/backend-rs/target` before building Firefish. + ```sh + rm --recursive --force packages/backend-rs/target + ``` +- Please do not terminate `pnpm run migrate` even if it appears to be frozen. + +### For Docker/Podman users + +You may not be able to access your server for a while after starting the container. + ## v20240326 ### For Docker/Podman users @@ -31,11 +58,11 @@ psql (PostgreSQL) 16.1 In this case, your PostgreSQL major version is `16`. -There are official installation instructions for many operating systems on , so please follow the instructions on this page. However, since many users are using Ubuntu, and there are no instructions for Arch Linux and Fedora, we explicitly list the instructions for Ubuntu, Arch Linux and Fedora here. Please keep in mind that this is not official information and the procedures may change. +There are official installation instructions for many operating systems on , so please follow the instructions on this page. However, since many users are using Ubuntu LTS or Debian, and there are no instructions for Arch Linux and Fedora, we explicitly list the instructions for Ubuntu LTS, Debian, Arch Linux and Fedora here. Please keep in mind that this is not official information and the procedures may change. -##### Ubuntu +##### Ubuntu LTS -1. Install subdependencies and add apt repository +1. Install subdependencies ```sh sudo apt install -y software-properties-common sudo add-apt-repository -y universe @@ -43,14 +70,35 @@ There are official installation instructions for many operating systems on + allowedPrivateNetworks?: Array + /** `NapiValue` is not implemented for `u64` */ + maxFileSize?: number + accessLog?: string + clusterLimits?: WorkerConfig + cuid?: IdConfig + outgoingAddress?: string + deliverJobConcurrency?: number + inboxJobConcurrency?: number + deliverJobPerSec?: number + inboxJobPerSec?: number + deliverJobMaxAttempts?: number + inboxJobMaxAttempts?: number + logLevel?: Array + syslog?: SysLogConfig + proxyRemoteFiles?: boolean + mediaProxy?: string + summalyProxyUrl?: string + reservedUsernames?: Array + maxUserSignups?: number + isManagedHosting?: boolean + maxNoteLength?: number + maxCaptionLength?: number + deepl?: DeepLConfig + libreTranslate?: LibreTranslateConfig + email?: EmailConfig + objectStorage?: ObjectStorageConfig +} +export interface DbConfig { + host: string + port: number + db: string + user: string + pass: string + disableCache?: boolean + extra?: any +} +export interface RedisConfig { + host: string + port: number + family?: number + user?: string + pass?: string + tls?: TlsConfig + db: number + prefix: string +} +export interface TlsConfig { + host: string + rejectUnauthorized: boolean +} +export interface WorkerConfig { + web?: number + queue?: number +} +export interface IdConfig { + length?: number + fingerprint?: string +} +export interface SysLogConfig { + host: string + port: number +} +export interface DeepLConfig { + managed?: boolean + authKey?: string + isPro?: boolean +} +export interface LibreTranslateConfig { + managed?: boolean + apiUrl?: string + apiKey?: string +} +export interface EmailConfig { + managed?: boolean + address?: string + host?: string + port?: number + user?: string + pass?: string + useImplicitSslTls?: boolean +} +export interface ObjectStorageConfig { + managed?: boolean + baseUrl?: string + bucket?: string + prefix?: string + endpoint?: string + region?: string + accessKey?: string + secretKey?: string + useSsl?: boolean + connnectOverProxy?: boolean + setPublicReadOnUpload?: boolean + s3ForcePathStyle?: boolean +} +export function readServerConfig(): ServerConfig +export interface Acct { + username: string + host: string | null +} +export function stringToAcct(acct: string): Acct +export function acctToString(acct: Acct): string +/** TODO: handle name collisions better */ +export interface NoteLikeForCheckWordMute { + fileIds: Array + userId: string | null + text: string | null + cw: string | null + renoteId: string | null + replyId: string | null +} +export function checkWordMute(note: NoteLikeForCheckWordMute, mutedWordLists: Array>, mutedPatterns: Array): Promise +export function getFullApAccount(username: string, host?: string | undefined | null): string +export function isSelfHost(host?: string | undefined | null): boolean +export function isSameOrigin(uri: string): boolean +export function extractHost(uri: string): string +export function toPuny(host: string): string +export function isUnicodeEmoji(s: string): boolean +export function sqlLikeEscape(src: string): string +export function safeForSql(src: string): boolean +/** Convert milliseconds to a human readable string */ +export function formatMilliseconds(milliseconds: number): string +/** TODO: handle name collisions better */ +export interface NoteLikeForGetNoteSummary { + fileIds: Array + text: string | null + cw: string | null + hasPoll: boolean +} +export function getNoteSummary(note: NoteLikeForGetNoteSummary): string +export function toMastodonId(firefishId: string): string | null +export function fromMastodonId(mastodonId: string): string | null +export function fetchMeta(useCache: boolean): Promise +export interface PugArgs { + img: string | null + title: string + instanceName: string + desc: string | null + icon: string | null + splashIcon: string | null + themeColor: string | null + randomMotd: string + privateMode: boolean | null +} +export function metaToPugArgs(meta: Meta): PugArgs +export function nyaify(text: string, lang?: string | undefined | null): string +export function hashPassword(password: string): string +export function verifyPassword(password: string, hash: string): boolean +export function isOldPasswordAlgorithm(hash: string): boolean +export interface DecodedReaction { + reaction: string + name: string | null + host: string | null +} +export function decodeReaction(reaction: string): DecodedReaction +export function countReactions(reactions: Record): Record +export function toDbReaction(reaction?: string | undefined | null, host?: string | undefined | null): Promise +export interface AbuseUserReport { + id: string + createdAt: Date + targetUserId: string + reporterId: string + assigneeId: string | null + resolved: boolean + comment: string + targetUserHost: string | null + reporterHost: string | null + forwarded: boolean +} +export interface AccessToken { + id: string + createdAt: Date + token: string + hash: string + userId: string + appId: string | null + lastUsedAt: Date | null + session: string | null + name: string | null + description: string | null + iconUrl: string | null + permission: Array + fetched: boolean +} +export interface Ad { + id: string + createdAt: Date + expiresAt: Date + place: string + priority: string + url: string + imageUrl: string + memo: string + ratio: number +} +export interface Announcement { + id: string + createdAt: Date + text: string + title: string + imageUrl: string | null + updatedAt: Date | null + showPopup: boolean + isGoodNews: boolean +} +export interface AnnouncementRead { + id: string + userId: string + announcementId: string + createdAt: Date +} +export interface Antenna { + id: string + createdAt: Date + userId: string + name: string + src: AntennaSrcEnum + userListId: string | null + keywords: Json + withFile: boolean + expression: string | null + notify: boolean + caseSensitive: boolean + withReplies: boolean + userGroupJoiningId: string | null + users: Array + excludeKeywords: Json + instances: Json +} +export interface App { + id: string + createdAt: Date + userId: string | null + secret: string + name: string + description: string + permission: Array + callbackUrl: string | null +} +export interface AttestationChallenge { + id: string + userId: string + challenge: string + createdAt: Date + registrationChallenge: boolean +} +export interface AuthSession { + id: string + createdAt: Date + token: string + userId: string | null + appId: string +} +export interface Blocking { + id: string + createdAt: Date + blockeeId: string + blockerId: string +} +export interface Channel { + id: string + createdAt: Date + lastNotedAt: Date | null + userId: string | null + name: string + description: string | null + bannerId: string | null + notesCount: number + usersCount: number +} +export interface ChannelFollowing { + id: string + createdAt: Date + followeeId: string + followerId: string +} +export interface ChannelNotePining { + id: string + createdAt: Date + channelId: string + noteId: string +} +export interface Clip { + id: string + createdAt: Date + userId: string + name: string + isPublic: boolean + description: string | null +} +export interface ClipNote { + id: string + noteId: string + clipId: string +} +export interface DriveFile { + id: string + createdAt: Date + userId: string | null + userHost: string | null + md5: string + name: string + type: string + size: number + comment: string | null + properties: Json + storedInternal: boolean + url: string + thumbnailUrl: string | null + webpublicUrl: string | null + accessKey: string | null + thumbnailAccessKey: string | null + webpublicAccessKey: string | null + uri: string | null + src: string | null + folderId: string | null + isSensitive: boolean + isLink: boolean + blurhash: string | null + webpublicType: string | null + requestHeaders: Json | null + requestIp: string | null + usageHint: DriveFileUsageHintEnum | null +} +export interface DriveFolder { + id: string + createdAt: Date + name: string + userId: string | null + parentId: string | null +} +export interface Emoji { + id: string + updatedAt: Date | null + name: string + host: string | null + originalUrl: string + uri: string | null + type: string | null + aliases: Array + category: string | null + publicUrl: string + license: string | null + width: number | null + height: number | null +} +export interface FollowRequest { + id: string + createdAt: Date + followeeId: string + followerId: string + requestId: string | null + followerHost: string | null + followerInbox: string | null + followerSharedInbox: string | null + followeeHost: string | null + followeeInbox: string | null + followeeSharedInbox: string | null +} +export interface Following { + id: string + createdAt: Date + followeeId: string + followerId: string + followerHost: string | null + followerInbox: string | null + followerSharedInbox: string | null + followeeHost: string | null + followeeInbox: string | null + followeeSharedInbox: string | null +} +export interface GalleryLike { + id: string + createdAt: Date + userId: string + postId: string +} +export interface GalleryPost { + id: string + createdAt: Date + updatedAt: Date + title: string + description: string | null + userId: string + fileIds: Array + isSensitive: boolean + likedCount: number + tags: Array +} +export interface Hashtag { + id: string + name: string + mentionedUserIds: Array + mentionedUsersCount: number + mentionedLocalUserIds: Array + mentionedLocalUsersCount: number + mentionedRemoteUserIds: Array + mentionedRemoteUsersCount: number + attachedUserIds: Array + attachedUsersCount: number + attachedLocalUserIds: Array + attachedLocalUsersCount: number + attachedRemoteUserIds: Array + attachedRemoteUsersCount: number +} +export interface Instance { + id: string + caughtAt: Date + host: string + usersCount: number + notesCount: number + followingCount: number + followersCount: number + latestRequestSentAt: Date | null + latestStatus: number | null + latestRequestReceivedAt: Date | null + lastCommunicatedAt: Date + isNotResponding: boolean + softwareName: string | null + softwareVersion: string | null + openRegistrations: boolean | null + name: string | null + description: string | null + maintainerName: string | null + maintainerEmail: string | null + infoUpdatedAt: Date | null + isSuspended: boolean + iconUrl: string | null + themeColor: string | null + faviconUrl: string | null +} +export interface MessagingMessage { + id: string + createdAt: Date + userId: string + recipientId: string | null + text: string | null + isRead: boolean + fileId: string | null + groupId: string | null + reads: Array + uri: string | null +} +export interface Meta { + id: string + name: string | null + description: string | null + maintainerName: string | null + maintainerEmail: string | null + disableRegistration: boolean + disableLocalTimeline: boolean + disableGlobalTimeline: boolean + useStarForReactionFallback: boolean + langs: Array + hiddenTags: Array + blockedHosts: Array + mascotImageUrl: string | null + bannerUrl: string | null + errorImageUrl: string | null + iconUrl: string | null + cacheRemoteFiles: boolean + enableRecaptcha: boolean + recaptchaSiteKey: string | null + recaptchaSecretKey: string | null + localDriveCapacityMb: number + remoteDriveCapacityMb: number + antennaLimit: number + summalyProxy: string | null + enableEmail: boolean + email: string | null + smtpSecure: boolean + smtpHost: string | null + smtpPort: number | null + smtpUser: string | null + smtpPass: string | null + enableServiceWorker: boolean + swPublicKey: string | null + swPrivateKey: string | null + pinnedUsers: Array + tosUrl: string | null + repositoryUrl: string + feedbackUrl: string | null + useObjectStorage: boolean + objectStorageBucket: string | null + objectStoragePrefix: string | null + objectStorageBaseUrl: string | null + objectStorageEndpoint: string | null + objectStorageRegion: string | null + objectStorageAccessKey: string | null + objectStorageSecretKey: string | null + objectStoragePort: number | null + objectStorageUseSsl: boolean + proxyAccountId: string | null + objectStorageUseProxy: boolean + enableHcaptcha: boolean + hcaptchaSiteKey: string | null + hcaptchaSecretKey: string | null + objectStorageSetPublicRead: boolean + pinnedPages: Array + backgroundImageUrl: string | null + logoImageUrl: string | null + pinnedClipId: string | null + objectStorageS3ForcePathStyle: boolean + allowedHosts: Array | null + secureMode: boolean | null + privateMode: boolean | null + deeplAuthKey: string | null + deeplIsPro: boolean + emailRequiredForSignup: boolean + themeColor: string | null + defaultLightTheme: string | null + defaultDarkTheme: string | null + enableIpLogging: boolean + enableActiveEmailValidation: boolean + customMotd: Array + customSplashIcons: Array + disableRecommendedTimeline: boolean + recommendedInstances: Array + enableGuestTimeline: boolean + defaultReaction: string + libreTranslateApiUrl: string | null + libreTranslateApiKey: string | null + silencedHosts: Array + experimentalFeatures: Json + enableServerMachineStats: boolean + enableIdenticonGeneration: boolean + donationLink: string | null + moreUrls: Json + markLocalFilesNsfwByDefault: boolean +} +export interface Migrations { + id: number + timestamp: number + name: string +} +export interface ModerationLog { + id: string + createdAt: Date + userId: string + type: string + info: Json +} +export interface MutedNote { + id: string + noteId: string + userId: string + reason: MutedNoteReasonEnum +} +export interface Muting { + id: string + createdAt: Date + muteeId: string + muterId: string + expiresAt: Date | null +} +export interface Note { + id: string + createdAt: Date + replyId: string | null + renoteId: string | null + text: string | null + name: string | null + cw: string | null + userId: string + localOnly: boolean + renoteCount: number + repliesCount: number + reactions: Json + visibility: NoteVisibilityEnum + uri: string | null + score: number + fileIds: Array + attachedFileTypes: Array + visibleUserIds: Array + mentions: Array + mentionedRemoteUsers: string + emojis: Array + tags: Array + hasPoll: boolean + userHost: string | null + replyUserId: string | null + replyUserHost: string | null + renoteUserId: string | null + renoteUserHost: string | null + url: string | null + channelId: string | null + threadId: string | null + updatedAt: Date | null + lang: string | null +} +export interface NoteEdit { + id: string + noteId: string + text: string | null + cw: string | null + fileIds: Array + updatedAt: Date + emojis: Array +} +export interface NoteFavorite { + id: string + createdAt: Date + userId: string + noteId: string +} +export interface NoteFile { + serialNo: number + noteId: string + fileId: string +} +export interface NoteReaction { + id: string + createdAt: Date + userId: string + noteId: string + reaction: string +} +export interface NoteThreadMuting { + id: string + createdAt: Date + userId: string + threadId: string +} +export interface NoteUnread { + id: string + userId: string + noteId: string + noteUserId: string + isSpecified: boolean + isMentioned: boolean + noteChannelId: string | null +} +export interface NoteWatching { + id: string + createdAt: Date + userId: string + noteId: string + noteUserId: string +} +export interface Notification { + id: string + createdAt: Date + notifieeId: string + notifierId: string | null + isRead: boolean + noteId: string | null + reaction: string | null + choice: number | null + followRequestId: string | null + type: NotificationTypeEnum + userGroupInvitationId: string | null + customBody: string | null + customHeader: string | null + customIcon: string | null + appAccessTokenId: string | null +} +export interface Page { + id: string + createdAt: Date + updatedAt: Date + title: string + name: string + summary: string | null + alignCenter: boolean + font: string + userId: string + eyeCatchingImageId: string | null + content: Json + variables: Json + visibility: PageVisibilityEnum + visibleUserIds: Array + likedCount: number + hideTitleWhenPinned: boolean + script: string + isPublic: boolean +} +export interface PageLike { + id: string + createdAt: Date + userId: string + pageId: string +} +export interface PasswordResetRequest { + id: string + createdAt: Date + token: string + userId: string +} +export interface Poll { + noteId: string + expiresAt: Date | null + multiple: boolean + choices: Array + votes: Array + noteVisibility: PollNotevisibilityEnum + userId: string + userHost: string | null +} +export interface PollVote { + id: string + createdAt: Date + userId: string + noteId: string + choice: number +} +export interface PromoNote { + noteId: string + expiresAt: Date + userId: string +} +export interface PromoRead { + id: string + createdAt: Date + userId: string + noteId: string +} +export interface RegistrationTicket { + id: string + createdAt: Date + code: string +} +export interface RegistryItem { + id: string + createdAt: Date + updatedAt: Date + userId: string + key: string + scope: Array + domain: string | null + value: Json | null +} +export interface Relay { + id: string + inbox: string + status: RelayStatusEnum +} +export interface RenoteMuting { + id: string + createdAt: Date + muteeId: string + muterId: string +} +export interface ReplyMuting { + id: string + createdAt: Date + muteeId: string + muterId: string +} +export enum AntennaSrcEnum { + All = 'all', + Group = 'group', + Home = 'home', + Instances = 'instances', + List = 'list', + Users = 'users' +} +export enum DriveFileUsageHintEnum { + UserAvatar = 'userAvatar', + UserBanner = 'userBanner' +} +export enum MutedNoteReasonEnum { + Manual = 'manual', + Other = 'other', + Spam = 'spam', + Word = 'word' +} +export enum NoteVisibilityEnum { + Followers = 'followers', + Hidden = 'hidden', + Home = 'home', + Public = 'public', + Specified = 'specified' +} +export enum NotificationTypeEnum { + App = 'app', + Follow = 'follow', + FollowRequestAccepted = 'followRequestAccepted', + GroupInvited = 'groupInvited', + Mention = 'mention', + PollEnded = 'pollEnded', + PollVote = 'pollVote', + Quote = 'quote', + Reaction = 'reaction', + ReceiveFollowRequest = 'receiveFollowRequest', + Renote = 'renote', + Reply = 'reply' +} +export enum PageVisibilityEnum { + Followers = 'followers', + Public = 'public', + Specified = 'specified' +} +export enum PollNotevisibilityEnum { + Followers = 'followers', + Home = 'home', + Public = 'public', + Specified = 'specified' +} +export enum RelayStatusEnum { + Accepted = 'accepted', + Rejected = 'rejected', + Requesting = 'requesting' +} +export enum UserEmojimodpermEnum { + Add = 'add', + Full = 'full', + Mod = 'mod', + Unauthorized = 'unauthorized' +} +export enum UserProfileFfvisibilityEnum { + Followers = 'followers', + Private = 'private', + Public = 'public' +} +export enum UserProfileMutingnotificationtypesEnum { + App = 'app', + Follow = 'follow', + FollowRequestAccepted = 'followRequestAccepted', + GroupInvited = 'groupInvited', + Mention = 'mention', + PollEnded = 'pollEnded', + PollVote = 'pollVote', + Quote = 'quote', + Reaction = 'reaction', + ReceiveFollowRequest = 'receiveFollowRequest', + Renote = 'renote', + Reply = 'reply' +} +export interface Signin { + id: string + createdAt: Date + userId: string + ip: string + headers: Json + success: boolean +} +export interface SwSubscription { + id: string + createdAt: Date + userId: string + endpoint: string + auth: string + publickey: string + sendReadMessage: boolean +} +export interface UsedUsername { + username: string + createdAt: Date +} +export interface User { + id: string + createdAt: Date + updatedAt: Date | null + lastFetchedAt: Date | null + username: string + usernameLower: string + name: string | null + followersCount: number + followingCount: number + notesCount: number + avatarId: string | null + bannerId: string | null + tags: Array + isSuspended: boolean + isSilenced: boolean + isLocked: boolean + isBot: boolean + isCat: boolean + isAdmin: boolean + isModerator: boolean + emojis: Array + host: string | null + inbox: string | null + sharedInbox: string | null + featured: string | null + uri: string | null + token: string | null + isExplorable: boolean + followersUri: string | null + lastActiveDate: Date | null + hideOnlineStatus: boolean + isDeleted: boolean + driveCapacityOverrideMb: number | null + movedToUri: string | null + alsoKnownAs: string | null + speakAsCat: boolean + emojiModPerm: UserEmojimodpermEnum + isIndexable: boolean +} +export interface UserGroup { + id: string + createdAt: Date + name: string + userId: string + isPrivate: boolean +} +export interface UserGroupInvitation { + id: string + createdAt: Date + userId: string + userGroupId: string +} +export interface UserGroupInvite { + id: string + createdAt: Date + userId: string + userGroupId: string +} +export interface UserGroupJoining { + id: string + createdAt: Date + userId: string + userGroupId: string +} +export interface UserIp { + id: number + createdAt: Date + userId: string + ip: string +} +export interface UserKeypair { + userId: string + publicKey: string + privateKey: string +} +export interface UserList { + id: string + createdAt: Date + userId: string + name: string +} +export interface UserListJoining { + id: string + createdAt: Date + userId: string + userListId: string +} +export interface UserNotePining { + id: string + createdAt: Date + userId: string + noteId: string +} +export interface UserPending { + id: string + createdAt: Date + code: string + username: string + email: string + password: string +} +export interface UserProfile { + userId: string + location: string | null + birthday: string | null + description: string | null + fields: Json + url: string | null + email: string | null + emailVerifyCode: string | null + emailVerified: boolean + twoFactorTempSecret: string | null + twoFactorSecret: string | null + twoFactorEnabled: boolean + password: string | null + clientData: Json + autoAcceptFollowed: boolean + alwaysMarkNsfw: boolean + carefulBot: boolean + userHost: string | null + securityKeysAvailable: boolean + usePasswordLessLogin: boolean + pinnedPageId: string | null + room: Json + injectFeaturedNote: boolean + enableWordMute: boolean + mutedWords: Json + mutingNotificationTypes: Array + noCrawle: boolean + receiveAnnouncementEmail: boolean + emailNotificationTypes: Json + mutedInstances: Json + publicReactions: boolean + ffVisibility: UserProfileFfvisibilityEnum + moderationNote: string + preventAiLearning: boolean + isIndexable: boolean + mutedPatterns: Array +} +export interface UserPublickey { + userId: string + keyId: string + keyPem: string +} +export interface UserSecurityKey { + id: string + userId: string + publicKey: string + lastUsed: Date + name: string +} +export interface Webhook { + id: string + createdAt: Date + userId: string + name: string + on: Array + url: string + secret: string + active: boolean + latestSentAt: Date | null + latestStatus: number | null +} +/** Initializes Cuid2 generator. Must be called before any [create_id]. */ +export function initIdGenerator(length: number, fingerprint: string): void +export function getTimestamp(id: string): number +/** + * The generated ID results in the form of `[8 chars timestamp] + [cuid2]`. + * The minimum and maximum lengths are 16 and 24, respectively. + * With the length of 16, namely 8 for cuid2, roughly 1427399 IDs are needed + * in the same millisecond to reach 50% chance of collision. + * + * Ref: https://github.com/paralleldrive/cuid2#parameterized-length + */ +export function genId(date?: Date | undefined | null): string +export function secureRndstr(length?: number | undefined | null): string diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 94960878f3..6d64f6ec75 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -224,17 +224,32 @@ switch (platform) { } break case 'arm': - localFileExisted = existsSync( - join(__dirname, 'backend-rs.linux-arm-gnueabihf.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./backend-rs.linux-arm-gnueabihf.node') - } else { - nativeBinding = require('backend-rs-linux-arm-gnueabihf') + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'backend-rs.linux-arm-musleabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./backend-rs.linux-arm-musleabihf.node') + } else { + nativeBinding = require('backend-rs-linux-arm-musleabihf') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'backend-rs.linux-arm-gnueabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./backend-rs.linux-arm-gnueabihf.node') + } else { + nativeBinding = require('backend-rs-linux-arm-gnueabihf') + } + } catch (e) { + loadError = e } - } catch (e) { - loadError = e } break case 'riscv64': @@ -295,11 +310,46 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { nativeRandomStr, IdConvertType, convertId, nativeGetTimestamp, nativeCreateId, nativeInitIdGenerator } = nativeBinding +const { readEnvironmentConfig, readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getNoteSummary, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding -module.exports.nativeRandomStr = nativeRandomStr -module.exports.IdConvertType = IdConvertType -module.exports.convertId = convertId -module.exports.nativeGetTimestamp = nativeGetTimestamp -module.exports.nativeCreateId = nativeCreateId -module.exports.nativeInitIdGenerator = nativeInitIdGenerator +module.exports.readEnvironmentConfig = readEnvironmentConfig +module.exports.readServerConfig = readServerConfig +module.exports.stringToAcct = stringToAcct +module.exports.acctToString = acctToString +module.exports.checkWordMute = checkWordMute +module.exports.getFullApAccount = getFullApAccount +module.exports.isSelfHost = isSelfHost +module.exports.isSameOrigin = isSameOrigin +module.exports.extractHost = extractHost +module.exports.toPuny = toPuny +module.exports.isUnicodeEmoji = isUnicodeEmoji +module.exports.sqlLikeEscape = sqlLikeEscape +module.exports.safeForSql = safeForSql +module.exports.formatMilliseconds = formatMilliseconds +module.exports.getNoteSummary = getNoteSummary +module.exports.toMastodonId = toMastodonId +module.exports.fromMastodonId = fromMastodonId +module.exports.fetchMeta = fetchMeta +module.exports.metaToPugArgs = metaToPugArgs +module.exports.nyaify = nyaify +module.exports.hashPassword = hashPassword +module.exports.verifyPassword = verifyPassword +module.exports.isOldPasswordAlgorithm = isOldPasswordAlgorithm +module.exports.decodeReaction = decodeReaction +module.exports.countReactions = countReactions +module.exports.toDbReaction = toDbReaction +module.exports.AntennaSrcEnum = AntennaSrcEnum +module.exports.DriveFileUsageHintEnum = DriveFileUsageHintEnum +module.exports.MutedNoteReasonEnum = MutedNoteReasonEnum +module.exports.NoteVisibilityEnum = NoteVisibilityEnum +module.exports.NotificationTypeEnum = NotificationTypeEnum +module.exports.PageVisibilityEnum = PageVisibilityEnum +module.exports.PollNotevisibilityEnum = PollNotevisibilityEnum +module.exports.RelayStatusEnum = RelayStatusEnum +module.exports.UserEmojimodpermEnum = UserEmojimodpermEnum +module.exports.UserProfileFfvisibilityEnum = UserProfileFfvisibilityEnum +module.exports.UserProfileMutingnotificationtypesEnum = UserProfileMutingnotificationtypesEnum +module.exports.initIdGenerator = initIdGenerator +module.exports.getTimestamp = getTimestamp +module.exports.genId = genId +module.exports.secureRndstr = secureRndstr diff --git a/packages/backend-rs/package.json b/packages/backend-rs/package.json index 6cc295dac4..1f3f49e9fb 100644 --- a/packages/backend-rs/package.json +++ b/packages/backend-rs/package.json @@ -22,7 +22,7 @@ } }, "devDependencies": { - "@napi-rs/cli": "2.18.0", + "@napi-rs/cli": "2.18.1", "ava": "6.1.2" }, "ava": { @@ -33,14 +33,12 @@ }, "scripts": { "artifacts": "napi artifacts", - "build": "napi build --features napi --platform --release ./built/", - "build:debug": "napi build --features napi --platform ./built/", + "build": "napi build --features napi --no-const-enum --platform --release ./built/", + "build:debug": "napi build --features napi --no-const-enum --platform ./built/", "prepublishOnly": "napi prepublish -t npm", "test": "pnpm run cargo:test && pnpm run build:debug && ava", "universal": "napi universal", "version": "napi version", - "format": "cargo fmt --all --", - "lint": "cargo clippy --fix --allow-dirty --allow-staged && cargo fmt --all --", "cargo:test": "pnpm run cargo:unit && pnpm run cargo:integration", "cargo:unit": "cargo test unit_test && cargo test -F napi unit_test", "cargo:integration": "cargo test int_test" diff --git a/packages/backend-rs/src/config/environment.rs b/packages/backend-rs/src/config/environment.rs new file mode 100644 index 0000000000..7d66aec7ba --- /dev/null +++ b/packages/backend-rs/src/config/environment.rs @@ -0,0 +1,27 @@ +// FIXME: Are these options used? +#[crate::export(object)] +pub struct EnvConfig { + pub only_queue: bool, + pub only_server: bool, + pub no_daemons: bool, + pub disable_clustering: bool, + pub verbose: bool, + pub with_log_time: bool, + pub slow: bool, +} + +#[crate::export] +pub fn read_environment_config() -> EnvConfig { + let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase(); + let is_testing = node_env == "test"; + + EnvConfig { + only_queue: std::env::var("MK_ONLY_QUEUE").is_ok(), + only_server: std::env::var("MK_ONLY_SERVER").is_ok(), + no_daemons: is_testing || std::env::var("MK_NO_DAEMONS").is_ok(), + disable_clustering: is_testing || std::env::var("MK_DISABLE_CLUSTERING").is_ok(), + verbose: std::env::var("MK_VERBOSE").is_ok(), + with_log_time: std::env::var("MK_WITH_LOG_TIME").is_ok(), + slow: std::env::var("MK_SLOW").is_ok(), + } +} diff --git a/packages/backend-rs/src/config/mod.rs b/packages/backend-rs/src/config/mod.rs new file mode 100644 index 0000000000..b708f2b265 --- /dev/null +++ b/packages/backend-rs/src/config/mod.rs @@ -0,0 +1,2 @@ +pub mod environment; +pub mod server; diff --git a/packages/backend-rs/src/config/server.rs b/packages/backend-rs/src/config/server.rs new file mode 100644 index 0000000000..125bae90b9 --- /dev/null +++ b/packages/backend-rs/src/config/server.rs @@ -0,0 +1,183 @@ +use once_cell::sync::Lazy; +use serde::Deserialize; +use std::env; +use std::fs; + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct ServerConfig { + pub url: String, + pub port: u16, + /// host to listen on + pub bind: Option, + pub disable_hsts: Option, + + pub db: DbConfig, + pub redis: RedisConfig, + pub cache_server: Option, + + pub proxy: Option, + pub proxy_smtp: Option, + pub proxy_bypass_hosts: Option>, + + pub allowed_private_networks: Option>, + /// `NapiValue` is not implemented for `u64` + pub max_file_size: Option, + pub access_log: Option, + pub cluster_limits: Option, + pub cuid: Option, + pub outgoing_address: Option, + + pub deliver_job_concurrency: Option, + pub inbox_job_concurrency: Option, + pub deliver_job_per_sec: Option, + pub inbox_job_per_sec: Option, + pub deliver_job_max_attempts: Option, + pub inbox_job_max_attempts: Option, + + pub log_level: Option>, + + pub syslog: Option, + + pub proxy_remote_files: Option, + pub media_proxy: Option, + pub summaly_proxy_url: Option, + + pub reserved_usernames: Option>, + + pub max_user_signups: Option, + pub is_managed_hosting: Option, + pub max_note_length: Option, + pub max_caption_length: Option, + + pub deepl: Option, + pub libre_translate: Option, + pub email: Option, + pub object_storage: Option, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct DbConfig { + pub host: String, + pub port: u16, + pub db: String, + pub user: String, + pub pass: String, + pub disable_cache: Option, + pub extra: Option, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct RedisConfig { + pub host: String, + pub port: u16, + pub family: Option, + pub user: Option, + pub pass: Option, + pub tls: Option, + #[serde(default)] + pub db: u32, + #[serde(default)] + pub prefix: String, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct TlsConfig { + pub host: String, + pub reject_unauthorized: bool, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct WorkerConfig { + pub web: Option, + pub queue: Option, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct IdConfig { + pub length: Option, + pub fingerprint: Option, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct SysLogConfig { + pub host: String, + pub port: u16, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct DeepLConfig { + pub managed: Option, + pub auth_key: Option, + pub is_pro: Option, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct LibreTranslateConfig { + pub managed: Option, + pub api_url: Option, + pub api_key: Option, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct EmailConfig { + pub managed: Option, + pub address: Option, + pub host: Option, + pub port: Option, + pub user: Option, + pub pass: Option, + pub use_implicit_ssl_tls: Option, +} + +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +#[crate::export(object, use_nullable = false)] +pub struct ObjectStorageConfig { + pub managed: Option, + pub base_url: Option, + pub bucket: Option, + pub prefix: Option, + pub endpoint: Option, + pub region: Option, + pub access_key: Option, + pub secret_key: Option, + pub use_ssl: Option, + pub connnect_over_proxy: Option, + pub set_public_read_on_upload: Option, + pub s3_force_path_style: Option, +} + +#[crate::export] +pub fn read_server_config() -> ServerConfig { + let cwd = env::current_dir().unwrap(); + let yml = fs::File::open(cwd.join("../../.config/default.yml")) + .expect("Failed to open '.config/default.yml'"); + let mut data: ServerConfig = serde_yaml::from_reader(yml).expect("Failed to parse yaml"); + data.url = url::Url::parse(&data.url) + .expect("Config url is invalid") + .origin() + .ascii_serialization(); + data +} + +pub static SERVER_CONFIG: Lazy = Lazy::new(read_server_config); diff --git a/packages/backend-rs/src/database/error.rs b/packages/backend-rs/src/database/error.rs deleted file mode 100644 index 68e959e0af..0000000000 --- a/packages/backend-rs/src/database/error.rs +++ /dev/null @@ -1,13 +0,0 @@ -use sea_orm::error::DbErr; - -use crate::impl_into_napi_error; - -#[derive(thiserror::Error, Debug, PartialEq, Eq)] -pub enum Error { - #[error("The database connections have not been initialized yet")] - Uninitialized, - #[error("ORM error: {0}")] - OrmError(#[from] DbErr), -} - -impl_into_napi_error!(Error); diff --git a/packages/backend-rs/src/database/mod.rs b/packages/backend-rs/src/database/mod.rs index 739f39bb64..f598e35cc7 100644 --- a/packages/backend-rs/src/database/mod.rs +++ b/packages/backend-rs/src/database/mod.rs @@ -1,26 +1,34 @@ -pub mod error; - -use error::Error; -use sea_orm::{Database, DbConn}; +use crate::config::server::SERVER_CONFIG; +use sea_orm::{Database, DbConn, DbErr}; static DB_CONN: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); -pub async fn init_database(conn_uri: impl Into) -> Result<(), Error> { - let conn = Database::connect(conn_uri.into()).await?; - DB_CONN.get_or_init(move || conn); - Ok(()) +async fn init_database() -> Result<&'static DbConn, DbErr> { + let database_uri = format!( + "postgres://{}:{}@{}:{}/{}", + SERVER_CONFIG.db.user, + urlencoding::encode(&SERVER_CONFIG.db.pass), + SERVER_CONFIG.db.host, + SERVER_CONFIG.db.port, + SERVER_CONFIG.db.db, + ); + let conn = Database::connect(database_uri).await?; + Ok(DB_CONN.get_or_init(move || conn)) } -pub fn get_database() -> Result<&'static DbConn, Error> { - DB_CONN.get().ok_or(Error::Uninitialized) +pub async fn db_conn() -> Result<&'static DbConn, DbErr> { + match DB_CONN.get() { + Some(conn) => Ok(conn), + None => init_database().await, + } } #[cfg(test)] mod unit_test { - use super::{error::Error, get_database}; + use super::db_conn; - #[test] - fn error_uninitialized() { - assert_eq!(get_database().unwrap_err(), Error::Uninitialized); + #[tokio::test] + async fn connect_test() { + assert!(db_conn().await.is_ok()); } } diff --git a/packages/backend-rs/src/lib.rs b/packages/backend-rs/src/lib.rs index f18e69a48f..bef7a41808 100644 --- a/packages/backend-rs/src/lib.rs +++ b/packages/backend-rs/src/lib.rs @@ -1,7 +1,7 @@ +pub use macro_rs::export; + +pub mod config; pub mod database; -pub mod macros; +pub mod misc; pub mod model; pub mod util; - -#[cfg(feature = "napi")] -pub mod mastodon_api; diff --git a/packages/backend-rs/src/macros.rs b/packages/backend-rs/src/macros.rs deleted file mode 100644 index 49ab826329..0000000000 --- a/packages/backend-rs/src/macros.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[macro_export] -macro_rules! impl_into_napi_error { - ($a:ty) => { - #[cfg(feature = "napi")] - impl Into for $a { - fn into(self) -> napi::Error { - napi::Error::from_reason(self.to_string()) - } - } - }; -} diff --git a/packages/backend-rs/src/mastodon_api.rs b/packages/backend-rs/src/mastodon_api.rs deleted file mode 100644 index 61ee4018af..0000000000 --- a/packages/backend-rs/src/mastodon_api.rs +++ /dev/null @@ -1,70 +0,0 @@ -use napi::{Error, Status}; -use napi_derive::napi; - -static CHAR_COLLECTION: &str = "0123456789abcdefghijklmnopqrstuvwxyz"; - -// -- NAPI exports -- - -#[napi] -pub enum IdConvertType { - MastodonId, - FirefishId, -} - -#[napi] -pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result { - use IdConvertType::*; - match id_convert_type { - MastodonId => { - let mut out: i128 = 0; - for (i, c) in in_id.to_lowercase().chars().rev().enumerate() { - out += num_from_char(c)? as i128 * 36_i128.pow(i as u32); - } - - Ok(out.to_string()) - } - FirefishId => { - let mut input: i128 = match in_id.parse() { - Ok(s) => s, - Err(_) => { - return Err(Error::new( - Status::InvalidArg, - "Unable to parse ID as MastodonId", - )) - } - }; - let mut out = String::new(); - - while input != 0 { - out.insert(0, char_from_num((input % 36) as u8)?); - input /= 36; - } - - Ok(out) - } - } -} - -// -- end -- - -#[inline(always)] -fn num_from_char(character: char) -> napi::Result { - for (i, c) in CHAR_COLLECTION.chars().enumerate() { - if c == character { - return Ok(i as u8); - } - } - - Err(Error::new( - Status::InvalidArg, - "Invalid character in parsed base36 id", - )) -} - -#[inline(always)] -fn char_from_num(number: u8) -> napi::Result { - CHAR_COLLECTION - .chars() - .nth(number as usize) - .ok_or(Error::from_status(Status::Unknown)) -} diff --git a/packages/backend-rs/src/misc/acct.rs b/packages/backend-rs/src/misc/acct.rs new file mode 100644 index 0000000000..6dcb4f9a74 --- /dev/null +++ b/packages/backend-rs/src/misc/acct.rs @@ -0,0 +1,74 @@ +#[derive(Debug, PartialEq)] +#[crate::export(object)] +pub struct Acct { + pub username: String, + pub host: Option, +} + +#[crate::export] +pub fn string_to_acct(acct: &str) -> Acct { + let split: Vec<&str> = if let Some(stripped) = acct.strip_prefix('@') { + stripped + } else { + acct + } + .split('@') + .collect(); + + Acct { + username: split[0].to_string(), + host: if split.len() == 1 { + None + } else { + Some(split[1].to_string()) + }, + } +} + +#[crate::export] +pub fn acct_to_string(acct: &Acct) -> String { + match &acct.host { + Some(host) => format!("{}@{}", acct.username, host), + None => acct.username.clone(), + } +} + +#[cfg(test)] +mod unit_test { + use super::{acct_to_string, string_to_acct, Acct}; + use pretty_assertions::assert_eq; + + #[test] + fn test_acct_to_string() { + let remote_acct = Acct { + username: "firefish".to_string(), + host: Some("example.com".to_string()), + }; + let local_acct = Acct { + username: "MisakaMikoto".to_string(), + host: None, + }; + + assert_eq!(acct_to_string(&remote_acct), "firefish@example.com"); + assert_ne!(acct_to_string(&remote_acct), "mastodon@example.com"); + assert_eq!(acct_to_string(&local_acct), "MisakaMikoto"); + assert_ne!(acct_to_string(&local_acct), "ShiraiKuroko"); + } + + #[test] + fn test_string_to_acct() { + let remote_acct = Acct { + username: "firefish".to_string(), + host: Some("example.com".to_string()), + }; + let local_acct = Acct { + username: "MisakaMikoto".to_string(), + host: None, + }; + + assert_eq!(string_to_acct("@firefish@example.com"), remote_acct); + assert_eq!(string_to_acct("firefish@example.com"), remote_acct); + assert_eq!(string_to_acct("@MisakaMikoto"), local_acct); + assert_eq!(string_to_acct("MisakaMikoto"), local_acct); + } +} diff --git a/packages/backend-rs/src/misc/check_word_mute.rs b/packages/backend-rs/src/misc/check_word_mute.rs new file mode 100644 index 0000000000..18b550c29b --- /dev/null +++ b/packages/backend-rs/src/misc/check_word_mute.rs @@ -0,0 +1,118 @@ +use crate::database::db_conn; +use crate::model::entity::{drive_file, note}; +use once_cell::sync::Lazy; +use regex::Regex; +use sea_orm::{prelude::*, QuerySelect}; + +/// TODO: handle name collisions better +#[crate::export(object, js_name = "NoteLikeForCheckWordMute")] +pub struct NoteLike { + pub file_ids: Vec, + pub user_id: Option, + pub text: Option, + pub cw: Option, + pub renote_id: Option, + pub reply_id: Option, +} + +async fn all_texts(note: NoteLike) -> Result, DbErr> { + let db = db_conn().await?; + + let mut texts: Vec = vec![]; + + if let Some(text) = note.text { + texts.push(text); + } + if let Some(cw) = note.cw { + texts.push(cw); + } + + texts.extend( + drive_file::Entity::find() + .select_only() + .column(drive_file::Column::Comment) + .filter(drive_file::Column::Id.is_in(note.file_ids)) + .into_tuple::>() + .all(db) + .await? + .into_iter() + .flatten(), + ); + + if let Some(renote_id) = note.renote_id { + if let Some((text, cw)) = note::Entity::find_by_id(renote_id) + .select_only() + .columns([note::Column::Text, note::Column::Cw]) + .into_tuple::<(Option, Option)>() + .one(db) + .await? + { + if let Some(t) = text { + texts.push(t); + } + if let Some(c) = cw { + texts.push(c); + } + } + } + + if let Some(reply_id) = note.reply_id { + if let Some((text, cw)) = note::Entity::find_by_id(reply_id) + .select_only() + .columns([note::Column::Text, note::Column::Cw]) + .into_tuple::<(Option, Option)>() + .one(db) + .await? + { + if let Some(t) = text { + texts.push(t); + } + if let Some(c) = cw { + texts.push(c); + } + } + } + + Ok(texts) +} + +fn convert_regex(js_regex: &str) -> String { + static RE: Lazy = Lazy::new(|| Regex::new(r"^/(.+)/(.*)$").unwrap()); + RE.replace(js_regex, "(?$2)$1").to_string() +} + +fn check_word_mute_impl( + texts: &[String], + muted_word_lists: &[Vec], + muted_patterns: &[String], +) -> bool { + muted_word_lists.iter().any(|muted_word_list| { + texts.iter().any(|text| { + let text_lower = text.to_lowercase(); + muted_word_list + .iter() + .all(|muted_word| text_lower.contains(&muted_word.to_lowercase())) + }) + }) || muted_patterns.iter().any(|muted_pattern| { + Regex::new(convert_regex(muted_pattern).as_str()) + .map(|re| texts.iter().any(|text| re.is_match(text))) + .unwrap_or(false) + }) +} + +#[crate::export] +pub async fn check_word_mute( + note: NoteLike, + muted_word_lists: Vec>, + muted_patterns: Vec, +) -> Result { + if muted_word_lists.is_empty() && muted_patterns.is_empty() { + Ok(false) + } else { + Ok(check_word_mute_impl( + &all_texts(note).await?, + &muted_word_lists, + &muted_patterns, + )) + } +} diff --git a/packages/backend-rs/src/misc/convert_host.rs b/packages/backend-rs/src/misc/convert_host.rs new file mode 100644 index 0000000000..34a0792c62 --- /dev/null +++ b/packages/backend-rs/src/misc/convert_host.rs @@ -0,0 +1,67 @@ +use crate::config::server::SERVER_CONFIG; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Idna error: {0}")] + IdnaError(#[from] idna::Errors), + #[error("Url parse error: {0}")] + UrlParseError(#[from] url::ParseError), + #[error("Hostname is missing")] + NoHostname, +} + +#[crate::export] +pub fn get_full_ap_account(username: &str, host: Option<&str>) -> Result { + Ok(match host { + Some(host) => format!("{}@{}", username, to_puny(host)?), + None => format!("{}@{}", username, extract_host(&SERVER_CONFIG.url)?), + }) +} + +#[crate::export] +pub fn is_self_host(host: Option<&str>) -> Result { + Ok(match host { + Some(host) => extract_host(&SERVER_CONFIG.url)? == to_puny(host)?, + None => true, + }) +} + +#[crate::export] +pub fn is_same_origin(uri: &str) -> Result { + Ok(url::Url::parse(uri)?.origin().ascii_serialization() == SERVER_CONFIG.url) +} + +#[crate::export] +pub fn extract_host(uri: &str) -> Result { + url::Url::parse(uri)? + .host_str() + .ok_or(Error::NoHostname) + .and_then(|v| Ok(to_puny(v)?)) +} + +#[crate::export] +pub fn to_puny(host: &str) -> Result { + idna::domain_to_ascii(host) +} + +#[cfg(test)] +mod unit_test { + use super::{extract_host, to_puny}; + use pretty_assertions::assert_eq; + + #[test] + fn extract_host_test() { + assert_eq!( + extract_host("https://firefish.dev/firefish/firefish.git").unwrap(), + "firefish.dev" + ); + } + + #[test] + fn to_puny_test() { + assert_eq!( + to_puny("何もかも.owari.shop").unwrap(), + "xn--u8jyfb5762a.owari.shop" + ); + } +} diff --git a/packages/backend-rs/src/misc/emoji.rs b/packages/backend-rs/src/misc/emoji.rs new file mode 100644 index 0000000000..df7d33848c --- /dev/null +++ b/packages/backend-rs/src/misc/emoji.rs @@ -0,0 +1,31 @@ +#[inline] +#[crate::export] +pub fn is_unicode_emoji(s: &str) -> bool { + emojis::get(s).is_some() +} + +#[cfg(test)] +mod unit_test { + use super::is_unicode_emoji; + + #[test] + fn test_unicode_emoji_check() { + assert!(is_unicode_emoji("⭐")); + assert!(is_unicode_emoji("👍")); + assert!(is_unicode_emoji("❤")); + assert!(is_unicode_emoji("♥️")); + assert!(is_unicode_emoji("❤️")); + assert!(is_unicode_emoji("💙")); + assert!(is_unicode_emoji("🩷")); + assert!(is_unicode_emoji("🖖🏿")); + assert!(is_unicode_emoji("🏃‍➡️")); + assert!(is_unicode_emoji("👩‍❤️‍👨")); + assert!(is_unicode_emoji("👩‍👦‍👦")); + assert!(is_unicode_emoji("🏳️‍🌈")); + + assert!(!is_unicode_emoji("⭐⭐")); + assert!(!is_unicode_emoji("x")); + assert!(!is_unicode_emoji("\t")); + assert!(!is_unicode_emoji(":meow_aww:")); + } +} diff --git a/packages/backend-rs/src/misc/escape_sql.rs b/packages/backend-rs/src/misc/escape_sql.rs new file mode 100644 index 0000000000..c575e088ce --- /dev/null +++ b/packages/backend-rs/src/misc/escape_sql.rs @@ -0,0 +1,36 @@ +#[crate::export] +pub fn sql_like_escape(src: &str) -> String { + src.replace('%', r"\%").replace('_', r"\_") +} + +#[crate::export] +pub fn safe_for_sql(src: &str) -> bool { + !src.contains([ + '\0', '\x08', '\x09', '\x1a', '\n', '\r', '"', '\'', '\\', '%', + ]) +} + +#[cfg(test)] +mod unit_test { + use super::{safe_for_sql, sql_like_escape}; + use pretty_assertions::assert_eq; + + #[test] + fn sql_like_escape_test() { + assert_eq!(sql_like_escape(""), ""); + assert_eq!(sql_like_escape("abc"), "abc"); + assert_eq!(sql_like_escape("a%bc"), r"a\%bc"); + assert_eq!(sql_like_escape("a呼%吸bc"), r"a呼\%吸bc"); + assert_eq!(sql_like_escape("a呼%吸b%_c"), r"a呼\%吸b\%\_c"); + assert_eq!(sql_like_escape("_اللغة العربية"), r"\_اللغة العربية"); + } + + #[test] + fn safe_for_sql_test() { + assert!(safe_for_sql("123")); + assert!(safe_for_sql("人間")); + assert!(!safe_for_sql("人間\x09")); + assert!(!safe_for_sql("abc\ndef")); + assert!(!safe_for_sql("%something%")); + } +} diff --git a/packages/backend-rs/src/misc/format_milliseconds.rs b/packages/backend-rs/src/misc/format_milliseconds.rs new file mode 100644 index 0000000000..dfa8df6f62 --- /dev/null +++ b/packages/backend-rs/src/misc/format_milliseconds.rs @@ -0,0 +1,46 @@ +/// Convert milliseconds to a human readable string +#[crate::export] +pub fn format_milliseconds(milliseconds: u32) -> String { + let mut seconds = milliseconds / 1000; + let mut minutes = seconds / 60; + let mut hours = minutes / 60; + let days = hours / 24; + + seconds %= 60; + minutes %= 60; + hours %= 24; + + let mut buf: Vec = vec![]; + + if days > 0 { + buf.push(format!("{} day(s)", days)); + } + if hours > 0 { + buf.push(format!("{} hour(s)", hours)); + } + if minutes > 0 { + buf.push(format!("{} minute(s)", minutes)); + } + if seconds > 0 { + buf.push(format!("{} second(s)", seconds)); + } + + buf.join(", ") +} + +#[cfg(test)] +mod unit_test { + use super::format_milliseconds; + use pretty_assertions::assert_eq; + + #[test] + fn format_milliseconds_test() { + assert_eq!(format_milliseconds(1000), "1 second(s)"); + assert_eq!(format_milliseconds(1387938), "23 minute(s), 7 second(s)"); + assert_eq!(format_milliseconds(34200457), "9 hour(s), 30 minute(s)"); + assert_eq!( + format_milliseconds(998244353), + "11 day(s), 13 hour(s), 17 minute(s), 24 second(s)" + ); + } +} diff --git a/packages/backend-rs/src/misc/get_note_summary.rs b/packages/backend-rs/src/misc/get_note_summary.rs new file mode 100644 index 0000000000..3b759b04f5 --- /dev/null +++ b/packages/backend-rs/src/misc/get_note_summary.rs @@ -0,0 +1,90 @@ +/// TODO: handle name collisions better +#[crate::export(object, js_name = "NoteLikeForGetNoteSummary")] +pub struct NoteLike { + pub file_ids: Vec, + pub text: Option, + pub cw: Option, + pub has_poll: bool, +} + +#[crate::export] +pub fn get_note_summary(note: NoteLike) -> String { + let mut buf: Vec = vec![]; + + if let Some(cw) = note.cw { + buf.push(cw) + } else if let Some(text) = note.text { + buf.push(text) + } + + match note.file_ids.len() { + 0 => (), + 1 => buf.push("📎".to_string()), + n => buf.push(format!("📎 ({})", n)), + }; + + if note.has_poll { + buf.push("📊".to_string()) + } + + buf.join(" ") +} + +#[cfg(test)] +mod unit_test { + use super::{get_note_summary, NoteLike}; + use pretty_assertions::assert_eq; + + #[test] + fn test_note_summary() { + let note = NoteLike { + file_ids: vec![], + text: Some("Hello world!".to_string()), + cw: None, + has_poll: false, + }; + assert_eq!(get_note_summary(note), "Hello world!"); + + let note_with_cw = NoteLike { + file_ids: vec![], + text: Some("Hello world!".to_string()), + cw: Some("Content warning".to_string()), + has_poll: false, + }; + assert_eq!(get_note_summary(note_with_cw), "Content warning"); + + let note_with_file_and_cw = NoteLike { + file_ids: vec!["9s7fmcqogiq4igin".to_string()], + text: None, + cw: Some("Selfie, no ec".to_string()), + has_poll: false, + }; + assert_eq!(get_note_summary(note_with_file_and_cw), "Selfie, no ec 📎"); + + let note_with_files_only = NoteLike { + file_ids: vec![ + "9s7fmcqogiq4igin".to_string(), + "9s7qrld5u14cey98".to_string(), + "9s7gebs5zgts4kca".to_string(), + "9s5z3e4vefqd29ee".to_string(), + ], + text: None, + cw: None, + has_poll: false, + }; + assert_eq!(get_note_summary(note_with_files_only), "📎 (4)"); + + let note_all = NoteLike { + file_ids: vec![ + "9s7fmcqogiq4igin".to_string(), + "9s7qrld5u14cey98".to_string(), + "9s7gebs5zgts4kca".to_string(), + "9s5z3e4vefqd29ee".to_string(), + ], + text: Some("Hello world!".to_string()), + cw: Some("Content warning".to_string()), + has_poll: true, + }; + assert_eq!(get_note_summary(note_all), "Content warning 📎 (4) 📊"); + } +} diff --git a/packages/backend-rs/src/misc/mastodon_id.rs b/packages/backend-rs/src/misc/mastodon_id.rs new file mode 100644 index 0000000000..94ba561b58 --- /dev/null +++ b/packages/backend-rs/src/misc/mastodon_id.rs @@ -0,0 +1,35 @@ +#[crate::export] +pub fn to_mastodon_id(firefish_id: &str) -> Option { + let decoded: [u8; 16] = basen::BASE36.decode_var_len(&firefish_id.to_ascii_lowercase())?; + Some(basen::BASE10.encode_var_len(&decoded)) +} + +#[crate::export] +pub fn from_mastodon_id(mastodon_id: &str) -> Option { + let decoded: [u8; 16] = basen::BASE10.decode_var_len(mastodon_id)?; + Some(basen::BASE36.encode_var_len(&decoded)) +} + +#[cfg(test)] +mod unit_test { + use super::{from_mastodon_id, to_mastodon_id}; + use pretty_assertions::assert_eq; + + #[test] + fn to_mastodon_id_test() { + assert_eq!( + to_mastodon_id("9pdqi3rjl4lxirq3").unwrap(), + "2145531976185871567229403" + ); + assert_eq!(to_mastodon_id("9pdqi3r*irq3"), None); + } + + #[test] + fn from_mastodon_id_test() { + assert_eq!( + from_mastodon_id("2145531976185871567229403").unwrap(), + "9pdqi3rjl4lxirq3" + ); + assert_eq!(from_mastodon_id("9pdqi3rjl4lxirq3"), None); + } +} diff --git a/packages/backend-rs/src/misc/meta.rs b/packages/backend-rs/src/misc/meta.rs new file mode 100644 index 0000000000..5aed617038 --- /dev/null +++ b/packages/backend-rs/src/misc/meta.rs @@ -0,0 +1,83 @@ +use crate::database::db_conn; +use crate::model::entity::meta; +use rand::prelude::*; +use sea_orm::{prelude::*, ActiveValue}; +use std::sync::Mutex; + +type Meta = meta::Model; + +static CACHE: Mutex> = Mutex::new(None); +fn update_cache(meta: &Meta) { + let _ = CACHE.lock().map(|mut cache| *cache = Some(meta.clone())); +} + +#[crate::export] +pub async fn fetch_meta(use_cache: bool) -> Result { + // try using cache + if use_cache { + if let Some(cache) = CACHE.lock().ok().and_then(|cache| cache.clone()) { + return Ok(cache); + } + } + + // try fetching from db + let db = db_conn().await?; + let meta = meta::Entity::find().one(db).await?; + if let Some(meta) = meta { + update_cache(&meta); + return Ok(meta); + } + + // create a new meta object and insert into db + let meta = meta::Entity::insert(meta::ActiveModel { + id: ActiveValue::Set("x".to_owned()), + ..Default::default() + }) + .exec_with_returning(db) + .await?; + update_cache(&meta); + Ok(meta) +} + +#[crate::export(object)] +pub struct PugArgs { + pub img: Option, + pub title: String, + pub instance_name: String, + pub desc: Option, + pub icon: Option, + pub splash_icon: Option, + pub theme_color: Option, + pub random_motd: String, + pub private_mode: Option, +} + +#[crate::export] +pub fn meta_to_pug_args(meta: Meta) -> PugArgs { + let mut rng = rand::thread_rng(); + + let splash_icon = meta + .custom_splash_icons + .choose(&mut rng) + .map(|s| s.to_owned()) + .or_else(|| meta.icon_url.to_owned()); + + let random_motd = meta + .custom_motd + .choose(&mut rng) + .map(|s| s.to_owned()) + .unwrap_or_else(|| "Loading...".to_owned()); + + let name = meta.name.unwrap_or_else(|| "Firefish".to_owned()); + PugArgs { + img: meta.banner_url, + title: name.clone(), + instance_name: name.clone(), + desc: meta.description, + icon: meta.icon_url, + splash_icon, + theme_color: meta.theme_color, + random_motd, + private_mode: meta.private_mode, + } +} diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs new file mode 100644 index 0000000000..a9d7074dbf --- /dev/null +++ b/packages/backend-rs/src/misc/mod.rs @@ -0,0 +1,12 @@ +pub mod acct; +pub mod check_word_mute; +pub mod convert_host; +pub mod emoji; +pub mod escape_sql; +pub mod format_milliseconds; +pub mod get_note_summary; +pub mod mastodon_id; +pub mod meta; +pub mod nyaify; +pub mod password; +pub mod reaction; diff --git a/packages/backend-rs/src/misc/nyaify.rs b/packages/backend-rs/src/misc/nyaify.rs new file mode 100644 index 0000000000..94f1615d67 --- /dev/null +++ b/packages/backend-rs/src/misc/nyaify.rs @@ -0,0 +1,97 @@ +use once_cell::sync::Lazy; +use regex::{Captures, Regex}; + +#[crate::export] +pub fn nyaify(text: &str, lang: Option<&str>) -> String { + let mut to_return = text.to_owned(); + + { + static RE: Lazy = + Lazy::new(|| Regex::new(r"(?i-u)(non)([bcdfghjklmnpqrstvwxyz])").unwrap()); + to_return = RE + .replace_all(&to_return, |caps: &Captures<'_>| { + format!( + "{}{}", + match &caps[1] { + "non" => "nyan", + "Non" => "Nyan", + "NON" => "NYAN", + _ => &caps[1], + }, + &caps[2] + ) + }) + .to_string(); + } + + { + static RE: Lazy = Lazy::new(|| Regex::new(r"다([..。…??!!\s]|$)").unwrap()); + to_return = RE.replace_all(&to_return, r"다냥$1").to_string(); + } + + { + static RE: Lazy = Lazy::new(|| Regex::new(r"야([??\s]|$)").unwrap()); + to_return = RE.replace_all(&to_return, r"냥$1").to_string(); + } + + { + static RE: Lazy = Lazy::new(|| Regex::new(r"([나-낳])").unwrap()); + to_return = RE + .replace_all(&to_return, |caps: &Captures<'_>| { + format!( + "{}", + char::from_u32( + caps[0].chars().next().unwrap() as u32 + 56 /* = '냐' - '나' */ + ) + .unwrap() + ) + }) + .to_string(); + } + + if lang.is_some() && lang.unwrap().starts_with("zh") { + static RE: Lazy = Lazy::new(|| Regex::new(r"[妙庙描渺瞄秒苗藐廟]").unwrap()); + to_return = RE.replace_all(&to_return, "喵").to_string(); + } + + let simple_rules = [ + ("な", "にゃ"), + ("ナ", "ニャ"), + ("ナ", "ニャ"), + ("na", "nya"), + ("NA", "NYA"), + ("Na", "Nya"), + ("morning", "mornyan"), + ("Morning", "Mornyan"), + ("MORNING", "MORNYAN"), + ("everyone", "everynyan"), + ("Everyone", "Everynyan"), + ("EVERYONE", "EVERYNYAN"), + ("να", "νια"), + ("ΝΑ", "ΝΙΑ"), + ("Να", "Νια"), + ]; + + simple_rules.into_iter().for_each(|(from, to)| { + to_return = to_return.replace(from, to); + }); + + to_return +} + +#[cfg(test)] +mod unit_test { + use super::nyaify; + use pretty_assertions::assert_eq; + + #[test] + fn can_nyaify() { + assert_eq!(nyaify("Hello everyone!", Some("en")), "Hello everynyan!"); + assert_eq!(nyaify("Nonbinary people", None), "Nyanbinyary people"); + assert_eq!(nyaify("1分鐘是60秒", Some("zh-TW")), "1分鐘是60喵"); + assert_eq!(nyaify("1分間は60秒です", Some("ja-JP")), "1分間は60秒です"); + assert_eq!(nyaify("あなたは誰ですか", None), "あにゃたは誰ですか"); + assert_eq!(nyaify("Ναυτικός", Some("el-GR")), "Νιαυτικός"); + assert_eq!(nyaify("일어나다", None), "일어냐다냥"); + } +} diff --git a/packages/backend-rs/src/misc/password.rs b/packages/backend-rs/src/misc/password.rs new file mode 100644 index 0000000000..b21ff73499 --- /dev/null +++ b/packages/backend-rs/src/misc/password.rs @@ -0,0 +1,69 @@ +use argon2::{ + password_hash, + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; + +#[crate::export] +pub fn hash_password(password: &str) -> Result { + let salt = SaltString::generate(&mut OsRng); + Ok(Argon2::default() + .hash_password(password.as_bytes(), &salt)? + .to_string()) +} + +#[derive(thiserror::Error, Debug)] +pub enum VerifyError { + #[error("An error occured while bcrypt verification: {0}")] + BcryptError(#[from] bcrypt::BcryptError), + #[error("Invalid argon2 password hash: {0}")] + InvalidArgon2Hash(#[from] password_hash::Error), + #[error("An error occured while argon2 verification: {0}")] + Argon2Error(#[from] argon2::Error), +} + +#[crate::export] +pub fn verify_password(password: &str, hash: &str) -> Result { + if is_old_password_algorithm(hash) { + Ok(bcrypt::verify(password, hash)?) + } else { + let parsed_hash = PasswordHash::new(hash)?; + Ok(Argon2::default() + .verify_password(password.as_bytes(), &parsed_hash) + .is_ok()) + } +} + +#[inline] +#[crate::export] +pub fn is_old_password_algorithm(hash: &str) -> bool { + // bcrypt hashes start with $2[ab]$ + hash.starts_with("$2") +} + +#[cfg(test)] +mod unit_test { + use super::{hash_password, is_old_password_algorithm, verify_password}; + + #[test] + fn verify_password_test() { + let password = "omWc*%sD^fn7o2cXmc9e2QasBdrbRuhNB*gx!J5"; + + let hash = hash_password(password).unwrap(); + assert!(verify_password(password, hash.as_str()).unwrap()); + + let argon2_hash = "$argon2id$v=19$m=19456,t=2,p=1$jty3puDFd4ENv/lgHn3ROQ$kRHDdEoVv2rruvnF731E74NxnYlvj5FMgePdGIIq3Jk"; + let argon2_invalid_hash = "$argon2id$v=19$m=19456,t=2,p=1$jty3puDFd4ENv/lgHn3ROQ$kRHDdEoVv2rruvnF731E74NxnYlvj4FMgePdGIIq3Jk"; + let bcrypt_hash = "$2a$12$WzUc.20jgbHmQjUMqTr8vOhKqYbS1BUvubapv/GLjCK1IN.h4e4la"; + let bcrypt_invalid_hash = "$2a$12$WzUc.20jgbHmQjUMqTr7vOhKqYbS1BUvubapv/GLjCK1IN.h4e4la"; + + assert!(!is_old_password_algorithm(argon2_hash)); + assert!(is_old_password_algorithm(bcrypt_hash)); + + assert!(verify_password(password, argon2_hash).unwrap()); + assert!(verify_password(password, bcrypt_hash).unwrap()); + + assert!(!verify_password(password, argon2_invalid_hash).unwrap()); + assert!(!verify_password(password, bcrypt_invalid_hash).unwrap()); + } +} diff --git a/packages/backend-rs/src/misc/reaction.rs b/packages/backend-rs/src/misc/reaction.rs new file mode 100644 index 0000000000..a29ddf95de --- /dev/null +++ b/packages/backend-rs/src/misc/reaction.rs @@ -0,0 +1,191 @@ +use crate::database::db_conn; +use crate::misc::{convert_host::to_puny, emoji::is_unicode_emoji, meta::fetch_meta}; +use crate::model::entity::emoji; +use once_cell::sync::Lazy; +use regex::Regex; +use sea_orm::prelude::*; +use std::collections::HashMap; + +#[derive(PartialEq, Debug)] +#[crate::export(object)] +pub struct DecodedReaction { + pub reaction: String, + pub name: Option, + pub host: Option, +} + +#[crate::export] +pub fn decode_reaction(reaction: &str) -> DecodedReaction { + // Misskey allows you to include "+" and "-" in emoji shortcodes + // MFM spec: https://github.com/misskey-dev/mfm.js/blob/6aaf68089023c6adebe44123eebbc4dcd75955e0/docs/syntax.md?plain=1#L583 + // Misskey's implementation: https://github.com/misskey-dev/misskey/blob/bba3097765317cbf95d09627961b5b5dce16a972/packages/backend/src/core/ReactionService.ts#L68 + static RE: Lazy = + Lazy::new(|| Regex::new(r"^:([0-9A-Za-z_+-]+)(?:@([0-9A-Za-z_.-]+))?:$").unwrap()); + + if let Some(captures) = RE.captures(reaction) { + let name = &captures[1]; + let host = captures.get(2).map(|s| s.as_str()); + + DecodedReaction { + reaction: format!(":{}@{}:", name, host.unwrap_or(".")), + name: Some(name.to_owned()), + host: host.map(|s| s.to_owned()), + } + } else { + DecodedReaction { + reaction: reaction.to_owned(), + name: None, + host: None, + } + } +} + +#[crate::export] +pub fn count_reactions(reactions: &HashMap) -> HashMap { + let mut res = HashMap::::new(); + + for (reaction, count) in reactions.iter() { + if count > &0 { + let decoded = decode_reaction(reaction).reaction; + let total = res.entry(decoded).or_insert(0); + *total += count; + } + } + + res +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Idna error: {0}")] + IdnaError(#[from] idna::Errors), + #[error("Database error: {0}")] + DbError(#[from] DbErr), +} + +#[crate::export] +pub async fn to_db_reaction(reaction: Option<&str>, host: Option<&str>) -> Result { + if let Some(reaction) = reaction { + // FIXME: Is it okay to do this only here? + // This was introduced in https://firefish.dev/firefish/firefish/-/commit/af730e75b6fc1a57ca680ce83459d7e433b130cf + if reaction.contains('❤') || reaction.contains("♥️") { + return Ok("❤️".to_owned()); + } + + if is_unicode_emoji(reaction) { + return Ok(reaction.to_owned()); + } + + static RE: Lazy = + Lazy::new(|| Regex::new(r"^:([0-9A-Za-z_+-]+)(?:@\.)?:$").unwrap()); + + if let Some(captures) = RE.captures(reaction) { + let name = &captures[1]; + let db = db_conn().await?; + + if let Some(host) = host { + // remote emoji + let ascii_host = to_puny(host)?; + + // TODO: Does SeaORM have the `exists` method? + if emoji::Entity::find() + .filter(emoji::Column::Name.eq(name)) + .filter(emoji::Column::Host.eq(&ascii_host)) + .one(db) + .await? + .is_some() + { + return Ok(format!(":{name}@{ascii_host}:")); + } + } else { + // local emoji + // TODO: Does SeaORM have the `exists` method? + if emoji::Entity::find() + .filter(emoji::Column::Name.eq(name)) + .filter(emoji::Column::Host.is_null()) + .one(db) + .await? + .is_some() + { + return Ok(format!(":{name}:")); + } + } + }; + }; + + Ok(fetch_meta(true).await?.default_reaction) +} + +#[cfg(test)] +mod unit_test { + use super::{decode_reaction, DecodedReaction}; + use pretty_assertions::{assert_eq, assert_ne}; + + #[test] + fn test_decode_reaction() { + let unicode_emoji_1 = DecodedReaction { + reaction: "⭐".to_string(), + name: None, + host: None, + }; + let unicode_emoji_2 = DecodedReaction { + reaction: "🩷".to_string(), + name: None, + host: None, + }; + + assert_eq!(decode_reaction("⭐"), unicode_emoji_1); + assert_eq!(decode_reaction("🩷"), unicode_emoji_2); + + assert_ne!(decode_reaction("⭐"), unicode_emoji_2); + assert_ne!(decode_reaction("🩷"), unicode_emoji_1); + + let unicode_emoji_3 = DecodedReaction { + reaction: "🖖🏿".to_string(), + name: None, + host: None, + }; + assert_eq!(decode_reaction("🖖🏿"), unicode_emoji_3); + + let local_emoji = DecodedReaction { + reaction: ":meow_melt_tears@.:".to_string(), + name: Some("meow_melt_tears".to_string()), + host: None, + }; + assert_eq!(decode_reaction(":meow_melt_tears:"), local_emoji); + + let remote_emoji_1 = DecodedReaction { + reaction: ":meow_uwu@some-domain.example.org:".to_string(), + name: Some("meow_uwu".to_string()), + host: Some("some-domain.example.org".to_string()), + }; + assert_eq!( + decode_reaction(":meow_uwu@some-domain.example.org:"), + remote_emoji_1 + ); + + let remote_emoji_2 = DecodedReaction { + reaction: ":C++23@xn--eckwd4c7c.example.org:".to_string(), + name: Some("C++23".to_string()), + host: Some("xn--eckwd4c7c.example.org".to_string()), + }; + assert_eq!( + decode_reaction(":C++23@xn--eckwd4c7c.example.org:"), + remote_emoji_2 + ); + + let invalid_reaction_1 = DecodedReaction { + reaction: ":foo".to_string(), + name: None, + host: None, + }; + assert_eq!(decode_reaction(":foo"), invalid_reaction_1); + + let invalid_reaction_2 = DecodedReaction { + reaction: ":foo&@example.com:".to_string(), + name: None, + host: None, + }; + assert_eq!(decode_reaction(":foo&@example.com:"), invalid_reaction_2); + } +} diff --git a/packages/backend-rs/src/model/entity/abuse_user_report.rs b/packages/backend-rs/src/model/entity/abuse_user_report.rs index 51b18eba56..4d781f06dd 100644 --- a/packages/backend-rs/src/model/entity/abuse_user_report.rs +++ b/packages/backend-rs/src/model/entity/abuse_user_report.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "abuse_user_report")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "AbuseUserReport", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "targetUserId")] pub target_user_id: String, #[sea_orm(column_name = "reporterId")] diff --git a/packages/backend-rs/src/model/entity/access_token.rs b/packages/backend-rs/src/model/entity/access_token.rs index 4f37c58307..3083bb8c90 100644 --- a/packages/backend-rs/src/model/entity/access_token.rs +++ b/packages/backend-rs/src/model/entity/access_token.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "access_token")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "AccessToken", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, pub token: String, pub hash: String, #[sea_orm(column_name = "userId")] @@ -16,7 +20,7 @@ pub struct Model { #[sea_orm(column_name = "appId")] pub app_id: Option, #[sea_orm(column_name = "lastUsedAt")] - pub last_used_at: Option, + pub last_used_at: Option, pub session: Option, pub name: Option, pub description: Option, diff --git a/packages/backend-rs/src/model/entity/ad.rs b/packages/backend-rs/src/model/entity/ad.rs index 4ffbf53456..98ec50ea91 100644 --- a/packages/backend-rs/src/model/entity/ad.rs +++ b/packages/backend-rs/src/model/entity/ad.rs @@ -4,13 +4,17 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "ad")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Ad", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "expiresAt")] - pub expires_at: DateTimeWithTimeZone, + pub expires_at: DateTime, pub place: String, pub priority: String, pub url: String, diff --git a/packages/backend-rs/src/model/entity/announcement.rs b/packages/backend-rs/src/model/entity/announcement.rs index 999673adb5..311571c113 100644 --- a/packages/backend-rs/src/model/entity/announcement.rs +++ b/packages/backend-rs/src/model/entity/announcement.rs @@ -4,17 +4,21 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "announcement")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Announcement", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, pub text: String, pub title: String, #[sea_orm(column_name = "imageUrl")] pub image_url: Option, #[sea_orm(column_name = "updatedAt")] - pub updated_at: Option, + pub updated_at: Option, #[sea_orm(column_name = "showPopup")] pub show_popup: bool, #[sea_orm(column_name = "isGoodNews")] diff --git a/packages/backend-rs/src/model/entity/announcement_read.rs b/packages/backend-rs/src/model/entity/announcement_read.rs index a91214fd81..157e402aa6 100644 --- a/packages/backend-rs/src/model/entity/announcement_read.rs +++ b/packages/backend-rs/src/model/entity/announcement_read.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "announcement_read")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "AnnouncementRead", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, @@ -12,7 +16,7 @@ pub struct Model { #[sea_orm(column_name = "announcementId")] pub announcement_id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/packages/backend-rs/src/model/entity/antenna.rs b/packages/backend-rs/src/model/entity/antenna.rs index c48579d41e..1edd6e8761 100644 --- a/packages/backend-rs/src/model/entity/antenna.rs +++ b/packages/backend-rs/src/model/entity/antenna.rs @@ -5,11 +5,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "antenna")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Antenna", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub name: String, diff --git a/packages/backend-rs/src/model/entity/app.rs b/packages/backend-rs/src/model/entity/app.rs index 86db6e99a1..d9517ed211 100644 --- a/packages/backend-rs/src/model/entity/app.rs +++ b/packages/backend-rs/src/model/entity/app.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "app")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "App", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: Option, pub secret: String, diff --git a/packages/backend-rs/src/model/entity/attestation_challenge.rs b/packages/backend-rs/src/model/entity/attestation_challenge.rs index 1ed507af33..0c131066dd 100644 --- a/packages/backend-rs/src/model/entity/attestation_challenge.rs +++ b/packages/backend-rs/src/model/entity/attestation_challenge.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "attestation_challenge")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "AttestationChallenge", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, @@ -11,7 +15,7 @@ pub struct Model { pub user_id: String, pub challenge: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "registrationChallenge")] pub registration_challenge: bool, } diff --git a/packages/backend-rs/src/model/entity/auth_session.rs b/packages/backend-rs/src/model/entity/auth_session.rs index 81cabf219a..f022a5e632 100644 --- a/packages/backend-rs/src/model/entity/auth_session.rs +++ b/packages/backend-rs/src/model/entity/auth_session.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "auth_session")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "AuthSession", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, pub token: String, #[sea_orm(column_name = "userId")] pub user_id: Option, diff --git a/packages/backend-rs/src/model/entity/blocking.rs b/packages/backend-rs/src/model/entity/blocking.rs index 3a00281850..2f5a3e0482 100644 --- a/packages/backend-rs/src/model/entity/blocking.rs +++ b/packages/backend-rs/src/model/entity/blocking.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "blocking")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Blocking", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "blockeeId")] pub blockee_id: String, #[sea_orm(column_name = "blockerId")] diff --git a/packages/backend-rs/src/model/entity/channel.rs b/packages/backend-rs/src/model/entity/channel.rs index dcad55ddda..52f8059030 100644 --- a/packages/backend-rs/src/model/entity/channel.rs +++ b/packages/backend-rs/src/model/entity/channel.rs @@ -4,13 +4,17 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "channel")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Channel", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "lastNotedAt")] - pub last_noted_at: Option, + pub last_noted_at: Option, #[sea_orm(column_name = "userId")] pub user_id: Option, pub name: String, diff --git a/packages/backend-rs/src/model/entity/channel_following.rs b/packages/backend-rs/src/model/entity/channel_following.rs index ca7af1e1ba..01a25ccb83 100644 --- a/packages/backend-rs/src/model/entity/channel_following.rs +++ b/packages/backend-rs/src/model/entity/channel_following.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "channel_following")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "ChannelFollowing", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "followeeId")] pub followee_id: String, #[sea_orm(column_name = "followerId")] diff --git a/packages/backend-rs/src/model/entity/channel_note_pining.rs b/packages/backend-rs/src/model/entity/channel_note_pining.rs index 61befb8cf9..0a41efd3e8 100644 --- a/packages/backend-rs/src/model/entity/channel_note_pining.rs +++ b/packages/backend-rs/src/model/entity/channel_note_pining.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "channel_note_pining")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "ChannelNotePining", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "channelId")] pub channel_id: String, #[sea_orm(column_name = "noteId")] diff --git a/packages/backend-rs/src/model/entity/clip.rs b/packages/backend-rs/src/model/entity/clip.rs index 23f748a6dd..6cbbcf4756 100644 --- a/packages/backend-rs/src/model/entity/clip.rs +++ b/packages/backend-rs/src/model/entity/clip.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "clip")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Clip", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub name: String, diff --git a/packages/backend-rs/src/model/entity/clip_note.rs b/packages/backend-rs/src/model/entity/clip_note.rs index be6f01ac0a..262f4a9b50 100644 --- a/packages/backend-rs/src/model/entity/clip_note.rs +++ b/packages/backend-rs/src/model/entity/clip_note.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "clip_note")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "ClipNote", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, diff --git a/packages/backend-rs/src/model/entity/drive_file.rs b/packages/backend-rs/src/model/entity/drive_file.rs index 249d711796..a6926e7af2 100644 --- a/packages/backend-rs/src/model/entity/drive_file.rs +++ b/packages/backend-rs/src/model/entity/drive_file.rs @@ -1,14 +1,19 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15 +use super::sea_orm_active_enums::DriveFileUsageHintEnum; use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "drive_file")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "DriveFile", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: Option, #[sea_orm(column_name = "userHost")] @@ -48,6 +53,8 @@ pub struct Model { pub request_headers: Option, #[sea_orm(column_name = "requestIp")] pub request_ip: Option, + #[sea_orm(column_name = "usageHint")] + pub usage_hint: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/packages/backend-rs/src/model/entity/drive_folder.rs b/packages/backend-rs/src/model/entity/drive_folder.rs index f0c3bfc3ad..727a698ce3 100644 --- a/packages/backend-rs/src/model/entity/drive_folder.rs +++ b/packages/backend-rs/src/model/entity/drive_folder.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "drive_folder")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "DriveFolder", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, pub name: String, #[sea_orm(column_name = "userId")] pub user_id: Option, diff --git a/packages/backend-rs/src/model/entity/emoji.rs b/packages/backend-rs/src/model/entity/emoji.rs index 36aad826cc..530dfe12f5 100644 --- a/packages/backend-rs/src/model/entity/emoji.rs +++ b/packages/backend-rs/src/model/entity/emoji.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "emoji")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Emoji", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "updatedAt")] - pub updated_at: Option, + pub updated_at: Option, pub name: String, pub host: Option, #[sea_orm(column_name = "originalUrl")] diff --git a/packages/backend-rs/src/model/entity/follow_request.rs b/packages/backend-rs/src/model/entity/follow_request.rs index b71814ebd5..4a6b572433 100644 --- a/packages/backend-rs/src/model/entity/follow_request.rs +++ b/packages/backend-rs/src/model/entity/follow_request.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "follow_request")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "FollowRequest", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "followeeId")] pub followee_id: String, #[sea_orm(column_name = "followerId")] diff --git a/packages/backend-rs/src/model/entity/following.rs b/packages/backend-rs/src/model/entity/following.rs index d0fe6d1a87..f19e46140e 100644 --- a/packages/backend-rs/src/model/entity/following.rs +++ b/packages/backend-rs/src/model/entity/following.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "following")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Following", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "followeeId")] pub followee_id: String, #[sea_orm(column_name = "followerId")] diff --git a/packages/backend-rs/src/model/entity/gallery_like.rs b/packages/backend-rs/src/model/entity/gallery_like.rs index edb0bb5a3f..f4ede4169a 100644 --- a/packages/backend-rs/src/model/entity/gallery_like.rs +++ b/packages/backend-rs/src/model/entity/gallery_like.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "gallery_like")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "GalleryLike", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "postId")] diff --git a/packages/backend-rs/src/model/entity/gallery_post.rs b/packages/backend-rs/src/model/entity/gallery_post.rs index ab8f1dab42..797bf38242 100644 --- a/packages/backend-rs/src/model/entity/gallery_post.rs +++ b/packages/backend-rs/src/model/entity/gallery_post.rs @@ -4,13 +4,17 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "gallery_post")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "GalleryPost", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "updatedAt")] - pub updated_at: DateTimeWithTimeZone, + pub updated_at: DateTime, pub title: String, pub description: Option, #[sea_orm(column_name = "userId")] diff --git a/packages/backend-rs/src/model/entity/hashtag.rs b/packages/backend-rs/src/model/entity/hashtag.rs index b98ec49bcb..e2bb816b26 100644 --- a/packages/backend-rs/src/model/entity/hashtag.rs +++ b/packages/backend-rs/src/model/entity/hashtag.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "hashtag")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Hashtag", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, diff --git a/packages/backend-rs/src/model/entity/instance.rs b/packages/backend-rs/src/model/entity/instance.rs index 408ad56ce9..8b598f72b1 100644 --- a/packages/backend-rs/src/model/entity/instance.rs +++ b/packages/backend-rs/src/model/entity/instance.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "instance")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Instance", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "caughtAt")] - pub caught_at: DateTimeWithTimeZone, + pub caught_at: DateTime, pub host: String, #[sea_orm(column_name = "usersCount")] pub users_count: i32, @@ -19,13 +23,13 @@ pub struct Model { #[sea_orm(column_name = "followersCount")] pub followers_count: i32, #[sea_orm(column_name = "latestRequestSentAt")] - pub latest_request_sent_at: Option, + pub latest_request_sent_at: Option, #[sea_orm(column_name = "latestStatus")] pub latest_status: Option, #[sea_orm(column_name = "latestRequestReceivedAt")] - pub latest_request_received_at: Option, + pub latest_request_received_at: Option, #[sea_orm(column_name = "lastCommunicatedAt")] - pub last_communicated_at: DateTimeWithTimeZone, + pub last_communicated_at: DateTime, #[sea_orm(column_name = "isNotResponding")] pub is_not_responding: bool, #[sea_orm(column_name = "softwareName")] @@ -41,7 +45,7 @@ pub struct Model { #[sea_orm(column_name = "maintainerEmail")] pub maintainer_email: Option, #[sea_orm(column_name = "infoUpdatedAt")] - pub info_updated_at: Option, + pub info_updated_at: Option, #[sea_orm(column_name = "isSuspended")] pub is_suspended: bool, #[sea_orm(column_name = "iconUrl")] diff --git a/packages/backend-rs/src/model/entity/messaging_message.rs b/packages/backend-rs/src/model/entity/messaging_message.rs index adce4351af..304f876d1a 100644 --- a/packages/backend-rs/src/model/entity/messaging_message.rs +++ b/packages/backend-rs/src/model/entity/messaging_message.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "messaging_message")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "MessagingMessage", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "recipientId")] @@ -31,7 +35,7 @@ pub enum Relation { from = "Column::FileId", to = "super::drive_file::Column::Id", on_update = "NoAction", - on_delete = "Cascade" + on_delete = "SetNull" )] DriveFile, #[sea_orm( diff --git a/packages/backend-rs/src/model/entity/meta.rs b/packages/backend-rs/src/model/entity/meta.rs index c6f0b6a9d0..fcba9e0be9 100644 --- a/packages/backend-rs/src/model/entity/meta.rs +++ b/packages/backend-rs/src/model/entity/meta.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "meta")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Meta", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, @@ -36,8 +40,6 @@ pub struct Model { pub icon_url: Option, #[sea_orm(column_name = "cacheRemoteFiles")] pub cache_remote_files: bool, - #[sea_orm(column_name = "markLocalFilesNsfwByDefault")] - pub always_make_server_file_nsfw: bool, #[sea_orm(column_name = "enableRecaptcha")] pub enable_recaptcha: bool, #[sea_orm(column_name = "recaptchaSiteKey")] @@ -169,6 +171,10 @@ pub struct Model { pub donation_link: Option, #[sea_orm(column_name = "moreUrls", column_type = "JsonBinary")] pub more_urls: Json, + #[sea_orm(column_name = "markLocalFilesNsfwByDefault")] + pub mark_local_files_nsfw_by_default: bool, + #[sea_orm(column_name = "antennaLimit")] + pub antenna_limit: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/packages/backend-rs/src/model/entity/migrations.rs b/packages/backend-rs/src/model/entity/migrations.rs index 04b79bcbae..235156ba4e 100644 --- a/packages/backend-rs/src/model/entity/migrations.rs +++ b/packages/backend-rs/src/model/entity/migrations.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "migrations")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Migrations", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key)] pub id: i32, diff --git a/packages/backend-rs/src/model/entity/moderation_log.rs b/packages/backend-rs/src/model/entity/moderation_log.rs index 1e2807dd4d..b76f2c33df 100644 --- a/packages/backend-rs/src/model/entity/moderation_log.rs +++ b/packages/backend-rs/src/model/entity/moderation_log.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "moderation_log")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "ModerationLog", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub r#type: String, diff --git a/packages/backend-rs/src/model/entity/muted_note.rs b/packages/backend-rs/src/model/entity/muted_note.rs index 60d5d01742..7c2880a03d 100644 --- a/packages/backend-rs/src/model/entity/muted_note.rs +++ b/packages/backend-rs/src/model/entity/muted_note.rs @@ -5,6 +5,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "muted_note")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "MutedNote", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, diff --git a/packages/backend-rs/src/model/entity/muting.rs b/packages/backend-rs/src/model/entity/muting.rs index 023439e4a9..917e6a2e20 100644 --- a/packages/backend-rs/src/model/entity/muting.rs +++ b/packages/backend-rs/src/model/entity/muting.rs @@ -4,17 +4,21 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "muting")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Muting", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "muteeId")] pub mutee_id: String, #[sea_orm(column_name = "muterId")] pub muter_id: String, #[sea_orm(column_name = "expiresAt")] - pub expires_at: Option, + pub expires_at: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/packages/backend-rs/src/model/entity/note.rs b/packages/backend-rs/src/model/entity/note.rs index 271ea1fa65..5903216c1a 100644 --- a/packages/backend-rs/src/model/entity/note.rs +++ b/packages/backend-rs/src/model/entity/note.rs @@ -5,11 +5,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "note")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Note", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "replyId")] pub reply_id: Option, #[sea_orm(column_name = "renoteId")] @@ -17,6 +21,7 @@ pub struct Model { #[sea_orm(column_type = "Text", nullable)] pub text: Option, pub name: Option, + #[sea_orm(column_type = "Text", nullable)] pub cw: Option, #[sea_orm(column_name = "userId")] pub user_id: String, @@ -60,7 +65,7 @@ pub struct Model { #[sea_orm(column_name = "threadId")] pub thread_id: Option, #[sea_orm(column_name = "updatedAt")] - pub updated_at: Option, + pub updated_at: Option, pub lang: Option, } diff --git a/packages/backend-rs/src/model/entity/note_edit.rs b/packages/backend-rs/src/model/entity/note_edit.rs index a403560b39..edfb35029a 100644 --- a/packages/backend-rs/src/model/entity/note_edit.rs +++ b/packages/backend-rs/src/model/entity/note_edit.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "note_edit")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "NoteEdit", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, @@ -15,7 +19,8 @@ pub struct Model { #[sea_orm(column_name = "fileIds")] pub file_ids: Vec, #[sea_orm(column_name = "updatedAt")] - pub updated_at: DateTimeWithTimeZone, + pub updated_at: DateTime, + pub emojis: Vec, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/packages/backend-rs/src/model/entity/note_favorite.rs b/packages/backend-rs/src/model/entity/note_favorite.rs index d202da3ff6..76d45e9e98 100644 --- a/packages/backend-rs/src/model/entity/note_favorite.rs +++ b/packages/backend-rs/src/model/entity/note_favorite.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "note_favorite")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "NoteFavorite", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "noteId")] diff --git a/packages/backend-rs/src/model/entity/note_file.rs b/packages/backend-rs/src/model/entity/note_file.rs index 00281e64e3..2c52a4e5e8 100644 --- a/packages/backend-rs/src/model/entity/note_file.rs +++ b/packages/backend-rs/src/model/entity/note_file.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "note_file")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "NoteFile", use_nullable = true) +)] pub struct Model { #[sea_orm(column_name = "serialNo", primary_key)] pub serial_no: i64, diff --git a/packages/backend-rs/src/model/entity/note_reaction.rs b/packages/backend-rs/src/model/entity/note_reaction.rs index f99a23900a..dd870a3e7f 100644 --- a/packages/backend-rs/src/model/entity/note_reaction.rs +++ b/packages/backend-rs/src/model/entity/note_reaction.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "note_reaction")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "NoteReaction", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "noteId")] diff --git a/packages/backend-rs/src/model/entity/note_thread_muting.rs b/packages/backend-rs/src/model/entity/note_thread_muting.rs index 7bb30b5262..965001189e 100644 --- a/packages/backend-rs/src/model/entity/note_thread_muting.rs +++ b/packages/backend-rs/src/model/entity/note_thread_muting.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "note_thread_muting")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "NoteThreadMuting", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "threadId")] diff --git a/packages/backend-rs/src/model/entity/note_unread.rs b/packages/backend-rs/src/model/entity/note_unread.rs index 7823bcbf0d..ba96aed69f 100644 --- a/packages/backend-rs/src/model/entity/note_unread.rs +++ b/packages/backend-rs/src/model/entity/note_unread.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "note_unread")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "NoteUnread", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, diff --git a/packages/backend-rs/src/model/entity/note_watching.rs b/packages/backend-rs/src/model/entity/note_watching.rs index 58079e20cf..5b3b331e90 100644 --- a/packages/backend-rs/src/model/entity/note_watching.rs +++ b/packages/backend-rs/src/model/entity/note_watching.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "note_watching")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "NoteWatching", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "noteId")] diff --git a/packages/backend-rs/src/model/entity/notification.rs b/packages/backend-rs/src/model/entity/notification.rs index ca4919bb30..6ed5f718aa 100644 --- a/packages/backend-rs/src/model/entity/notification.rs +++ b/packages/backend-rs/src/model/entity/notification.rs @@ -5,11 +5,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "notification")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Notification", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "notifieeId")] pub notifiee_id: String, #[sea_orm(column_name = "notifierId")] diff --git a/packages/backend-rs/src/model/entity/page.rs b/packages/backend-rs/src/model/entity/page.rs index df312fda00..e1652a372b 100644 --- a/packages/backend-rs/src/model/entity/page.rs +++ b/packages/backend-rs/src/model/entity/page.rs @@ -5,13 +5,17 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "page")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Page", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "updatedAt")] - pub updated_at: DateTimeWithTimeZone, + pub updated_at: DateTime, pub title: String, pub name: String, pub summary: Option, diff --git a/packages/backend-rs/src/model/entity/page_like.rs b/packages/backend-rs/src/model/entity/page_like.rs index a1c9e81963..c1e59ef0e1 100644 --- a/packages/backend-rs/src/model/entity/page_like.rs +++ b/packages/backend-rs/src/model/entity/page_like.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "page_like")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "PageLike", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "pageId")] diff --git a/packages/backend-rs/src/model/entity/password_reset_request.rs b/packages/backend-rs/src/model/entity/password_reset_request.rs index 55100dc0c5..058eaedebe 100644 --- a/packages/backend-rs/src/model/entity/password_reset_request.rs +++ b/packages/backend-rs/src/model/entity/password_reset_request.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "password_reset_request")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "PasswordResetRequest", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, pub token: String, #[sea_orm(column_name = "userId")] pub user_id: String, diff --git a/packages/backend-rs/src/model/entity/poll.rs b/packages/backend-rs/src/model/entity/poll.rs index 8d5dbee0f2..6bcbcac08b 100644 --- a/packages/backend-rs/src/model/entity/poll.rs +++ b/packages/backend-rs/src/model/entity/poll.rs @@ -5,11 +5,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "poll")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Poll", use_nullable = true) +)] pub struct Model { #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)] pub note_id: String, #[sea_orm(column_name = "expiresAt")] - pub expires_at: Option, + pub expires_at: Option, pub multiple: bool, pub choices: Vec, pub votes: Vec, diff --git a/packages/backend-rs/src/model/entity/poll_vote.rs b/packages/backend-rs/src/model/entity/poll_vote.rs index ce5f517c53..0f2df2f5db 100644 --- a/packages/backend-rs/src/model/entity/poll_vote.rs +++ b/packages/backend-rs/src/model/entity/poll_vote.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "poll_vote")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "PollVote", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "noteId")] diff --git a/packages/backend-rs/src/model/entity/promo_note.rs b/packages/backend-rs/src/model/entity/promo_note.rs index a9fe33e607..c4e012b1a9 100644 --- a/packages/backend-rs/src/model/entity/promo_note.rs +++ b/packages/backend-rs/src/model/entity/promo_note.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "promo_note")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "PromoNote", use_nullable = true) +)] pub struct Model { #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)] pub note_id: String, #[sea_orm(column_name = "expiresAt")] - pub expires_at: DateTimeWithTimeZone, + pub expires_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, } diff --git a/packages/backend-rs/src/model/entity/promo_read.rs b/packages/backend-rs/src/model/entity/promo_read.rs index 5f587ad829..10fe176405 100644 --- a/packages/backend-rs/src/model/entity/promo_read.rs +++ b/packages/backend-rs/src/model/entity/promo_read.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "promo_read")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "PromoRead", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "noteId")] diff --git a/packages/backend-rs/src/model/entity/registration_ticket.rs b/packages/backend-rs/src/model/entity/registration_ticket.rs index 7581ae95e2..55d60d78b0 100644 --- a/packages/backend-rs/src/model/entity/registration_ticket.rs +++ b/packages/backend-rs/src/model/entity/registration_ticket.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "registration_ticket")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "RegistrationTicket", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, pub code: String, } diff --git a/packages/backend-rs/src/model/entity/registry_item.rs b/packages/backend-rs/src/model/entity/registry_item.rs index c7b81331af..74ae18cef3 100644 --- a/packages/backend-rs/src/model/entity/registry_item.rs +++ b/packages/backend-rs/src/model/entity/registry_item.rs @@ -4,13 +4,17 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "registry_item")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "RegistryItem", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "updatedAt")] - pub updated_at: DateTimeWithTimeZone, + pub updated_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub key: String, diff --git a/packages/backend-rs/src/model/entity/relay.rs b/packages/backend-rs/src/model/entity/relay.rs index 6073c943e0..c035a74bec 100644 --- a/packages/backend-rs/src/model/entity/relay.rs +++ b/packages/backend-rs/src/model/entity/relay.rs @@ -5,6 +5,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "relay")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Relay", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, diff --git a/packages/backend-rs/src/model/entity/renote_muting.rs b/packages/backend-rs/src/model/entity/renote_muting.rs index 8b7df4a140..b6604cad88 100644 --- a/packages/backend-rs/src/model/entity/renote_muting.rs +++ b/packages/backend-rs/src/model/entity/renote_muting.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "renote_muting")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "RenoteMuting", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "muteeId")] pub mutee_id: String, #[sea_orm(column_name = "muterId")] diff --git a/packages/backend-rs/src/model/entity/reply_muting.rs b/packages/backend-rs/src/model/entity/reply_muting.rs index 429bbe7566..84fe0cbbfa 100644 --- a/packages/backend-rs/src/model/entity/reply_muting.rs +++ b/packages/backend-rs/src/model/entity/reply_muting.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "reply_muting")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "ReplyMuting", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "muteeId")] pub mutee_id: String, #[sea_orm(column_name = "muterId")] diff --git a/packages/backend-rs/src/model/entity/sea_orm_active_enums.rs b/packages/backend-rs/src/model/entity/sea_orm_active_enums.rs index 5e3666c352..36281f4dc5 100644 --- a/packages/backend-rs/src/model/entity/sea_orm_active_enums.rs +++ b/packages/backend-rs/src/model/entity/sea_orm_active_enums.rs @@ -2,7 +2,9 @@ use sea_orm::entity::prelude::*; -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "antenna_src_enum")] pub enum AntennaSrcEnum { #[sea_orm(string_value = "all")] @@ -18,7 +20,23 @@ pub enum AntennaSrcEnum { #[sea_orm(string_value = "users")] Users, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] +#[sea_orm( + rs_type = "String", + db_type = "Enum", + enum_name = "drive_file_usage_hint_enum" +)] +pub enum DriveFileUsageHintEnum { + #[sea_orm(string_value = "userAvatar")] + UserAvatar, + #[sea_orm(string_value = "userBanner")] + UserBanner, +} +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm( rs_type = "String", db_type = "Enum", @@ -34,7 +52,9 @@ pub enum MutedNoteReasonEnum { #[sea_orm(string_value = "word")] Word, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm( rs_type = "String", db_type = "Enum", @@ -52,7 +72,9 @@ pub enum NoteVisibilityEnum { #[sea_orm(string_value = "specified")] Specified, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm( rs_type = "String", db_type = "Enum", @@ -84,7 +106,9 @@ pub enum NotificationTypeEnum { #[sea_orm(string_value = "reply")] Reply, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm( rs_type = "String", db_type = "Enum", @@ -98,7 +122,9 @@ pub enum PageVisibilityEnum { #[sea_orm(string_value = "specified")] Specified, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm( rs_type = "String", db_type = "Enum", @@ -114,7 +140,9 @@ pub enum PollNotevisibilityEnum { #[sea_orm(string_value = "specified")] Specified, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "relay_status_enum")] pub enum RelayStatusEnum { #[sea_orm(string_value = "accepted")] @@ -124,7 +152,9 @@ pub enum RelayStatusEnum { #[sea_orm(string_value = "requesting")] Requesting, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm( rs_type = "String", db_type = "Enum", @@ -140,7 +170,9 @@ pub enum UserEmojimodpermEnum { #[sea_orm(string_value = "unauthorized")] Unauthorized, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm( rs_type = "String", db_type = "Enum", @@ -154,7 +186,9 @@ pub enum UserProfileFfvisibilityEnum { #[sea_orm(string_value = "public")] Public, } -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)] +#[cfg_attr(not(feature = "napi"), derive(Clone))] +#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))] #[sea_orm( rs_type = "String", db_type = "Enum", diff --git a/packages/backend-rs/src/model/entity/signin.rs b/packages/backend-rs/src/model/entity/signin.rs index b0624b00b0..491f079a82 100644 --- a/packages/backend-rs/src/model/entity/signin.rs +++ b/packages/backend-rs/src/model/entity/signin.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "signin")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Signin", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub ip: String, diff --git a/packages/backend-rs/src/model/entity/sw_subscription.rs b/packages/backend-rs/src/model/entity/sw_subscription.rs index ecebc06ff1..4aa275f77b 100644 --- a/packages/backend-rs/src/model/entity/sw_subscription.rs +++ b/packages/backend-rs/src/model/entity/sw_subscription.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "sw_subscription")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "SwSubscription", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub endpoint: String, diff --git a/packages/backend-rs/src/model/entity/used_username.rs b/packages/backend-rs/src/model/entity/used_username.rs index 8972a20718..9e108a8a4f 100644 --- a/packages/backend-rs/src/model/entity/used_username.rs +++ b/packages/backend-rs/src/model/entity/used_username.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "used_username")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UsedUsername", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub username: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/packages/backend-rs/src/model/entity/user.rs b/packages/backend-rs/src/model/entity/user.rs index 8f673089a8..8af0b27e88 100644 --- a/packages/backend-rs/src/model/entity/user.rs +++ b/packages/backend-rs/src/model/entity/user.rs @@ -5,15 +5,19 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "User", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "updatedAt")] - pub updated_at: Option, + pub updated_at: Option, #[sea_orm(column_name = "lastFetchedAt")] - pub last_fetched_at: Option, + pub last_fetched_at: Option, pub username: String, #[sea_orm(column_name = "usernameLower")] pub username_lower: String, @@ -57,7 +61,7 @@ pub struct Model { #[sea_orm(column_name = "followersUri")] pub followers_uri: Option, #[sea_orm(column_name = "lastActiveDate")] - pub last_active_date: Option, + pub last_active_date: Option, #[sea_orm(column_name = "hideOnlineStatus")] pub hide_online_status: bool, #[sea_orm(column_name = "isDeleted")] diff --git a/packages/backend-rs/src/model/entity/user_group.rs b/packages/backend-rs/src/model/entity/user_group.rs index c412ada09c..7d9ae71b24 100644 --- a/packages/backend-rs/src/model/entity/user_group.rs +++ b/packages/backend-rs/src/model/entity/user_group.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_group")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserGroup", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, pub name: String, #[sea_orm(column_name = "userId")] pub user_id: String, diff --git a/packages/backend-rs/src/model/entity/user_group_invitation.rs b/packages/backend-rs/src/model/entity/user_group_invitation.rs index 0a60a97ed3..c449a48078 100644 --- a/packages/backend-rs/src/model/entity/user_group_invitation.rs +++ b/packages/backend-rs/src/model/entity/user_group_invitation.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_group_invitation")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserGroupInvitation", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "userGroupId")] diff --git a/packages/backend-rs/src/model/entity/user_group_invite.rs b/packages/backend-rs/src/model/entity/user_group_invite.rs index 6aaa5396d5..3df43af3f6 100644 --- a/packages/backend-rs/src/model/entity/user_group_invite.rs +++ b/packages/backend-rs/src/model/entity/user_group_invite.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_group_invite")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserGroupInvite", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "userGroupId")] diff --git a/packages/backend-rs/src/model/entity/user_group_joining.rs b/packages/backend-rs/src/model/entity/user_group_joining.rs index 040e0f2a36..2ff31b3a5f 100644 --- a/packages/backend-rs/src/model/entity/user_group_joining.rs +++ b/packages/backend-rs/src/model/entity/user_group_joining.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_group_joining")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserGroupJoining", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "userGroupId")] diff --git a/packages/backend-rs/src/model/entity/user_ip.rs b/packages/backend-rs/src/model/entity/user_ip.rs index 7a79d4448f..d6eadc7f71 100644 --- a/packages/backend-rs/src/model/entity/user_ip.rs +++ b/packages/backend-rs/src/model/entity/user_ip.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_ip")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserIp", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key)] pub id: i32, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub ip: String, diff --git a/packages/backend-rs/src/model/entity/user_keypair.rs b/packages/backend-rs/src/model/entity/user_keypair.rs index 7a22f44a91..d59853158a 100644 --- a/packages/backend-rs/src/model/entity/user_keypair.rs +++ b/packages/backend-rs/src/model/entity/user_keypair.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_keypair")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserKeypair", use_nullable = true) +)] pub struct Model { #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)] pub user_id: String, diff --git a/packages/backend-rs/src/model/entity/user_list.rs b/packages/backend-rs/src/model/entity/user_list.rs index 832c65869f..356ec5318c 100644 --- a/packages/backend-rs/src/model/entity/user_list.rs +++ b/packages/backend-rs/src/model/entity/user_list.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_list")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserList", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub name: String, diff --git a/packages/backend-rs/src/model/entity/user_list_joining.rs b/packages/backend-rs/src/model/entity/user_list_joining.rs index db0cdca6b4..037d7af181 100644 --- a/packages/backend-rs/src/model/entity/user_list_joining.rs +++ b/packages/backend-rs/src/model/entity/user_list_joining.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_list_joining")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserListJoining", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "userListId")] diff --git a/packages/backend-rs/src/model/entity/user_note_pining.rs b/packages/backend-rs/src/model/entity/user_note_pining.rs index b9ced3f3c2..f0a80a66c9 100644 --- a/packages/backend-rs/src/model/entity/user_note_pining.rs +++ b/packages/backend-rs/src/model/entity/user_note_pining.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_note_pining")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserNotePining", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, #[sea_orm(column_name = "noteId")] diff --git a/packages/backend-rs/src/model/entity/user_pending.rs b/packages/backend-rs/src/model/entity/user_pending.rs index b96c5e6368..1fa13c2829 100644 --- a/packages/backend-rs/src/model/entity/user_pending.rs +++ b/packages/backend-rs/src/model/entity/user_pending.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_pending")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserPending", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, pub code: String, pub username: String, pub email: String, diff --git a/packages/backend-rs/src/model/entity/user_profile.rs b/packages/backend-rs/src/model/entity/user_profile.rs index f806f1d07b..a121118926 100644 --- a/packages/backend-rs/src/model/entity/user_profile.rs +++ b/packages/backend-rs/src/model/entity/user_profile.rs @@ -6,6 +6,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_profile")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserProfile", use_nullable = true) +)] pub struct Model { #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)] pub user_id: String, diff --git a/packages/backend-rs/src/model/entity/user_publickey.rs b/packages/backend-rs/src/model/entity/user_publickey.rs index b4181de196..ad6a456ead 100644 --- a/packages/backend-rs/src/model/entity/user_publickey.rs +++ b/packages/backend-rs/src/model/entity/user_publickey.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_publickey")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserPublickey", use_nullable = true) +)] pub struct Model { #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)] pub user_id: String, diff --git a/packages/backend-rs/src/model/entity/user_security_key.rs b/packages/backend-rs/src/model/entity/user_security_key.rs index e4d6b86b67..aae6dfa8c6 100644 --- a/packages/backend-rs/src/model/entity/user_security_key.rs +++ b/packages/backend-rs/src/model/entity/user_security_key.rs @@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user_security_key")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "UserSecurityKey", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, @@ -12,7 +16,7 @@ pub struct Model { #[sea_orm(column_name = "publicKey")] pub public_key: String, #[sea_orm(column_name = "lastUsed")] - pub last_used: DateTimeWithTimeZone, + pub last_used: DateTime, pub name: String, } diff --git a/packages/backend-rs/src/model/entity/webhook.rs b/packages/backend-rs/src/model/entity/webhook.rs index bce26e11d9..e7656056b9 100644 --- a/packages/backend-rs/src/model/entity/webhook.rs +++ b/packages/backend-rs/src/model/entity/webhook.rs @@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "webhook")] +#[cfg_attr( + feature = "napi", + napi_derive::napi(object, js_name = "Webhook", use_nullable = true) +)] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(column_name = "createdAt")] - pub created_at: DateTimeWithTimeZone, + pub created_at: DateTime, #[sea_orm(column_name = "userId")] pub user_id: String, pub name: String, @@ -17,7 +21,7 @@ pub struct Model { pub secret: String, pub active: bool, #[sea_orm(column_name = "latestSentAt")] - pub latest_sent_at: Option, + pub latest_sent_at: Option, #[sea_orm(column_name = "latestStatus")] pub latest_status: Option, } diff --git a/packages/backend-rs/src/model/error.rs b/packages/backend-rs/src/model/error.rs index 8e9213066b..b3d9f6eda5 100644 --- a/packages/backend-rs/src/model/error.rs +++ b/packages/backend-rs/src/model/error.rs @@ -1,15 +1,9 @@ -use crate::impl_into_napi_error; - #[derive(thiserror::Error, Debug, PartialEq, Eq)] pub enum Error { #[error("Failed to parse string: {0}")] ParseError(#[from] parse_display::ParseError), - #[error("Failed to get database connection: {0}")] - DbConnError(#[from] crate::database::error::Error), - #[error("Database operation error: {0}")] - DbOperationError(#[from] sea_orm::DbErr), + #[error("Database error: {0}")] + DbError(#[from] sea_orm::DbErr), #[error("Requested entity not found")] NotFound, } - -impl_into_napi_error!(Error); diff --git a/packages/backend-rs/src/util/id.rs b/packages/backend-rs/src/util/id.rs index 9d1427e65d..20b2f2b74c 100644 --- a/packages/backend-rs/src/util/id.rs +++ b/packages/backend-rs/src/util/id.rs @@ -2,18 +2,14 @@ use basen::BASE36; use cfg_if::cfg_if; -use chrono::Utc; +use chrono::NaiveDateTime; use once_cell::sync::OnceCell; use std::cmp; -use crate::impl_into_napi_error; - #[derive(thiserror::Error, Debug, PartialEq, Eq)] #[error("ID generator has not been initialized yet")] pub struct ErrorUninitialized; -impl_into_napi_error!(ErrorUninitialized); - static FINGERPRINT: OnceCell = OnceCell::new(); static GENERATOR: OnceCell = OnceCell::new(); @@ -21,7 +17,8 @@ const TIME_2000: i64 = 946_684_800_000; const TIMESTAMP_LENGTH: u16 = 8; /// Initializes Cuid2 generator. Must be called before any [create_id]. -pub fn init_id(length: u16, fingerprint: &str) { +#[crate::export] +pub fn init_id_generator(length: u16, fingerprint: &str) { FINGERPRINT.get_or_init(move || format!("{}{}", fingerprint, cuid2::create_id())); GENERATOR.get_or_init(move || { cuid2::CuidConstructor::new() @@ -33,26 +30,21 @@ pub fn init_id(length: u16, fingerprint: &str) { /// Returns Cuid2 with the length specified by [init_id]. Must be called after /// [init_id], otherwise returns [ErrorUninitialized]. -/// The current timestamp via [chrono::Utc] is used if `date_num` is `0`. -pub fn create_id(date_num: i64) -> Result { +pub fn create_id(datetime: &NaiveDateTime) -> Result { match GENERATOR.get() { None => Err(ErrorUninitialized), Some(gen) => { - let date_num = if date_num > 0 { - date_num - } else { - Utc::now().timestamp_millis() - }; - let time = cmp::max(date_num - TIME_2000, 0); + let date_num = cmp::max(0, datetime.and_utc().timestamp_millis() - TIME_2000) as u64; Ok(format!( "{:0>8}{}", - BASE36.encode_var_len(&(time as u64)), + BASE36.encode_var_len(&date_num), gen.create_id() )) } } } +#[crate::export] pub fn get_timestamp(id: &str) -> i64 { let n: Option = BASE36.decode_var_len(&id[0..8]); match n { @@ -63,23 +55,17 @@ pub fn get_timestamp(id: &str) -> i64 { cfg_if! { if #[cfg(feature = "napi")] { - use napi_derive::napi; + use chrono::{DateTime, Utc}; - /// Calls [init_id] inside. Must be called before [native_create_id]. - #[napi] - pub fn native_init_id_generator(length: u16, fingerprint: String) { - init_id(length, &fingerprint); - } - - /// Generates - #[napi] - pub fn native_create_id(date_num: i64) -> String { - create_id(date_num).unwrap() - } - - #[napi] - pub fn native_get_timestamp(id: String) -> i64 { - get_timestamp(&id) + /// The generated ID results in the form of `[8 chars timestamp] + [cuid2]`. + /// The minimum and maximum lengths are 16 and 24, respectively. + /// With the length of 16, namely 8 for cuid2, roughly 1427399 IDs are needed + /// in the same millisecond to reach 50% chance of collision. + /// + /// Ref: https://github.com/paralleldrive/cuid2#parameterized-length + #[napi_derive::napi] + pub fn gen_id(date: Option>) -> String { + create_id(&date.unwrap_or_else(Utc::now).naive_utc()).unwrap() } } } @@ -92,18 +78,18 @@ mod unit_test { use std::thread; #[test] - fn can_create_and_decode() { - assert_eq!(id::create_id(0), Err(id::ErrorUninitialized)); - id::init_id(16, ""); - assert_eq!(id::create_id(0).unwrap().len(), 16); - assert_ne!(id::create_id(0).unwrap(), id::create_id(0).unwrap()); - let id1 = thread::spawn(|| id::create_id(0).unwrap()); - let id2 = thread::spawn(|| id::create_id(0).unwrap()); + fn can_create_and_decode_id() { + let now = Utc::now().naive_utc(); + assert_eq!(id::create_id(&now), Err(id::ErrorUninitialized)); + id::init_id_generator(16, ""); + assert_eq!(id::create_id(&now).unwrap().len(), 16); + assert_ne!(id::create_id(&now).unwrap(), id::create_id(&now).unwrap()); + let id1 = thread::spawn(move || id::create_id(&now).unwrap()); + let id2 = thread::spawn(move || id::create_id(&now).unwrap()); assert_ne!(id1.join().unwrap(), id2.join().unwrap()); - let now = Utc::now().timestamp_millis(); - let test_id = id::create_id(now).unwrap(); + let test_id = id::create_id(&now).unwrap(); let timestamp = id::get_timestamp(&test_id); - assert_eq!(now, timestamp); + assert_eq!(now.and_utc().timestamp_millis(), timestamp); } } diff --git a/packages/backend-rs/src/util/random.rs b/packages/backend-rs/src/util/random.rs index ffcbca980f..61edbf11cf 100644 --- a/packages/backend-rs/src/util/random.rs +++ b/packages/backend-rs/src/util/random.rs @@ -9,10 +9,9 @@ pub fn gen_string(length: u16) -> String { .collect() } -#[cfg(feature = "napi")] -#[napi_derive::napi] -pub fn native_random_str(length: u16) -> String { - gen_string(length) +#[crate::export(js_name = "secureRndstr")] +pub fn native_random_str(length: Option) -> String { + gen_string(length.unwrap_or(32)) } #[cfg(test)] diff --git a/packages/backend/package.json b/packages/backend/package.json index af0821e3ad..9289c2f7ea 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -22,26 +22,23 @@ "@swc/core-android-arm64": "1.3.11" }, "dependencies": { - "@bull-board/api": "5.15.2", - "@bull-board/koa": "5.15.2", - "@bull-board/ui": "5.15.2", - "@discordapp/twemoji": "^15.0.2", + "@bull-board/api": "5.15.5", + "@bull-board/koa": "5.15.5", + "@bull-board/ui": "5.15.5", + "@discordapp/twemoji": "^15.0.3", "@koa/cors": "5.0.0", "@koa/multer": "3.0.2", "@koa/router": "12.0.1", "@ladjs/koa-views": "9.0.0", "@peertube/http-signature": "1.7.0", - "@redocly/openapi-core": "1.10.6", + "@redocly/openapi-core": "1.11.0", "@sinonjs/fake-timers": "11.2.2", - "@twemoji/parser": "^15.0.0", "adm-zip": "0.5.10", "ajv": "8.12.0", "archiver": "7.0.1", - "argon2": "^0.40.1", - "aws-sdk": "2.1585.0", + "aws-sdk": "2.1599.0", "axios": "^1.6.8", "backend-rs": "workspace:*", - "bcryptjs": "2.4.3", "blurhash": "2.0.5", "bull": "4.12.2", "cacheable-lookup": "TheEssem/cacheable-lookup", @@ -54,7 +51,7 @@ "date-fns": "3.6.0", "decompress": "^4.2.1", "deep-email-validator": "0.1.21", - "deepl-node": "1.12.0", + "deepl-node": "1.13.0", "escape-regexp": "0.0.1", "feed": "4.2.2", "file-type": "19.0.0", @@ -62,16 +59,16 @@ "form-data": "^4.0.0", "got": "14.2.1", "gunzip-maybe": "^1.4.2", - "happy-dom": "^14.3.8", + "happy-dom": "^14.7.1", "hpagent": "1.2.0", "ioredis": "5.3.2", "ip-cidr": "4.0.0", "is-svg": "5.0.0", - "js-yaml": "4.1.0", "json5": "2.2.3", "jsonld": "8.3.2", "jsrsasign": "11.1.0", - "koa": "2.15.2", + "katex": "0.16.10", + "koa": "2.15.3", "koa-body": "^6.0.1", "koa-bodyparser": "4.4.1", "koa-favicon": "2.1.0", @@ -91,21 +88,20 @@ "nodemailer": "6.9.13", "opencc-js": "^1.0.5", "os-utils": "0.0.14", - "otpauth": "^9.2.2", + "otpauth": "^9.2.3", "parse5": "7.1.2", - "pg": "8.11.3", + "pg": "8.11.5", "private-ip": "3.0.2", "probe-image-size": "7.2.3", "promise-limit": "2.7.0", "punycode": "2.3.1", "pureimage": "0.4.13", "qrcode": "1.5.3", - "qs": "6.12.0", + "qs": "6.12.1", "random-seed": "0.3.0", "ratelimiter": "3.4.1", - "re2": "1.20.10", "redis-semaphore": "5.5.1", - "reflect-metadata": "0.2.1", + "reflect-metadata": "0.2.2", "rename": "1.0.4", "rndstr": "1.0.0", "rss-parser": "3.13.0", @@ -115,7 +111,7 @@ "stringz": "2.1.0", "summaly": "2.7.0", "syslog-pro": "1.0.0", - "systeminformation": "5.22.6", + "systeminformation": "5.22.7", "tar-stream": "^3.1.7", "tesseract.js": "^5.0.5", "tinycolor2": "1.6.0", @@ -128,17 +124,16 @@ "xev": "3.0.2" }, "devDependencies": { - "@swc/cli": "0.3.10", - "@swc/core": "1.4.11", + "@swc/cli": "0.3.12", + "@swc/core": "1.4.13", "@types/adm-zip": "^0.5.5", - "@types/bcryptjs": "2.4.6", "@types/color-convert": "^2.0.3", "@types/content-disposition": "^0.5.8", "@types/escape-regexp": "0.0.3", "@types/fluent-ffmpeg": "2.1.24", - "@types/js-yaml": "4.0.9", "@types/jsonld": "1.5.13", "@types/jsrsasign": "10.5.13", + "@types/katex": "0.16.7", "@types/koa": "2.15.0", "@types/koa-bodyparser": "4.3.12", "@types/koa-cors": "0.0.6", @@ -150,12 +145,12 @@ "@types/koa__multer": "2.0.7", "@types/koa__router": "12.0.4", "@types/mocha": "10.0.6", - "@types/node": "20.11.30", + "@types/node": "20.12.7", "@types/node-fetch": "2.6.11", "@types/nodemailer": "6.4.14", "@types/oauth": "0.9.4", "@types/opencc-js": "^1.0.3", - "@types/pg": "^8.11.4", + "@types/pg": "^8.11.5", "@types/probe-image-size": "^7.2.4", "@types/pug": "2.0.10", "@types/punycode": "2.1.4", @@ -175,15 +170,15 @@ "@types/websocket": "1.0.10", "@types/ws": "8.5.10", "cross-env": "7.0.3", - "eslint": "^8.57.0", - "mocha": "10.3.0", + "eslint": "^9.0.0", + "mocha": "10.4.0", "pug": "3.0.2", "strict-event-emitter-types": "2.0.0", "swc-loader": "^0.2.6", "ts-loader": "9.5.1", "ts-node": "10.9.2", "tsconfig-paths": "4.2.0", - "typescript": "5.4.3", + "typescript": "5.4.5", "webpack": "^5.91.0", "ws": "8.16.0" } diff --git a/packages/backend/src/boot/index.ts b/packages/backend/src/boot/index.ts index 8caf7d062e..9854d2dce4 100644 --- a/packages/backend/src/boot/index.ts +++ b/packages/backend/src/boot/index.ts @@ -3,7 +3,7 @@ import chalk from "chalk"; import Xev from "xev"; import Logger from "@/services/logger.js"; -import { envOption } from "../env.js"; +import { envOption } from "@/config/index.js"; import { inspect } from "node:util"; // for typeorm @@ -76,9 +76,7 @@ cluster.on("exit", (worker) => { }); // Display detail of unhandled promise rejection -if (!envOption.quiet) { - process.on("unhandledRejection", console.dir); -} +process.on("unhandledRejection", console.dir); // Display detail of uncaught exception process.on("uncaughtException", (err) => { diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index e54a2889e2..3ba2d0cf50 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -10,7 +10,7 @@ import semver from "semver"; import Logger from "@/services/logger.js"; import loadConfig from "@/config/load.js"; import type { Config } from "@/config/types.js"; -import { envOption } from "@/env.js"; +import { envOption } from "@/config/index.js"; import { showMachineInfo } from "@/misc/show-machine-info.js"; import { db, initDb } from "@/db/postgre.js"; import { inspect } from "node:util"; @@ -28,58 +28,56 @@ const bootLogger = logger.createSubLogger("boot", "magenta", false); const themeColor = chalk.hex("#31748f"); function greet() { - if (!envOption.quiet) { - //#region Firefish logo - console.log( - themeColor( - "██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄ ", - ), - ); - console.log( - themeColor( - "██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄ ", - ), - ); - console.log( - themeColor( - "█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄ ", - ), - ); - console.log( - themeColor( - "██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄ ", - ), - ); - console.log( - themeColor( - "██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █ ", - ), - ); - console.log( - themeColor( - "╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀ ", - ), - ); - //#endregion + //#region Firefish logo + console.log( + themeColor( + "██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄ ", + ), + ); + console.log( + themeColor( + "██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄ ", + ), + ); + console.log( + themeColor( + "█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄ ", + ), + ); + console.log( + themeColor( + "██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄ ", + ), + ); + console.log( + themeColor( + "██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █ ", + ), + ); + console.log( + themeColor( + "╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀ ", + ), + ); + //#endregion - console.log( - " Firefish is an open-source decentralized microblogging platform.", - ); - console.log( - chalk.rgb( - 255, - 136, - 0, - )( - " If you like Firefish, please consider contributing to the repo. https://firefish.dev/firefish/firefish", - ), - ); + console.log( + " Firefish is an open-source decentralized microblogging platform.", + ); + console.log( + chalk.rgb( + 255, + 136, + 0, + )( + " If you like Firefish, please consider contributing to the repo. https://firefish.dev/firefish/firefish", + ), + ); - console.log(""); - console.log( - chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`, - ); - } + console.log(""); + console.log( + chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`, + ); bootLogger.info("Welcome to Firefish!"); bootLogger.info(`Firefish v${meta.version}`, null, true); diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts index 0acdcd97c6..647ea40fbd 100644 --- a/packages/backend/src/boot/worker.ts +++ b/packages/backend/src/boot/worker.ts @@ -1,11 +1,17 @@ import cluster from "node:cluster"; +import config from "@/config/index.js"; import { initDb } from "@/db/postgre.js"; +import { initIdGenerator } from "backend-rs"; import os from "node:os"; /** * Init worker process */ export async function workerMain() { + const length = Math.min(Math.max(config.cuid?.length ?? 16, 16), 24); + const fingerprint = config.cuid?.fingerprint ?? ""; + initIdGenerator(length, fingerprint); + await initDb(); if (!process.env.mode || process.env.mode === "web") { diff --git a/packages/backend/src/config/index.ts b/packages/backend/src/config/index.ts index ae197b09ca..fe87e5026a 100644 --- a/packages/backend/src/config/index.ts +++ b/packages/backend/src/config/index.ts @@ -1,3 +1,5 @@ import load from "./load.js"; +import { readEnvironmentConfig } from "backend-rs"; export default load(); +export const envOption = readEnvironmentConfig(); diff --git a/packages/backend/src/config/load.ts b/packages/backend/src/config/load.ts index 2ff3309264..682bf309d2 100644 --- a/packages/backend/src/config/load.ts +++ b/packages/backend/src/config/load.ts @@ -5,8 +5,8 @@ import * as fs from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname } from "node:path"; -import * as yaml from "js-yaml"; -import type { Source, Mixin } from "./types.js"; +import type { Mixin } from "./types.js"; +import { readServerConfig } from "backend-rs"; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -32,7 +32,7 @@ export default function load() { "utf-8", ), ); - const config = yaml.load(fs.readFileSync(path, "utf-8")) as Source; + const config = readServerConfig(); const mixin = {} as Mixin; @@ -55,6 +55,7 @@ export default function load() { mixin.userAgent = `Firefish/${meta.version} (${config.url})`; mixin.clientEntry = clientManifest["src/init.ts"]; + if (config.proxyRemoteFiles == null) config.proxyRemoteFiles = true; if (!config.redis.prefix) config.redis.prefix = mixin.hostname; if (config.cacheServer && !config.cacheServer.prefix) config.cacheServer.prefix = mixin.hostname; diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts index 882e429c79..6b593d3b2d 100644 --- a/packages/backend/src/config/types.ts +++ b/packages/backend/src/config/types.ts @@ -1,134 +1,7 @@ -/** - * ユーザーが設定する必要のある情報 - */ -export type Source = { - repository_url?: string; - feedback_url?: string; - url: string; - port: number; - bind?: string; - disableHsts?: boolean; - db: { - host: string; - port: number; - db: string; - user: string; - pass: string; - disableCache?: boolean; - extra?: { [x: string]: string }; - }; - redis: { - host: string; - port: number; - family?: number; - pass?: string; - db?: number; - prefix?: string; - user?: string; - tls?: { [y: string]: string }; - }; - cacheServer?: { - host: string; - port: number; - family?: number; - pass?: string; - db?: number; - prefix?: string; - user?: string; - tls?: { [z: string]: string }; - }; - - proxy?: string; - proxySmtp?: string; - proxyBypassHosts?: string[]; - - allowedPrivateNetworks?: string[]; - - maxFileSize?: number; - - accesslog?: string; - - clusterLimits?: { - web?: number; - queue?: number; - }; - - cuid?: { - length?: number; - fingerprint?: string; - }; - - outgoingAddress?: string; - outgoingAddressFamily?: "ipv4" | "ipv6" | "dual"; - - deliverJobConcurrency?: number; - inboxJobConcurrency?: number; - deliverJobPerSec?: number; - inboxJobPerSec?: number; - deliverJobMaxAttempts?: number; - inboxJobMaxAttempts?: number; - - logLevel?: string[]; - - syslog: { - host: string; - port: number; - }; - - mediaProxy?: string; - proxyRemoteFiles?: boolean; - - twa: { - nameSpace?: string; - packageName?: string; - sha256CertFingerprints?: string[]; - }; - - reservedUsernames?: string[]; - - // Managed hosting stuff - maxUserSignups?: number; - isManagedHosting?: boolean; - maxNoteLength?: number; - maxCaptionLength?: number; - deepl: { - managed?: boolean; - authKey?: string; - isPro?: boolean; - }; - libreTranslate: { - managed?: boolean; - apiUrl?: string; - apiKey?: string; - }; - email: { - managed?: boolean; - address?: string; - host?: string; - port?: number; - user?: string; - pass?: string; - useImplicitSslTls?: boolean; - }; - objectStorage: { - managed?: boolean; - baseUrl?: string; - bucket?: string; - prefix?: string; - endpoint?: string; - region?: string; - accessKey?: string; - secretKey?: string; - useSsl?: boolean; - connnectOverProxy?: boolean; - setPublicReadOnUpload?: boolean; - s3ForcePathStyle?: boolean; - }; - summalyProxyUrl?: string; -}; +import type { ServerConfig } from "backend-rs"; /** - * Misskeyが自動的に(ユーザーが設定した情報から推論して)設定する情報 + * Firefish が自動的に(ユーザーが設定した情報から推論して)設定する情報 */ export type Mixin = { version: string; @@ -144,4 +17,4 @@ export type Mixin = { clientEntry: string; }; -export type Config = Source & Mixin; +export type Config = ServerConfig & Mixin; diff --git a/packages/backend/src/daemons/janitor.ts b/packages/backend/src/daemons/janitor.ts index 2050d54d4c..99b809d1c8 100644 --- a/packages/backend/src/daemons/janitor.ts +++ b/packages/backend/src/daemons/janitor.ts @@ -10,7 +10,7 @@ import { LessThan } from "typeorm"; export default function () { async function tick() { await AttestationChallenges.delete({ - createdAt: LessThan(new Date(new Date().getTime() - 5 * 60 * 1000)), + createdAt: LessThan(new Date(Date.now() - 5 * 60 * 1000)), }); } diff --git a/packages/backend/src/daemons/server-stats.ts b/packages/backend/src/daemons/server-stats.ts index 58a9b1491b..df1f9b3032 100644 --- a/packages/backend/src/daemons/server-stats.ts +++ b/packages/backend/src/daemons/server-stats.ts @@ -1,7 +1,7 @@ import si from "systeminformation"; import Xev from "xev"; import * as osUtils from "os-utils"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; const ev = new Xev(); @@ -13,16 +13,15 @@ const round = (num: number) => Math.round(num * 10) / 10; /** * Report server stats regularly */ -export default function () { +export default async function () { const log = [] as any[]; ev.on("requestServerStatsLog", (x) => { ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length || 50)); }); - fetchMeta().then((meta) => { - if (!meta.enableServerMachineStats) return; - }); + const meta = await fetchMeta(true); + if (!meta.enableServerMachineStats) return; async function tick() { const cpu = await cpuUsage(); diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts index 19f7e7816a..6baccaa271 100644 --- a/packages/backend/src/db/postgre.ts +++ b/packages/backend/src/db/postgre.ts @@ -237,31 +237,3 @@ export async function initDb(force = false) { await db.initialize(); } } - -export async function resetDb() { - const reset = async () => { - await redisClient.flushdb(); - const tables = await db.query(`SELECT relname AS "table" - FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) - WHERE nspname NOT IN ('pg_catalog', 'information_schema') - AND C.relkind = 'r' - AND nspname !~ '^pg_toast';`); - for (const table of tables) { - await db.query(`DELETE FROM "${table.table}" CASCADE`); - } - }; - - for (let i = 1; i <= 3; i++) { - try { - await reset(); - } catch (e) { - if (i === 3) { - throw e; - } else { - await new Promise((resolve) => setTimeout(resolve, 1000)); - continue; - } - } - break; - } -} diff --git a/packages/backend/src/env.ts b/packages/backend/src/env.ts deleted file mode 100644 index a788a0fba2..0000000000 --- a/packages/backend/src/env.ts +++ /dev/null @@ -1,25 +0,0 @@ -const envOption = { - onlyQueue: false, - onlyServer: false, - noDaemons: false, - disableClustering: false, - verbose: false, - withLogTime: false, - quiet: false, - slow: false, -}; - -for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) { - if ( - process.env[ - `MK_${key.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase()}` - ] - ) - envOption[key] = true; -} - -if (process.env.NODE_ENV === "test") envOption.disableClustering = true; -if (process.env.NODE_ENV === "test") envOption.quiet = true; -if (process.env.NODE_ENV === "test") envOption.noDaemons = true; - -export { envOption }; diff --git a/packages/backend/src/mfm/to-html.ts b/packages/backend/src/mfm/to-html.ts index 47ee0c8890..7b7c0967a1 100644 --- a/packages/backend/src/mfm/to-html.ts +++ b/packages/backend/src/mfm/to-html.ts @@ -1,9 +1,23 @@ -import { Window } from "happy-dom"; +import { type HTMLElement, Window } from "happy-dom"; import type * as mfm from "mfm-js"; +import katex from "katex"; import config from "@/config/index.js"; import { intersperse } from "@/prelude/array.js"; import type { IMentionedRemoteUsers } from "@/models/entities/note.js"; +function toMathMl(code: string, displayMode: boolean): HTMLElement | null { + const { window } = new Window(); + const document = window.document; + + document.body.innerHTML = katex.renderToString(code, { + throwOnError: false, + output: "mathml", + displayMode, + }); + + return document.querySelector("math"); +} + export function toHtml( nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = [], @@ -93,12 +107,24 @@ export function toHtml( }, mathInline(node) { + const mathml = toMathMl(node.props.formula, false); + if (mathml != null) { + return mathml; + } + + // fallbacks to element const el = doc.createElement("code"); el.textContent = node.props.formula; return el; }, mathBlock(node) { + const mathml = toMathMl(node.props.formula, true); + if (mathml != null) { + return mathml; + } + + // fallbacks to element const el = doc.createElement("code"); el.textContent = node.props.formula; return el; diff --git a/packages/backend/src/migration/1000000000000-Init.ts b/packages/backend/src/migration/1000000000000-Init.ts index ae88514d18..5e83df6fdb 100644 --- a/packages/backend/src/migration/1000000000000-Init.ts +++ b/packages/backend/src/migration/1000000000000-Init.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class Init1000000000000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1556348509290-Pages.ts b/packages/backend/src/migration/1556348509290-Pages.ts index 66d00f7405..e8ab43e165 100644 --- a/packages/backend/src/migration/1556348509290-Pages.ts +++ b/packages/backend/src/migration/1556348509290-Pages.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class Pages1556348509290 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1556746559567-UserProfile.ts b/packages/backend/src/migration/1556746559567-UserProfile.ts index 015df00331..18e1878945 100644 --- a/packages/backend/src/migration/1556746559567-UserProfile.ts +++ b/packages/backend/src/migration/1556746559567-UserProfile.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class UserProfile1556746559567 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1557476068003-PinnedUsers.ts b/packages/backend/src/migration/1557476068003-PinnedUsers.ts index f7c279744d..5c51656abc 100644 --- a/packages/backend/src/migration/1557476068003-PinnedUsers.ts +++ b/packages/backend/src/migration/1557476068003-PinnedUsers.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class PinnedUsers1557476068003 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1557761316509-AddSomeUrls.ts b/packages/backend/src/migration/1557761316509-AddSomeUrls.ts index e0af30240f..9446b7c3ba 100644 --- a/packages/backend/src/migration/1557761316509-AddSomeUrls.ts +++ b/packages/backend/src/migration/1557761316509-AddSomeUrls.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class AddSomeUrls1557761316509 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1557932705754-ObjectStorageSetting.ts b/packages/backend/src/migration/1557932705754-ObjectStorageSetting.ts index cc8e36003b..66b313fa7a 100644 --- a/packages/backend/src/migration/1557932705754-ObjectStorageSetting.ts +++ b/packages/backend/src/migration/1557932705754-ObjectStorageSetting.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ObjectStorageSetting1557932705754 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1558072954435-PageLike.ts b/packages/backend/src/migration/1558072954435-PageLike.ts index 80c8da95b0..08b6d5e2d7 100644 --- a/packages/backend/src/migration/1558072954435-PageLike.ts +++ b/packages/backend/src/migration/1558072954435-PageLike.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class PageLike1558072954435 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1558103093633-UserGroup.ts b/packages/backend/src/migration/1558103093633-UserGroup.ts index 20e008b62c..ab386f3361 100644 --- a/packages/backend/src/migration/1558103093633-UserGroup.ts +++ b/packages/backend/src/migration/1558103093633-UserGroup.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class UserGroup1558103093633 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1558257926829-UserGroupInvite.ts b/packages/backend/src/migration/1558257926829-UserGroupInvite.ts index f65e8d17a3..d1c09c4833 100644 --- a/packages/backend/src/migration/1558257926829-UserGroupInvite.ts +++ b/packages/backend/src/migration/1558257926829-UserGroupInvite.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class UserGroupInvite1558257926829 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1558266512381-UserListJoining.ts b/packages/backend/src/migration/1558266512381-UserListJoining.ts index b531ba038a..d645f682e0 100644 --- a/packages/backend/src/migration/1558266512381-UserListJoining.ts +++ b/packages/backend/src/migration/1558266512381-UserListJoining.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class UserListJoining1558266512381 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1561706992953-webauthn.ts b/packages/backend/src/migration/1561706992953-webauthn.ts index 2fa6798237..d8d387c936 100644 --- a/packages/backend/src/migration/1561706992953-webauthn.ts +++ b/packages/backend/src/migration/1561706992953-webauthn.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class webauthn1561706992953 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1561873850023-ChartIndexes.ts b/packages/backend/src/migration/1561873850023-ChartIndexes.ts index ad907b84f9..72f752afab 100644 --- a/packages/backend/src/migration/1561873850023-ChartIndexes.ts +++ b/packages/backend/src/migration/1561873850023-ChartIndexes.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ChartIndexes1561873850023 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1562422242907-PasswordLessLogin.ts b/packages/backend/src/migration/1562422242907-PasswordLessLogin.ts index cf8d974b4a..6e08a4037a 100644 --- a/packages/backend/src/migration/1562422242907-PasswordLessLogin.ts +++ b/packages/backend/src/migration/1562422242907-PasswordLessLogin.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class PasswordLessLogin1562422242907 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1562444565093-PinnedPage.ts b/packages/backend/src/migration/1562444565093-PinnedPage.ts index eb953d05c7..be3d509698 100644 --- a/packages/backend/src/migration/1562444565093-PinnedPage.ts +++ b/packages/backend/src/migration/1562444565093-PinnedPage.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class PinnedPage1562444565093 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1562448332510-PageTitleHideOption.ts b/packages/backend/src/migration/1562448332510-PageTitleHideOption.ts index 5744b2578e..c5b9b2e221 100644 --- a/packages/backend/src/migration/1562448332510-PageTitleHideOption.ts +++ b/packages/backend/src/migration/1562448332510-PageTitleHideOption.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class PageTitleHideOption1562448332510 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1562869971568-ModerationLog.ts b/packages/backend/src/migration/1562869971568-ModerationLog.ts index 66e7bca25a..565cdc6f03 100644 --- a/packages/backend/src/migration/1562869971568-ModerationLog.ts +++ b/packages/backend/src/migration/1562869971568-ModerationLog.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ModerationLog1562869971568 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1563757595828-UsedUsername.ts b/packages/backend/src/migration/1563757595828-UsedUsername.ts index bb82b91a5d..d245c0a7c0 100644 --- a/packages/backend/src/migration/1563757595828-UsedUsername.ts +++ b/packages/backend/src/migration/1563757595828-UsedUsername.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class UsedUsername1563757595828 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1565634203341-room.ts b/packages/backend/src/migration/1565634203341-room.ts index e3023fcf31..f6f43f4fa6 100644 --- a/packages/backend/src/migration/1565634203341-room.ts +++ b/packages/backend/src/migration/1565634203341-room.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class room1565634203341 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1571220798684-CustomEmojiCategory.ts b/packages/backend/src/migration/1571220798684-CustomEmojiCategory.ts index c3d9ea8765..661c99c3c7 100644 --- a/packages/backend/src/migration/1571220798684-CustomEmojiCategory.ts +++ b/packages/backend/src/migration/1571220798684-CustomEmojiCategory.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class CustomEmojiCategory1571220798684 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1572760203493-nodeinfo.ts b/packages/backend/src/migration/1572760203493-nodeinfo.ts index e346a44779..2cc21d72c6 100644 --- a/packages/backend/src/migration/1572760203493-nodeinfo.ts +++ b/packages/backend/src/migration/1572760203493-nodeinfo.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class nodeinfo1572760203493 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1576269851876-TalkFederationId.ts b/packages/backend/src/migration/1576269851876-TalkFederationId.ts index 02671f78e3..b1d8691d17 100644 --- a/packages/backend/src/migration/1576269851876-TalkFederationId.ts +++ b/packages/backend/src/migration/1576269851876-TalkFederationId.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class TalkFederationId1576269851876 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1576869585998-ProxyRemoteFiles.ts b/packages/backend/src/migration/1576869585998-ProxyRemoteFiles.ts index e260da2195..4715dcb607 100644 --- a/packages/backend/src/migration/1576869585998-ProxyRemoteFiles.ts +++ b/packages/backend/src/migration/1576869585998-ProxyRemoteFiles.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ProxyRemoteFiles1576869585998 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1579267006611-v12.ts b/packages/backend/src/migration/1579267006611-v12.ts index 50cc491a6d..54c277df61 100644 --- a/packages/backend/src/migration/1579267006611-v12.ts +++ b/packages/backend/src/migration/1579267006611-v12.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v121579267006611 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1579270193251-v12-2.ts b/packages/backend/src/migration/1579270193251-v12-2.ts index d78a93828e..5e2e9e60b6 100644 --- a/packages/backend/src/migration/1579270193251-v12-2.ts +++ b/packages/backend/src/migration/1579270193251-v12-2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v1221579270193251 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1579282808087-v12-3.ts b/packages/backend/src/migration/1579282808087-v12-3.ts index 367fe78bcb..e8b0affe7d 100644 --- a/packages/backend/src/migration/1579282808087-v12-3.ts +++ b/packages/backend/src/migration/1579282808087-v12-3.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v1231579282808087 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1579544426412-v12-4.ts b/packages/backend/src/migration/1579544426412-v12-4.ts index c84eea3e93..c3aecb8f89 100644 --- a/packages/backend/src/migration/1579544426412-v12-4.ts +++ b/packages/backend/src/migration/1579544426412-v12-4.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v1241579544426412 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1579977526288-v12-5.ts b/packages/backend/src/migration/1579977526288-v12-5.ts index b619451d90..88d00cb696 100644 --- a/packages/backend/src/migration/1579977526288-v12-5.ts +++ b/packages/backend/src/migration/1579977526288-v12-5.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v1251579977526288 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1579993013959-v12-6.ts b/packages/backend/src/migration/1579993013959-v12-6.ts index af84e04651..63be82a4fd 100644 --- a/packages/backend/src/migration/1579993013959-v12-6.ts +++ b/packages/backend/src/migration/1579993013959-v12-6.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v1261579993013959 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1580069531114-v12-7.ts b/packages/backend/src/migration/1580069531114-v12-7.ts index e45ba5129a..7459dbaa78 100644 --- a/packages/backend/src/migration/1580069531114-v12-7.ts +++ b/packages/backend/src/migration/1580069531114-v12-7.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v1271580069531114 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1580148575182-v12-8.ts b/packages/backend/src/migration/1580148575182-v12-8.ts index 60e0487148..344f4fab4c 100644 --- a/packages/backend/src/migration/1580148575182-v12-8.ts +++ b/packages/backend/src/migration/1580148575182-v12-8.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v1281580148575182 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1580154400017-v12-9.ts b/packages/backend/src/migration/1580154400017-v12-9.ts index 1b4d390e5a..bfe0998a78 100644 --- a/packages/backend/src/migration/1580154400017-v12-9.ts +++ b/packages/backend/src/migration/1580154400017-v12-9.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v1291580154400017 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1580276619901-v12-10.ts b/packages/backend/src/migration/1580276619901-v12-10.ts index 80c48f45aa..03727a91e3 100644 --- a/packages/backend/src/migration/1580276619901-v12-10.ts +++ b/packages/backend/src/migration/1580276619901-v12-10.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v12101580276619901 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1580331224276-v12-11.ts b/packages/backend/src/migration/1580331224276-v12-11.ts index b83e020258..1c4989c1cf 100644 --- a/packages/backend/src/migration/1580331224276-v12-11.ts +++ b/packages/backend/src/migration/1580331224276-v12-11.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v12111580331224276 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1580508795118-v12-12.ts b/packages/backend/src/migration/1580508795118-v12-12.ts index 263889aa8c..7eed9efa14 100644 --- a/packages/backend/src/migration/1580508795118-v12-12.ts +++ b/packages/backend/src/migration/1580508795118-v12-12.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v12121580508795118 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1580543501339-v12-13.ts b/packages/backend/src/migration/1580543501339-v12-13.ts index a0e3e4f1ec..32b7ef8861 100644 --- a/packages/backend/src/migration/1580543501339-v12-13.ts +++ b/packages/backend/src/migration/1580543501339-v12-13.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v12131580543501339 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1580864313253-v12-14.ts b/packages/backend/src/migration/1580864313253-v12-14.ts index c8eefaefdf..b897dcaab3 100644 --- a/packages/backend/src/migration/1580864313253-v12-14.ts +++ b/packages/backend/src/migration/1580864313253-v12-14.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class v12141580864313253 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1581526429287-user-group-invitation.ts b/packages/backend/src/migration/1581526429287-user-group-invitation.ts index 811b10777e..0ba751b947 100644 --- a/packages/backend/src/migration/1581526429287-user-group-invitation.ts +++ b/packages/backend/src/migration/1581526429287-user-group-invitation.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userGroupInvitation1581526429287 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1581695816408-user-group-antenna.ts b/packages/backend/src/migration/1581695816408-user-group-antenna.ts index 2428e682c9..102a685ca7 100644 --- a/packages/backend/src/migration/1581695816408-user-group-antenna.ts +++ b/packages/backend/src/migration/1581695816408-user-group-antenna.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userGroupAntenna1581695816408 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1581708415836-drive-user-folder-id-index.ts b/packages/backend/src/migration/1581708415836-drive-user-folder-id-index.ts index 0d2b38905a..7650cef3ca 100644 --- a/packages/backend/src/migration/1581708415836-drive-user-folder-id-index.ts +++ b/packages/backend/src/migration/1581708415836-drive-user-folder-id-index.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class driveUserFolderIdIndex1581708415836 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1581979837262-promo.ts b/packages/backend/src/migration/1581979837262-promo.ts index c8dc2d1fed..4202ef6313 100644 --- a/packages/backend/src/migration/1581979837262-promo.ts +++ b/packages/backend/src/migration/1581979837262-promo.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class promo1581979837262 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1582019042083-featured-injecttion.ts b/packages/backend/src/migration/1582019042083-featured-injecttion.ts index 3890b84d71..d8cd22f049 100644 --- a/packages/backend/src/migration/1582019042083-featured-injecttion.ts +++ b/packages/backend/src/migration/1582019042083-featured-injecttion.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class featuredInjecttion1582019042083 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1582210532752-antenna-exclude.ts b/packages/backend/src/migration/1582210532752-antenna-exclude.ts index f78a8124cd..477401dd20 100644 --- a/packages/backend/src/migration/1582210532752-antenna-exclude.ts +++ b/packages/backend/src/migration/1582210532752-antenna-exclude.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class antennaExclude1582210532752 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1582875306439-note-reaction-length.ts b/packages/backend/src/migration/1582875306439-note-reaction-length.ts index e52a1b1ac3..fb9fa4e647 100644 --- a/packages/backend/src/migration/1582875306439-note-reaction-length.ts +++ b/packages/backend/src/migration/1582875306439-note-reaction-length.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class noteReactionLength1582875306439 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1585361548360-miauth.ts b/packages/backend/src/migration/1585361548360-miauth.ts index 5283ebbafc..eeac69eea4 100644 --- a/packages/backend/src/migration/1585361548360-miauth.ts +++ b/packages/backend/src/migration/1585361548360-miauth.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class miauth1585361548360 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1585385921215-custom-notification.ts b/packages/backend/src/migration/1585385921215-custom-notification.ts index 0016065fab..0b7bce7d77 100644 --- a/packages/backend/src/migration/1585385921215-custom-notification.ts +++ b/packages/backend/src/migration/1585385921215-custom-notification.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class customNotification1585385921215 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1585772678853-ap-url.ts b/packages/backend/src/migration/1585772678853-ap-url.ts index f985a60292..c1a6225d6b 100644 --- a/packages/backend/src/migration/1585772678853-ap-url.ts +++ b/packages/backend/src/migration/1585772678853-ap-url.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class apUrl1585772678853 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1586624197029-AddObjectStorageUseProxy.ts b/packages/backend/src/migration/1586624197029-AddObjectStorageUseProxy.ts index e6c29ecac6..42e207ac92 100644 --- a/packages/backend/src/migration/1586624197029-AddObjectStorageUseProxy.ts +++ b/packages/backend/src/migration/1586624197029-AddObjectStorageUseProxy.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class AddObjectStorageUseProxy1586624197029 implements MigrationInterface diff --git a/packages/backend/src/migration/1586641139527-remote-reaction.ts b/packages/backend/src/migration/1586641139527-remote-reaction.ts index f66245efca..5839695476 100644 --- a/packages/backend/src/migration/1586641139527-remote-reaction.ts +++ b/packages/backend/src/migration/1586641139527-remote-reaction.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class remoteReaction1586641139527 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1586708940386-pageAiScript.ts b/packages/backend/src/migration/1586708940386-pageAiScript.ts index 4849525f4e..c405432557 100644 --- a/packages/backend/src/migration/1586708940386-pageAiScript.ts +++ b/packages/backend/src/migration/1586708940386-pageAiScript.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class pageAiScript1586708940386 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1588044505511-hCaptcha.ts b/packages/backend/src/migration/1588044505511-hCaptcha.ts index b3008b8628..1a311a086e 100644 --- a/packages/backend/src/migration/1588044505511-hCaptcha.ts +++ b/packages/backend/src/migration/1588044505511-hCaptcha.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class hCaptcha1588044505511 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1589023282116-pubRelay.ts b/packages/backend/src/migration/1589023282116-pubRelay.ts index fb684f90e1..86a50dbb2d 100644 --- a/packages/backend/src/migration/1589023282116-pubRelay.ts +++ b/packages/backend/src/migration/1589023282116-pubRelay.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class pubRelay1589023282116 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1595075960584-blurhash.ts b/packages/backend/src/migration/1595075960584-blurhash.ts index d8dfaf5c9d..f87af04028 100644 --- a/packages/backend/src/migration/1595075960584-blurhash.ts +++ b/packages/backend/src/migration/1595075960584-blurhash.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class blurhash1595075960584 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1595077605646-blurhash-for-avatar-banner.ts b/packages/backend/src/migration/1595077605646-blurhash-for-avatar-banner.ts index 7454b5bfb3..2f7791ce1b 100644 --- a/packages/backend/src/migration/1595077605646-blurhash-for-avatar-banner.ts +++ b/packages/backend/src/migration/1595077605646-blurhash-for-avatar-banner.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class blurhashForAvatarBanner1595077605646 implements MigrationInterface diff --git a/packages/backend/src/migration/1595676934834-instance-icon-url.ts b/packages/backend/src/migration/1595676934834-instance-icon-url.ts index 30f6a940cd..c3289939f7 100644 --- a/packages/backend/src/migration/1595676934834-instance-icon-url.ts +++ b/packages/backend/src/migration/1595676934834-instance-icon-url.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class instanceIconUrl1595676934834 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1595771249699-word-mute.ts b/packages/backend/src/migration/1595771249699-word-mute.ts index ed08678947..8a809e6cab 100644 --- a/packages/backend/src/migration/1595771249699-word-mute.ts +++ b/packages/backend/src/migration/1595771249699-word-mute.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class wordMute1595771249699 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1595782306083-word-mute2.ts b/packages/backend/src/migration/1595782306083-word-mute2.ts index 1e7063caef..75b3684ab5 100644 --- a/packages/backend/src/migration/1595782306083-word-mute2.ts +++ b/packages/backend/src/migration/1595782306083-word-mute2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class wordMute21595782306083 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1596548170836-channel.ts b/packages/backend/src/migration/1596548170836-channel.ts index 02ecf958a3..50e07d5687 100644 --- a/packages/backend/src/migration/1596548170836-channel.ts +++ b/packages/backend/src/migration/1596548170836-channel.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class channel1596548170836 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1596786425167-channel2.ts b/packages/backend/src/migration/1596786425167-channel2.ts index d825f9cae5..a76bcbd00c 100644 --- a/packages/backend/src/migration/1596786425167-channel2.ts +++ b/packages/backend/src/migration/1596786425167-channel2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class channel21596786425167 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1597230137744-objectStorageSetPublicRead.ts b/packages/backend/src/migration/1597230137744-objectStorageSetPublicRead.ts index f5faacb53e..a8f32af3bd 100644 --- a/packages/backend/src/migration/1597230137744-objectStorageSetPublicRead.ts +++ b/packages/backend/src/migration/1597230137744-objectStorageSetPublicRead.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class objectStorageSetPublicRead1597230137744 implements MigrationInterface diff --git a/packages/backend/src/migration/1597236229720-IncludingNotificationTypes.ts b/packages/backend/src/migration/1597236229720-IncludingNotificationTypes.ts index 679fc0ff9a..718b3fda4a 100644 --- a/packages/backend/src/migration/1597236229720-IncludingNotificationTypes.ts +++ b/packages/backend/src/migration/1597236229720-IncludingNotificationTypes.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class IncludingNotificationTypes1597236229720 implements MigrationInterface diff --git a/packages/backend/src/migration/1597385880794-add-sensitive-index.ts b/packages/backend/src/migration/1597385880794-add-sensitive-index.ts index 432e7e9fe8..8f8018626f 100644 --- a/packages/backend/src/migration/1597385880794-add-sensitive-index.ts +++ b/packages/backend/src/migration/1597385880794-add-sensitive-index.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class addSensitiveIndex1597385880794 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1597459042300-channel-unread.ts b/packages/backend/src/migration/1597459042300-channel-unread.ts index 4216323a90..0619416dc4 100644 --- a/packages/backend/src/migration/1597459042300-channel-unread.ts +++ b/packages/backend/src/migration/1597459042300-channel-unread.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class channelUnread1597459042300 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1597893996136-ChannelNoteIdDescIndex.ts b/packages/backend/src/migration/1597893996136-ChannelNoteIdDescIndex.ts index 981514347a..83df98bf0f 100644 --- a/packages/backend/src/migration/1597893996136-ChannelNoteIdDescIndex.ts +++ b/packages/backend/src/migration/1597893996136-ChannelNoteIdDescIndex.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ChannelNoteIdDescIndex1597893996136 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1600353287890-mutingNotificationTypes.ts b/packages/backend/src/migration/1600353287890-mutingNotificationTypes.ts index ae47d53a4c..06792b9b3d 100644 --- a/packages/backend/src/migration/1600353287890-mutingNotificationTypes.ts +++ b/packages/backend/src/migration/1600353287890-mutingNotificationTypes.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class mutingNotificationTypes1600353287890 implements MigrationInterface diff --git a/packages/backend/src/migration/1603094348345-refine-abuse-user-report.ts b/packages/backend/src/migration/1603094348345-refine-abuse-user-report.ts index 0ed047783b..15416d2a6b 100644 --- a/packages/backend/src/migration/1603094348345-refine-abuse-user-report.ts +++ b/packages/backend/src/migration/1603094348345-refine-abuse-user-report.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class refineAbuseUserReport1603094348345 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1603095701770-refine-abuse-user-report2.ts b/packages/backend/src/migration/1603095701770-refine-abuse-user-report2.ts index e87685c465..63f1348fd6 100644 --- a/packages/backend/src/migration/1603095701770-refine-abuse-user-report2.ts +++ b/packages/backend/src/migration/1603095701770-refine-abuse-user-report2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class refineAbuseUserReport21603095701770 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1603776877564-instance-theme-color.ts b/packages/backend/src/migration/1603776877564-instance-theme-color.ts index 6bde772fe6..416b7235e3 100644 --- a/packages/backend/src/migration/1603776877564-instance-theme-color.ts +++ b/packages/backend/src/migration/1603776877564-instance-theme-color.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class instanceThemeColor1603776877564 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1603781553011-instance-favicon.ts b/packages/backend/src/migration/1603781553011-instance-favicon.ts index 1753f6449a..c6a0999795 100644 --- a/packages/backend/src/migration/1603781553011-instance-favicon.ts +++ b/packages/backend/src/migration/1603781553011-instance-favicon.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class instanceFavicon1603781553011 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1604821689616-delete-auto-watch.ts b/packages/backend/src/migration/1604821689616-delete-auto-watch.ts index 514087721b..fc2a1c06a9 100644 --- a/packages/backend/src/migration/1604821689616-delete-auto-watch.ts +++ b/packages/backend/src/migration/1604821689616-delete-auto-watch.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class deleteAutoWatch1604821689616 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1605408848373-clip-description.ts b/packages/backend/src/migration/1605408848373-clip-description.ts index 7cd98d8f8a..8cc23cfde4 100644 --- a/packages/backend/src/migration/1605408848373-clip-description.ts +++ b/packages/backend/src/migration/1605408848373-clip-description.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class clipDescription1605408848373 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1605408971051-comments.ts b/packages/backend/src/migration/1605408971051-comments.ts index b846d0526c..2513ad520f 100644 --- a/packages/backend/src/migration/1605408971051-comments.ts +++ b/packages/backend/src/migration/1605408971051-comments.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class comments1605408971051 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1605585339718-instance-pinned-pages.ts b/packages/backend/src/migration/1605585339718-instance-pinned-pages.ts index 480839fce9..153b6d74c2 100644 --- a/packages/backend/src/migration/1605585339718-instance-pinned-pages.ts +++ b/packages/backend/src/migration/1605585339718-instance-pinned-pages.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class instancePinnedPages1605585339718 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1605965516823-instance-images.ts b/packages/backend/src/migration/1605965516823-instance-images.ts index 2f024a5d38..c7002276c6 100644 --- a/packages/backend/src/migration/1605965516823-instance-images.ts +++ b/packages/backend/src/migration/1605965516823-instance-images.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class instanceImages1605965516823 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1606191203881-no-crawle.ts b/packages/backend/src/migration/1606191203881-no-crawle.ts index 7ca2ff30ba..fca0faa336 100644 --- a/packages/backend/src/migration/1606191203881-no-crawle.ts +++ b/packages/backend/src/migration/1606191203881-no-crawle.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class noCrawle1606191203881 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1607151207216-instance-pinned-clip.ts b/packages/backend/src/migration/1607151207216-instance-pinned-clip.ts index 1d77c69563..72cb416798 100644 --- a/packages/backend/src/migration/1607151207216-instance-pinned-clip.ts +++ b/packages/backend/src/migration/1607151207216-instance-pinned-clip.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class instancePinnedClip1607151207216 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1607353487793-isExplorable.ts b/packages/backend/src/migration/1607353487793-isExplorable.ts index 3518ab769c..732bc1c6dd 100644 --- a/packages/backend/src/migration/1607353487793-isExplorable.ts +++ b/packages/backend/src/migration/1607353487793-isExplorable.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class isExplorable1607353487793 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1610277136869-registry.ts b/packages/backend/src/migration/1610277136869-registry.ts index dea40bce5b..5c080df719 100644 --- a/packages/backend/src/migration/1610277136869-registry.ts +++ b/packages/backend/src/migration/1610277136869-registry.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class registry1610277136869 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1610277585759-registry2.ts b/packages/backend/src/migration/1610277585759-registry2.ts index 98287e6b68..5ef2970f0b 100644 --- a/packages/backend/src/migration/1610277585759-registry2.ts +++ b/packages/backend/src/migration/1610277585759-registry2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class registry21610277585759 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1610283021566-registry3.ts b/packages/backend/src/migration/1610283021566-registry3.ts index 11d094c2a8..e1e6bfb752 100644 --- a/packages/backend/src/migration/1610283021566-registry3.ts +++ b/packages/backend/src/migration/1610283021566-registry3.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class registry31610283021566 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1611354329133-followersUri.ts b/packages/backend/src/migration/1611354329133-followersUri.ts index e67c14c290..7b243658ce 100644 --- a/packages/backend/src/migration/1611354329133-followersUri.ts +++ b/packages/backend/src/migration/1611354329133-followersUri.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class followersUri1611354329133 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1611397665007-gallery.ts b/packages/backend/src/migration/1611397665007-gallery.ts index 3f80989ca1..b7a24a8393 100644 --- a/packages/backend/src/migration/1611397665007-gallery.ts +++ b/packages/backend/src/migration/1611397665007-gallery.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class gallery1611397665007 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1611547387175-objectStorageS3ForcePathStyle.ts b/packages/backend/src/migration/1611547387175-objectStorageS3ForcePathStyle.ts index d28b00b3c9..74f84b96af 100644 --- a/packages/backend/src/migration/1611547387175-objectStorageS3ForcePathStyle.ts +++ b/packages/backend/src/migration/1611547387175-objectStorageS3ForcePathStyle.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class objectStorageS3ForcePathStyle1611547387175 implements MigrationInterface diff --git a/packages/backend/src/migration/1612619156584-announcement-email.ts b/packages/backend/src/migration/1612619156584-announcement-email.ts index 7788d2ae50..b93238019e 100644 --- a/packages/backend/src/migration/1612619156584-announcement-email.ts +++ b/packages/backend/src/migration/1612619156584-announcement-email.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class announcementEmail1612619156584 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1613155914446-emailNotificationTypes.ts b/packages/backend/src/migration/1613155914446-emailNotificationTypes.ts index 228c3024a8..f2f9780469 100644 --- a/packages/backend/src/migration/1613155914446-emailNotificationTypes.ts +++ b/packages/backend/src/migration/1613155914446-emailNotificationTypes.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class emailNotificationTypes1613155914446 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1613181457597-user-lang.ts b/packages/backend/src/migration/1613181457597-user-lang.ts index 424fc20e94..bf4a91098e 100644 --- a/packages/backend/src/migration/1613181457597-user-lang.ts +++ b/packages/backend/src/migration/1613181457597-user-lang.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userLang1613181457597 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1613503367223-use-bigint-for-driveUsage.ts b/packages/backend/src/migration/1613503367223-use-bigint-for-driveUsage.ts index 7d7f29de65..082f3ed13c 100644 --- a/packages/backend/src/migration/1613503367223-use-bigint-for-driveUsage.ts +++ b/packages/backend/src/migration/1613503367223-use-bigint-for-driveUsage.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class useBigintForDriveUsage1613503367223 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1615965918224-chart-v2.ts b/packages/backend/src/migration/1615965918224-chart-v2.ts index 4b41f399b7..755a7fa57d 100644 --- a/packages/backend/src/migration/1615965918224-chart-v2.ts +++ b/packages/backend/src/migration/1615965918224-chart-v2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV21615965918224 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1615966519402-chart-v2-2.ts b/packages/backend/src/migration/1615966519402-chart-v2-2.ts index 12fb427b1b..f71cb83f7f 100644 --- a/packages/backend/src/migration/1615966519402-chart-v2-2.ts +++ b/packages/backend/src/migration/1615966519402-chart-v2-2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV221615966519402 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1618637372000-user-last-active-date.ts b/packages/backend/src/migration/1618637372000-user-last-active-date.ts index df75243246..b163001aeb 100644 --- a/packages/backend/src/migration/1618637372000-user-last-active-date.ts +++ b/packages/backend/src/migration/1618637372000-user-last-active-date.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userLastActiveDate1618637372000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1618639857000-user-hide-online-status.ts b/packages/backend/src/migration/1618639857000-user-hide-online-status.ts index 523b602ffc..3f97fb2e9b 100644 --- a/packages/backend/src/migration/1618639857000-user-hide-online-status.ts +++ b/packages/backend/src/migration/1618639857000-user-hide-online-status.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userHideOnlineStatus1618639857000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1619942102890-password-reset.ts b/packages/backend/src/migration/1619942102890-password-reset.ts index d456dafdd7..76bc16db16 100644 --- a/packages/backend/src/migration/1619942102890-password-reset.ts +++ b/packages/backend/src/migration/1619942102890-password-reset.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class passwordReset1619942102890 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1620019354680-ad.ts b/packages/backend/src/migration/1620019354680-ad.ts index 5b7eed9fa3..5aa3196f64 100644 --- a/packages/backend/src/migration/1620019354680-ad.ts +++ b/packages/backend/src/migration/1620019354680-ad.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ad1620019354680 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1620364649428-ad2.ts b/packages/backend/src/migration/1620364649428-ad2.ts index 321dd36610..615ae2480f 100644 --- a/packages/backend/src/migration/1620364649428-ad2.ts +++ b/packages/backend/src/migration/1620364649428-ad2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ad21620364649428 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1621479946000-add-note-indexes.ts b/packages/backend/src/migration/1621479946000-add-note-indexes.ts index ceb34f0838..e5f527a138 100644 --- a/packages/backend/src/migration/1621479946000-add-note-indexes.ts +++ b/packages/backend/src/migration/1621479946000-add-note-indexes.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class addNoteIndexes1621479946000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1622679304522-user-profile-description-length.ts b/packages/backend/src/migration/1622679304522-user-profile-description-length.ts index 5552ac169f..59f56198d4 100644 --- a/packages/backend/src/migration/1622679304522-user-profile-description-length.ts +++ b/packages/backend/src/migration/1622679304522-user-profile-description-length.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userProfileDescriptionLength1622679304522 implements MigrationInterface diff --git a/packages/backend/src/migration/1622681548499-log-message-length.ts b/packages/backend/src/migration/1622681548499-log-message-length.ts index f2c88cef5e..fb28a8065e 100644 --- a/packages/backend/src/migration/1622681548499-log-message-length.ts +++ b/packages/backend/src/migration/1622681548499-log-message-length.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class logMessageLength1622681548499 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1626509500668-fix-remote-file-proxy.ts b/packages/backend/src/migration/1626509500668-fix-remote-file-proxy.ts index 2fea0a8436..b616259798 100644 --- a/packages/backend/src/migration/1626509500668-fix-remote-file-proxy.ts +++ b/packages/backend/src/migration/1626509500668-fix-remote-file-proxy.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class fixRemoteFileProxy1626509500668 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1626733991004-allowlist-secure-mode.ts b/packages/backend/src/migration/1626733991004-allowlist-secure-mode.ts index 3282d7d989..113501b535 100644 --- a/packages/backend/src/migration/1626733991004-allowlist-secure-mode.ts +++ b/packages/backend/src/migration/1626733991004-allowlist-secure-mode.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class allowlistSecureMode1626733991004 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1629004542760-chart-reindex.ts b/packages/backend/src/migration/1629004542760-chart-reindex.ts index 503f0b2b11..4a2123cf90 100644 --- a/packages/backend/src/migration/1629004542760-chart-reindex.ts +++ b/packages/backend/src/migration/1629004542760-chart-reindex.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartReindex1629004542760 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1629024377804-deepl-integration.ts b/packages/backend/src/migration/1629024377804-deepl-integration.ts index 5d8ec48e57..10576f6ee2 100644 --- a/packages/backend/src/migration/1629024377804-deepl-integration.ts +++ b/packages/backend/src/migration/1629024377804-deepl-integration.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class deeplIntegration1629024377804 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1629288472000-fix-channel-userId.ts b/packages/backend/src/migration/1629288472000-fix-channel-userId.ts index e75ec7cf5a..59298060d8 100644 --- a/packages/backend/src/migration/1629288472000-fix-channel-userId.ts +++ b/packages/backend/src/migration/1629288472000-fix-channel-userId.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class fixChannelUserId1629288472000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1629512953000-user-is-deleted.ts b/packages/backend/src/migration/1629512953000-user-is-deleted.ts index 82b4dcfd4c..43d203cf15 100644 --- a/packages/backend/src/migration/1629512953000-user-is-deleted.ts +++ b/packages/backend/src/migration/1629512953000-user-is-deleted.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class isUserDeleted1629512953000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1629778475000-deepl-integration2.ts b/packages/backend/src/migration/1629778475000-deepl-integration2.ts index 5457685538..e4f59911f0 100644 --- a/packages/backend/src/migration/1629778475000-deepl-integration2.ts +++ b/packages/backend/src/migration/1629778475000-deepl-integration2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class deeplIntegration21629778475000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1629833361000-AddShowTLReplies.ts b/packages/backend/src/migration/1629833361000-AddShowTLReplies.ts index cd321ec1db..ed5a1e74f1 100644 --- a/packages/backend/src/migration/1629833361000-AddShowTLReplies.ts +++ b/packages/backend/src/migration/1629833361000-AddShowTLReplies.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class addShowTLReplies1629833361000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1629968054000_userInstanceBlocks.ts b/packages/backend/src/migration/1629968054000_userInstanceBlocks.ts index 3b8703f7b4..da3f2535be 100644 --- a/packages/backend/src/migration/1629968054000_userInstanceBlocks.ts +++ b/packages/backend/src/migration/1629968054000_userInstanceBlocks.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userInstanceBlocks1629968054000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1633068642000-email-required-for-signup.ts b/packages/backend/src/migration/1633068642000-email-required-for-signup.ts index 6fcfca58db..31e23909c5 100644 --- a/packages/backend/src/migration/1633068642000-email-required-for-signup.ts +++ b/packages/backend/src/migration/1633068642000-email-required-for-signup.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class emailRequiredForSignup1633068642000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1633071909016-user-pending.ts b/packages/backend/src/migration/1633071909016-user-pending.ts index cd6ad492cc..524006c462 100644 --- a/packages/backend/src/migration/1633071909016-user-pending.ts +++ b/packages/backend/src/migration/1633071909016-user-pending.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userPending1633071909016 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1634486652000-user-public-reactions.ts b/packages/backend/src/migration/1634486652000-user-public-reactions.ts index 73695334d7..4d9a44e0a8 100644 --- a/packages/backend/src/migration/1634486652000-user-public-reactions.ts +++ b/packages/backend/src/migration/1634486652000-user-public-reactions.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userPublicReactions1634486652000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1634902659689-delete-log.ts b/packages/backend/src/migration/1634902659689-delete-log.ts index 859a17c569..d982a76c54 100644 --- a/packages/backend/src/migration/1634902659689-delete-log.ts +++ b/packages/backend/src/migration/1634902659689-delete-log.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class deleteLog1634902659689 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1635500777168-note-thread-mute.ts b/packages/backend/src/migration/1635500777168-note-thread-mute.ts index 6d55632cb4..1e9d33570e 100644 --- a/packages/backend/src/migration/1635500777168-note-thread-mute.ts +++ b/packages/backend/src/migration/1635500777168-note-thread-mute.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class noteThreadMute1635500777168 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1636197624383-ff-visibility.ts b/packages/backend/src/migration/1636197624383-ff-visibility.ts index 09a323d1f1..80016ad4d0 100644 --- a/packages/backend/src/migration/1636197624383-ff-visibility.ts +++ b/packages/backend/src/migration/1636197624383-ff-visibility.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ffVisibility1636197624383 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1636697408073-remove-via-mobile.ts b/packages/backend/src/migration/1636697408073-remove-via-mobile.ts index a02143c4e9..89d76998d9 100644 --- a/packages/backend/src/migration/1636697408073-remove-via-mobile.ts +++ b/packages/backend/src/migration/1636697408073-remove-via-mobile.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class removeViaMobile1636697408073 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1637320813000-forwarded-report.ts b/packages/backend/src/migration/1637320813000-forwarded-report.ts index 7acd9ed0a6..fa71a96d82 100644 --- a/packages/backend/src/migration/1637320813000-forwarded-report.ts +++ b/packages/backend/src/migration/1637320813000-forwarded-report.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class forwardedReport1637320813000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1639325650583-chart-v3.ts b/packages/backend/src/migration/1639325650583-chart-v3.ts index 04267abc55..1fd58916e9 100644 --- a/packages/backend/src/migration/1639325650583-chart-v3.ts +++ b/packages/backend/src/migration/1639325650583-chart-v3.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV31639325650583 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1642611822809-emoji-url.ts b/packages/backend/src/migration/1642611822809-emoji-url.ts index 97b88e0866..fa961fb3d9 100644 --- a/packages/backend/src/migration/1642611822809-emoji-url.ts +++ b/packages/backend/src/migration/1642611822809-emoji-url.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class emojiUrl1642611822809 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1642613870898-drive-file-webpublic-type.ts b/packages/backend/src/migration/1642613870898-drive-file-webpublic-type.ts index 97457f6ad3..c55eca8ff1 100644 --- a/packages/backend/src/migration/1642613870898-drive-file-webpublic-type.ts +++ b/packages/backend/src/migration/1642613870898-drive-file-webpublic-type.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class driveFileWebpublicType1642613870898 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1643963705770-chart-v4.ts b/packages/backend/src/migration/1643963705770-chart-v4.ts index 081be2e9ce..402da2fab4 100644 --- a/packages/backend/src/migration/1643963705770-chart-v4.ts +++ b/packages/backend/src/migration/1643963705770-chart-v4.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV41643963705770 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1643966656277-chart-v5.ts b/packages/backend/src/migration/1643966656277-chart-v5.ts index c4ef29408e..d9f8f265ed 100644 --- a/packages/backend/src/migration/1643966656277-chart-v5.ts +++ b/packages/backend/src/migration/1643966656277-chart-v5.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV51643966656277 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1643967331284-chart-v6.ts b/packages/backend/src/migration/1643967331284-chart-v6.ts index b82cc31f48..6fcba78a72 100644 --- a/packages/backend/src/migration/1643967331284-chart-v6.ts +++ b/packages/backend/src/migration/1643967331284-chart-v6.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV61643967331284 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644010796173-convert-hard-mutes.ts b/packages/backend/src/migration/1644010796173-convert-hard-mutes.ts index 7579427d26..ccadea6332 100644 --- a/packages/backend/src/migration/1644010796173-convert-hard-mutes.ts +++ b/packages/backend/src/migration/1644010796173-convert-hard-mutes.ts @@ -1,6 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -import RE2 from "re2"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class convertHardMutes1644010796173 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { @@ -15,7 +13,7 @@ export class convertHardMutes1644010796173 implements MigrationInterface { if (regexp) { // convert regexp's try { - new RE2(regexp[1], regexp[2]); + new RegExp(regexp[1], regexp[2]); return `/${regexp[1]}/${regexp[2]}`; } catch (err) { // invalid regex, ignore it diff --git a/packages/backend/src/migration/1644058404077-chart-v7.ts b/packages/backend/src/migration/1644058404077-chart-v7.ts index 7441b002a9..4c2b89f372 100644 --- a/packages/backend/src/migration/1644058404077-chart-v7.ts +++ b/packages/backend/src/migration/1644058404077-chart-v7.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV71644058404077 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644059847460-chart-v8.ts b/packages/backend/src/migration/1644059847460-chart-v8.ts index fef309bcbe..e5cf03dd30 100644 --- a/packages/backend/src/migration/1644059847460-chart-v8.ts +++ b/packages/backend/src/migration/1644059847460-chart-v8.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV81644059847460 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644060125705-chart-v9.ts b/packages/backend/src/migration/1644060125705-chart-v9.ts index c55282ed32..f4b76c2692 100644 --- a/packages/backend/src/migration/1644060125705-chart-v9.ts +++ b/packages/backend/src/migration/1644060125705-chart-v9.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV91644060125705 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644073149413-chart-v10.ts b/packages/backend/src/migration/1644073149413-chart-v10.ts index 7bcf105b99..4b5bea3676 100644 --- a/packages/backend/src/migration/1644073149413-chart-v10.ts +++ b/packages/backend/src/migration/1644073149413-chart-v10.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV101644073149413 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644095659741-chart-v11.ts b/packages/backend/src/migration/1644095659741-chart-v11.ts index d5e7fb5f87..89a9836cdc 100644 --- a/packages/backend/src/migration/1644095659741-chart-v11.ts +++ b/packages/backend/src/migration/1644095659741-chart-v11.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV111644095659741 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644328606241-chart-v12.ts b/packages/backend/src/migration/1644328606241-chart-v12.ts index b2a3378bbd..f9fea782d1 100644 --- a/packages/backend/src/migration/1644328606241-chart-v12.ts +++ b/packages/backend/src/migration/1644328606241-chart-v12.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV121644328606241 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644331238153-chart-v13.ts b/packages/backend/src/migration/1644331238153-chart-v13.ts index 6a5aa75ad7..1e962a0109 100644 --- a/packages/backend/src/migration/1644331238153-chart-v13.ts +++ b/packages/backend/src/migration/1644331238153-chart-v13.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV131644331238153 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644344266289-chart-v14.ts b/packages/backend/src/migration/1644344266289-chart-v14.ts index bbbd8e3096..0d15d5c242 100644 --- a/packages/backend/src/migration/1644344266289-chart-v14.ts +++ b/packages/backend/src/migration/1644344266289-chart-v14.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV141644344266289 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644395759931-instance-theme-color.ts b/packages/backend/src/migration/1644395759931-instance-theme-color.ts index e0391fbde2..746c4ff10b 100644 --- a/packages/backend/src/migration/1644395759931-instance-theme-color.ts +++ b/packages/backend/src/migration/1644395759931-instance-theme-color.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class instanceThemeColor1644395759931 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644481657998-chart-v15.ts b/packages/backend/src/migration/1644481657998-chart-v15.ts index 54572997a3..855e5a554c 100644 --- a/packages/backend/src/migration/1644481657998-chart-v15.ts +++ b/packages/backend/src/migration/1644481657998-chart-v15.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartV151644481657998 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1644551208096-following-indexes.ts b/packages/backend/src/migration/1644551208096-following-indexes.ts index 5838124844..94f1527c85 100644 --- a/packages/backend/src/migration/1644551208096-following-indexes.ts +++ b/packages/backend/src/migration/1644551208096-following-indexes.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class followingIndexes1644551208096 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1645340161439-remove-max-note-text-length.ts b/packages/backend/src/migration/1645340161439-remove-max-note-text-length.ts index ac673ea936..ee9eb1641c 100644 --- a/packages/backend/src/migration/1645340161439-remove-max-note-text-length.ts +++ b/packages/backend/src/migration/1645340161439-remove-max-note-text-length.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class removeMaxNoteTextLength1645340161439 implements MigrationInterface diff --git a/packages/backend/src/migration/1645599900873-federation-chart-pubsub.ts b/packages/backend/src/migration/1645599900873-federation-chart-pubsub.ts index 6f80b79a22..6c92aa7e38 100644 --- a/packages/backend/src/migration/1645599900873-federation-chart-pubsub.ts +++ b/packages/backend/src/migration/1645599900873-federation-chart-pubsub.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class federationChartPubsub1645599900873 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1646143552768-instance-default-theme.ts b/packages/backend/src/migration/1646143552768-instance-default-theme.ts index a22bdc2792..2b6765a234 100644 --- a/packages/backend/src/migration/1646143552768-instance-default-theme.ts +++ b/packages/backend/src/migration/1646143552768-instance-default-theme.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class instanceDefaultTheme1646143552768 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1646387162108-mute-expires-at.ts b/packages/backend/src/migration/1646387162108-mute-expires-at.ts index 2a15d20405..5b36b28483 100644 --- a/packages/backend/src/migration/1646387162108-mute-expires-at.ts +++ b/packages/backend/src/migration/1646387162108-mute-expires-at.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class muteExpiresAt1646387162108 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1646549089451-poll-ended-notification.ts b/packages/backend/src/migration/1646549089451-poll-ended-notification.ts index 651b0a4b92..32db541aff 100644 --- a/packages/backend/src/migration/1646549089451-poll-ended-notification.ts +++ b/packages/backend/src/migration/1646549089451-poll-ended-notification.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class pollEndedNotification1646549089451 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1646633030285-chart-federation-active.ts b/packages/backend/src/migration/1646633030285-chart-federation-active.ts index 92b1358a1f..c36e478c39 100644 --- a/packages/backend/src/migration/1646633030285-chart-federation-active.ts +++ b/packages/backend/src/migration/1646633030285-chart-federation-active.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartFederationActive1646633030285 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1646655454495-remove-instance-drive-columns.ts b/packages/backend/src/migration/1646655454495-remove-instance-drive-columns.ts index ca969b34da..f312d3ba18 100644 --- a/packages/backend/src/migration/1646655454495-remove-instance-drive-columns.ts +++ b/packages/backend/src/migration/1646655454495-remove-instance-drive-columns.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class removeInstanceDriveColumns1646655454495 implements MigrationInterface diff --git a/packages/backend/src/migration/1646732390560-chart-federation-active-sub-pub.ts b/packages/backend/src/migration/1646732390560-chart-federation-active-sub-pub.ts index 18d01f5f94..824b662eee 100644 --- a/packages/backend/src/migration/1646732390560-chart-federation-active-sub-pub.ts +++ b/packages/backend/src/migration/1646732390560-chart-federation-active-sub-pub.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class chartFederationActiveSubPub1646732390560 implements MigrationInterface diff --git a/packages/backend/src/migration/1648548247382-webhook.ts b/packages/backend/src/migration/1648548247382-webhook.ts index 409ddc6bcd..04d133ac3e 100644 --- a/packages/backend/src/migration/1648548247382-webhook.ts +++ b/packages/backend/src/migration/1648548247382-webhook.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class webhook1648548247382 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1648816172177-webhook-2.ts b/packages/backend/src/migration/1648816172177-webhook-2.ts index c313a57bc2..8be10efed8 100644 --- a/packages/backend/src/migration/1648816172177-webhook-2.ts +++ b/packages/backend/src/migration/1648816172177-webhook-2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class webhook21648816172177 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1651224615271-foreign-key.ts b/packages/backend/src/migration/1651224615271-foreign-key.ts index c93ff28a26..707deaa276 100644 --- a/packages/backend/src/migration/1651224615271-foreign-key.ts +++ b/packages/backend/src/migration/1651224615271-foreign-key.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class foreignKeyReports1651224615271 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1652859567549-uniform-themecolor.ts b/packages/backend/src/migration/1652859567549-uniform-themecolor.ts index 0943d6218d..3d15b6ed51 100644 --- a/packages/backend/src/migration/1652859567549-uniform-themecolor.ts +++ b/packages/backend/src/migration/1652859567549-uniform-themecolor.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; import tinycolor from "tinycolor2"; diff --git a/packages/backend/src/migration/1655368940105-nsfw-detection.ts b/packages/backend/src/migration/1655368940105-nsfw-detection.ts index ed5af1bfaa..fcfa9a7f5f 100644 --- a/packages/backend/src/migration/1655368940105-nsfw-detection.ts +++ b/packages/backend/src/migration/1655368940105-nsfw-detection.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class nsfwDetection1655368940105 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1655371960534-nsfw-detection-2.ts b/packages/backend/src/migration/1655371960534-nsfw-detection-2.ts index 4f0362449b..b813195ab6 100644 --- a/packages/backend/src/migration/1655371960534-nsfw-detection-2.ts +++ b/packages/backend/src/migration/1655371960534-nsfw-detection-2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class nsfwDetection21655371960534 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1655388169582-nsfw-detection-3.ts b/packages/backend/src/migration/1655388169582-nsfw-detection-3.ts index 16cb039da5..be3a6c901d 100644 --- a/packages/backend/src/migration/1655388169582-nsfw-detection-3.ts +++ b/packages/backend/src/migration/1655388169582-nsfw-detection-3.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class nsfwDetection31655388169582 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1655393015659-nsfw-detection-4.ts b/packages/backend/src/migration/1655393015659-nsfw-detection-4.ts index e01e74e6a6..ea89dd0ae2 100644 --- a/packages/backend/src/migration/1655393015659-nsfw-detection-4.ts +++ b/packages/backend/src/migration/1655393015659-nsfw-detection-4.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class nsfwDetection41655393015659 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1655813815729-driveCapacityOverrideMb.ts b/packages/backend/src/migration/1655813815729-driveCapacityOverrideMb.ts index 8616fcb546..f143e17a68 100644 --- a/packages/backend/src/migration/1655813815729-driveCapacityOverrideMb.ts +++ b/packages/backend/src/migration/1655813815729-driveCapacityOverrideMb.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class driveCapacityOverrideMb1655813815729 implements MigrationInterface diff --git a/packages/backend/src/migration/1655918165614-user-ip.ts b/packages/backend/src/migration/1655918165614-user-ip.ts index db980e4b5c..1545a45ca0 100644 --- a/packages/backend/src/migration/1655918165614-user-ip.ts +++ b/packages/backend/src/migration/1655918165614-user-ip.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userIp1655918165614 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1656122560740-file-ip.ts b/packages/backend/src/migration/1656122560740-file-ip.ts index 52fdf1a64f..2e93de6485 100644 --- a/packages/backend/src/migration/1656122560740-file-ip.ts +++ b/packages/backend/src/migration/1656122560740-file-ip.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class fileIp1656122560740 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1656251734807-nsfw-detection-5.ts b/packages/backend/src/migration/1656251734807-nsfw-detection-5.ts index 2a89eef228..df9b0329f8 100644 --- a/packages/backend/src/migration/1656251734807-nsfw-detection-5.ts +++ b/packages/backend/src/migration/1656251734807-nsfw-detection-5.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class nsfwDetection51656251734807 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1656328812281-ip-2.ts b/packages/backend/src/migration/1656328812281-ip-2.ts index 45f608be3d..d80528042b 100644 --- a/packages/backend/src/migration/1656328812281-ip-2.ts +++ b/packages/backend/src/migration/1656328812281-ip-2.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ip21656328812281 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1656408772602-nsfw-detection-6.ts b/packages/backend/src/migration/1656408772602-nsfw-detection-6.ts index f3e34b097d..4a1ed32294 100644 --- a/packages/backend/src/migration/1656408772602-nsfw-detection-6.ts +++ b/packages/backend/src/migration/1656408772602-nsfw-detection-6.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class nsfwDetection61656408772602 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1656772790599-user-moderation-note.ts b/packages/backend/src/migration/1656772790599-user-moderation-note.ts index b98db08132..6612d7d2af 100644 --- a/packages/backend/src/migration/1656772790599-user-moderation-note.ts +++ b/packages/backend/src/migration/1656772790599-user-moderation-note.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class userModerationNote1656772790599 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1657346559800-active-email-validation.ts b/packages/backend/src/migration/1657346559800-active-email-validation.ts index e93f3f3a8c..55b99a3535 100644 --- a/packages/backend/src/migration/1657346559800-active-email-validation.ts +++ b/packages/backend/src/migration/1657346559800-active-email-validation.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class activeEmailValidation1657346559800 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1658203170545firefish.ts b/packages/backend/src/migration/1658203170545firefish.ts index 41df2367bc..9e058d1f64 100644 --- a/packages/backend/src/migration/1658203170545firefish.ts +++ b/packages/backend/src/migration/1658203170545firefish.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class calckey1658203170545 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1658656633972-note-replies-function.ts b/packages/backend/src/migration/1658656633972-note-replies-function.ts index eab330a08d..ea410b0201 100644 --- a/packages/backend/src/migration/1658656633972-note-replies-function.ts +++ b/packages/backend/src/migration/1658656633972-note-replies-function.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class noteRepliesFunction1658656633972 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1658939464003CustomMOTD.ts b/packages/backend/src/migration/1658939464003CustomMOTD.ts index e3247a274e..4c73be69cc 100644 --- a/packages/backend/src/migration/1658939464003CustomMOTD.ts +++ b/packages/backend/src/migration/1658939464003CustomMOTD.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class CustomMOTD1658939464003 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1658941974648CustomSplashIcons.ts b/packages/backend/src/migration/1658941974648CustomSplashIcons.ts index 43ddaf281d..d7a969aa29 100644 --- a/packages/backend/src/migration/1658941974648CustomSplashIcons.ts +++ b/packages/backend/src/migration/1658941974648CustomSplashIcons.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class CustomSplashIcons1658941974648 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1658981842728FixCalckey.ts b/packages/backend/src/migration/1658981842728FixCalckey.ts index cac88cd7dd..6d22f5aa5d 100644 --- a/packages/backend/src/migration/1658981842728FixCalckey.ts +++ b/packages/backend/src/migration/1658981842728FixCalckey.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class FixFirefish1658981842728 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1659042130648RecommendedTimeline.ts b/packages/backend/src/migration/1659042130648RecommendedTimeline.ts index 6a0b9140e5..e6f8bdd0e0 100644 --- a/packages/backend/src/migration/1659042130648RecommendedTimeline.ts +++ b/packages/backend/src/migration/1659042130648RecommendedTimeline.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class RecommendedTimeline1659042130648 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1660068273737GuestTimeline.ts b/packages/backend/src/migration/1660068273737GuestTimeline.ts index 4f6ddeb770..8ef5fa694d 100644 --- a/packages/backend/src/migration/1660068273737GuestTimeline.ts +++ b/packages/backend/src/migration/1660068273737GuestTimeline.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class GuestTimeline1660068273737 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1665091090561-add-renote-muting.ts b/packages/backend/src/migration/1665091090561-add-renote-muting.ts index f6787639dc..cb97f2151c 100644 --- a/packages/backend/src/migration/1665091090561-add-renote-muting.ts +++ b/packages/backend/src/migration/1665091090561-add-renote-muting.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class addRenoteMuting1665091090561 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1668828368510PageDraft.ts b/packages/backend/src/migration/1668828368510PageDraft.ts index 265e4d68ae..21150425ee 100644 --- a/packages/backend/src/migration/1668828368510PageDraft.ts +++ b/packages/backend/src/migration/1668828368510PageDraft.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class Page1668828368510 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1668831378728FixCalckeyAgain.ts b/packages/backend/src/migration/1668831378728FixCalckeyAgain.ts index 0f127e9244..962dc623b3 100644 --- a/packages/backend/src/migration/1668831378728FixCalckeyAgain.ts +++ b/packages/backend/src/migration/1668831378728FixCalckeyAgain.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class FixFirefishAgain1668831378728 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1669138716634-whetherPushNotifyToSendReadMessage.ts b/packages/backend/src/migration/1669138716634-whetherPushNotifyToSendReadMessage.ts index 38c7a31b85..fcd730bc83 100644 --- a/packages/backend/src/migration/1669138716634-whetherPushNotifyToSendReadMessage.ts +++ b/packages/backend/src/migration/1669138716634-whetherPushNotifyToSendReadMessage.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class whetherPushNotifyToSendReadMessage1669138716634 implements MigrationInterface diff --git a/packages/backend/src/migration/1669288094000-AddMovedToAndKnownAs.ts b/packages/backend/src/migration/1669288094000-AddMovedToAndKnownAs.ts index 3bdc26b4c9..d6423d499c 100644 --- a/packages/backend/src/migration/1669288094000-AddMovedToAndKnownAs.ts +++ b/packages/backend/src/migration/1669288094000-AddMovedToAndKnownAs.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class addMovedToAndKnownAs1669288094000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1671199573000-AddFkAbuseUserReportTargetUserIdToUserId.ts b/packages/backend/src/migration/1671199573000-AddFkAbuseUserReportTargetUserIdToUserId.ts index 26424d9c28..b91ff677b2 100644 --- a/packages/backend/src/migration/1671199573000-AddFkAbuseUserReportTargetUserIdToUserId.ts +++ b/packages/backend/src/migration/1671199573000-AddFkAbuseUserReportTargetUserIdToUserId.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class addFkAbuseUserReportTargetUserIdToUserId1671199573000 implements MigrationInterface diff --git a/packages/backend/src/migration/1671388343000-CalckeyRepoMove.ts b/packages/backend/src/migration/1671388343000-CalckeyRepoMove.ts index baf23963c4..828838424d 100644 --- a/packages/backend/src/migration/1671388343000-CalckeyRepoMove.ts +++ b/packages/backend/src/migration/1671388343000-CalckeyRepoMove.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; /* "FirefishRepoMove1671388343000" is a class that updates the "useStarForReactionFallback" column in the "meta" table to TRUE */ diff --git a/packages/backend/src/migration/1672882664294-DefaultReaction.ts b/packages/backend/src/migration/1672882664294-DefaultReaction.ts index 7874e571ef..e7621f1e38 100644 --- a/packages/backend/src/migration/1672882664294-DefaultReaction.ts +++ b/packages/backend/src/migration/1672882664294-DefaultReaction.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class DefaultReaction1672882664294 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1673336077243-PollChoiceLength.ts b/packages/backend/src/migration/1673336077243-PollChoiceLength.ts index 5f5ffd722a..330b7fc48d 100644 --- a/packages/backend/src/migration/1673336077243-PollChoiceLength.ts +++ b/packages/backend/src/migration/1673336077243-PollChoiceLength.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class PollChoiceLength1673336077243 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1676093997212-AntennaInstances.ts b/packages/backend/src/migration/1676093997212-AntennaInstances.ts index 63ac5ae29b..ece41705b8 100644 --- a/packages/backend/src/migration/1676093997212-AntennaInstances.ts +++ b/packages/backend/src/migration/1676093997212-AntennaInstances.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class AntennaInstances1676093997212 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1677935903517-DriveComment.ts b/packages/backend/src/migration/1677935903517-DriveComment.ts index 97d4bc4edf..d83ad1da7d 100644 --- a/packages/backend/src/migration/1677935903517-DriveComment.ts +++ b/packages/backend/src/migration/1677935903517-DriveComment.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class DriveComment1677935903517 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1678426061773-tweak-varchar-length.ts b/packages/backend/src/migration/1678426061773-tweak-varchar-length.ts index dc20555723..15e5dd1cff 100644 --- a/packages/backend/src/migration/1678426061773-tweak-varchar-length.ts +++ b/packages/backend/src/migration/1678426061773-tweak-varchar-length.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class tweakVarcharLength1678426061773 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1678945242650-add-props-for-custom-emoji.ts b/packages/backend/src/migration/1678945242650-add-props-for-custom-emoji.ts index 209dcbed70..affa0d9761 100644 --- a/packages/backend/src/migration/1678945242650-add-props-for-custom-emoji.ts +++ b/packages/backend/src/migration/1678945242650-add-props-for-custom-emoji.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class addPropsForCustomEmoji1678945242650 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1679269929000-fix-repo.ts b/packages/backend/src/migration/1679269929000-fix-repo.ts index 7c462bf626..38104a179c 100644 --- a/packages/backend/src/migration/1679269929000-fix-repo.ts +++ b/packages/backend/src/migration/1679269929000-fix-repo.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class FixRepo1679269929000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1680375641101-clean-charts.ts b/packages/backend/src/migration/1680375641101-clean-charts.ts index 9bc1356dcc..dc3b7b6c23 100644 --- a/packages/backend/src/migration/1680375641101-clean-charts.ts +++ b/packages/backend/src/migration/1680375641101-clean-charts.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class CleanCharts1680375641101 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1680426269172-SpeakAsCat.ts b/packages/backend/src/migration/1680426269172-SpeakAsCat.ts index 24700fe44f..20afaae6cc 100644 --- a/packages/backend/src/migration/1680426269172-SpeakAsCat.ts +++ b/packages/backend/src/migration/1680426269172-SpeakAsCat.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class SpeakAsCat1680426269172 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1682753227899-NoteEdit.ts b/packages/backend/src/migration/1682753227899-NoteEdit.ts index 6dae4efbdb..69f26e16cb 100644 --- a/packages/backend/src/migration/1682753227899-NoteEdit.ts +++ b/packages/backend/src/migration/1682753227899-NoteEdit.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class NoteEdit1682753227899 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1682777547198-LibreTranslate.ts b/packages/backend/src/migration/1682777547198-LibreTranslate.ts index c8b66f0d9e..de877966d8 100644 --- a/packages/backend/src/migration/1682777547198-LibreTranslate.ts +++ b/packages/backend/src/migration/1682777547198-LibreTranslate.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class LibreTranslate1682777547198 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1682891890317-InstanceSilence.ts b/packages/backend/src/migration/1682891890317-InstanceSilence.ts index ef36ad560d..b03cfb932a 100644 --- a/packages/backend/src/migration/1682891890317-InstanceSilence.ts +++ b/packages/backend/src/migration/1682891890317-InstanceSilence.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class InstanceSilence1682891890317 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1682891891317-AddHiddenPosts.ts b/packages/backend/src/migration/1682891891317-AddHiddenPosts.ts index f7f09ba44f..7f1890c718 100644 --- a/packages/backend/src/migration/1682891891317-AddHiddenPosts.ts +++ b/packages/backend/src/migration/1682891891317-AddHiddenPosts.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class AddHiddenPosts1682891891317 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1683682889948-PreventAiLearning.ts b/packages/backend/src/migration/1683682889948-PreventAiLearning.ts index 3123715b28..1bcf67839c 100644 --- a/packages/backend/src/migration/1683682889948-PreventAiLearning.ts +++ b/packages/backend/src/migration/1683682889948-PreventAiLearning.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class PreventAiLearning1683682889948 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1683980686995-ExperimentalFeatures.ts b/packages/backend/src/migration/1683980686995-ExperimentalFeatures.ts index b03408a00e..0245fa7f94 100644 --- a/packages/backend/src/migration/1683980686995-ExperimentalFeatures.ts +++ b/packages/backend/src/migration/1683980686995-ExperimentalFeatures.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ExperimentalFeatures1683980686995 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1684206886988-remove-showTimelineReplies.ts b/packages/backend/src/migration/1684206886988-remove-showTimelineReplies.ts index f156f41707..c16b79fe0f 100644 --- a/packages/backend/src/migration/1684206886988-remove-showTimelineReplies.ts +++ b/packages/backend/src/migration/1684206886988-remove-showTimelineReplies.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class RemoveShowTimelineReplies1684206886988 implements MigrationInterface diff --git a/packages/backend/src/migration/1684494870830-EmojiSize.ts b/packages/backend/src/migration/1684494870830-EmojiSize.ts index 987b7b77e2..9e95dd895b 100644 --- a/packages/backend/src/migration/1684494870830-EmojiSize.ts +++ b/packages/backend/src/migration/1684494870830-EmojiSize.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class EmojiSize1684494870830 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1688280713783-add-meta-options.ts b/packages/backend/src/migration/1688280713783-add-meta-options.ts index c058b7dcc4..be51ff9385 100644 --- a/packages/backend/src/migration/1688280713783-add-meta-options.ts +++ b/packages/backend/src/migration/1688280713783-add-meta-options.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class AddMetaOptions1688280713783 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1688845537045-announcement-popup.ts b/packages/backend/src/migration/1688845537045-announcement-popup.ts index c035051864..d75f9b3e02 100644 --- a/packages/backend/src/migration/1688845537045-announcement-popup.ts +++ b/packages/backend/src/migration/1688845537045-announcement-popup.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class AnnouncementPopup1688845537045 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1689136347561-donation-link.ts b/packages/backend/src/migration/1689136347561-donation-link.ts index 1abfa8e341..d043d1c2bb 100644 --- a/packages/backend/src/migration/1689136347561-donation-link.ts +++ b/packages/backend/src/migration/1689136347561-donation-link.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class DonationLink1689136347561 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1689739513827-firefish-repo.ts b/packages/backend/src/migration/1689739513827-firefish-repo.ts index dd34bcf183..774de00d70 100644 --- a/packages/backend/src/migration/1689739513827-firefish-repo.ts +++ b/packages/backend/src/migration/1689739513827-firefish-repo.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class FirefishRepo1689739513827 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1689957674000-firefish-repo.ts b/packages/backend/src/migration/1689957674000-firefish-repo.ts index 5ae1543f14..706b54f9d3 100644 --- a/packages/backend/src/migration/1689957674000-firefish-repo.ts +++ b/packages/backend/src/migration/1689957674000-firefish-repo.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class FirefishRepo1689957674000 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1692374635734-IncreaseHostCharLimit.ts b/packages/backend/src/migration/1692374635734-IncreaseHostCharLimit.ts index e4fe5cdc64..6e319c4972 100644 --- a/packages/backend/src/migration/1692374635734-IncreaseHostCharLimit.ts +++ b/packages/backend/src/migration/1692374635734-IncreaseHostCharLimit.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class IncreaseHostCharLimit1692374635734 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1692825433698-emoji-moderator.ts b/packages/backend/src/migration/1692825433698-emoji-moderator.ts index d5d405e536..67b1555f2b 100644 --- a/packages/backend/src/migration/1692825433698-emoji-moderator.ts +++ b/packages/backend/src/migration/1692825433698-emoji-moderator.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class EmojiModerator1692825433698 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1695334243217-add-post-lang.ts b/packages/backend/src/migration/1695334243217-add-post-lang.ts index df861e7639..54338b235e 100644 --- a/packages/backend/src/migration/1695334243217-add-post-lang.ts +++ b/packages/backend/src/migration/1695334243217-add-post-lang.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class AddPostLang1695334243217 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1698420787202-pgroonga.ts b/packages/backend/src/migration/1698420787202-pgroonga.ts index 703872c1c4..1e7a2fdd7b 100644 --- a/packages/backend/src/migration/1698420787202-pgroonga.ts +++ b/packages/backend/src/migration/1698420787202-pgroonga.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class Pgroonga1698420787202 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1699305365258-more-urls.ts b/packages/backend/src/migration/1699305365258-more-urls.ts index 2fe2704126..83e17d403c 100644 --- a/packages/backend/src/migration/1699305365258-more-urls.ts +++ b/packages/backend/src/migration/1699305365258-more-urls.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class MoreUrls1699305365258 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1704851359889-add-reply-muting.ts b/packages/backend/src/migration/1704851359889-add-reply-muting.ts index 3db5da32de..01b68a48f2 100644 --- a/packages/backend/src/migration/1704851359889-add-reply-muting.ts +++ b/packages/backend/src/migration/1704851359889-add-reply-muting.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class AddReplyMuting1704851359889 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1705848938166-remove-nsfw-detection.ts b/packages/backend/src/migration/1705848938166-remove-nsfw-detection.ts index c150b4b10d..8d61833cf9 100644 --- a/packages/backend/src/migration/1705848938166-remove-nsfw-detection.ts +++ b/packages/backend/src/migration/1705848938166-remove-nsfw-detection.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class RemoveNsfwDetection1705848938166 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1705877093218-remove-native-utils-migration.ts b/packages/backend/src/migration/1705877093218-remove-native-utils-migration.ts index a155a4ff78..51cc417cf5 100644 --- a/packages/backend/src/migration/1705877093218-remove-native-utils-migration.ts +++ b/packages/backend/src/migration/1705877093218-remove-native-utils-migration.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class RemoveNativeUtilsMigration1705877093218 implements MigrationInterface diff --git a/packages/backend/src/migration/1705944717480-rename-meta-columns.ts b/packages/backend/src/migration/1705944717480-rename-meta-columns.ts index b73bebe8e6..43caaac9c5 100644 --- a/packages/backend/src/migration/1705944717480-rename-meta-columns.ts +++ b/packages/backend/src/migration/1705944717480-rename-meta-columns.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class RenameMetaColumns1705944717480 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1706413792769-separate-hard-mute-words-and-patterns.ts b/packages/backend/src/migration/1706413792769-separate-hard-mute-words-and-patterns.ts index d2506616f7..f2e29fd5f6 100644 --- a/packages/backend/src/migration/1706413792769-separate-hard-mute-words-and-patterns.ts +++ b/packages/backend/src/migration/1706413792769-separate-hard-mute-words-and-patterns.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class SeparateHardMuteWordsAndPatterns1706413792769 implements MigrationInterface diff --git a/packages/backend/src/migration/1707850084123-firefish-url-move.ts b/packages/backend/src/migration/1707850084123-firefish-url-move.ts index a9621ab392..0d26bf4252 100644 --- a/packages/backend/src/migration/1707850084123-firefish-url-move.ts +++ b/packages/backend/src/migration/1707850084123-firefish-url-move.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class FirefishUrlMove1707850084123 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1708452631156-drop-user-profile-language.ts b/packages/backend/src/migration/1708452631156-drop-user-profile-language.ts index 568542cb67..7bb98d34aa 100644 --- a/packages/backend/src/migration/1708452631156-drop-user-profile-language.ts +++ b/packages/backend/src/migration/1708452631156-drop-user-profile-language.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class DropUserProfileLanguage1708452631156 implements MigrationInterface diff --git a/packages/backend/src/migration/1708872574733-index-alt-text-and-cw.ts b/packages/backend/src/migration/1708872574733-index-alt-text-and-cw.ts index b8072b717c..a13bfdb0b6 100644 --- a/packages/backend/src/migration/1708872574733-index-alt-text-and-cw.ts +++ b/packages/backend/src/migration/1708872574733-index-alt-text-and-cw.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class IndexAltTextAndCw1708872574733 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1709047957489-remove-charts.ts b/packages/backend/src/migration/1709047957489-remove-charts.ts index f4d303a574..e0ae442d30 100644 --- a/packages/backend/src/migration/1709047957489-remove-charts.ts +++ b/packages/backend/src/migration/1709047957489-remove-charts.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class RemoveCharts1709047957489 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1709129810501-fix-note-url-index.ts b/packages/backend/src/migration/1709129810501-fix-note-url-index.ts index b59119efa7..0947d32c1e 100644 --- a/packages/backend/src/migration/1709129810501-fix-note-url-index.ts +++ b/packages/backend/src/migration/1709129810501-fix-note-url-index.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class FixNoteUrlIndex1709129810501 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1709251460718-change-default-configs.ts b/packages/backend/src/migration/1709251460718-change-default-configs.ts index f9833450fd..b5d43487ed 100644 --- a/packages/backend/src/migration/1709251460718-change-default-configs.ts +++ b/packages/backend/src/migration/1709251460718-change-default-configs.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class ChangeDefaultConfigs1709251460718 implements MigrationInterface { async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1709305200000-markLocalFilesNsfwByDefault.ts b/packages/backend/src/migration/1709305200000-markLocalFilesNsfwByDefault.ts index c36c15fa41..cf88b02a56 100644 --- a/packages/backend/src/migration/1709305200000-markLocalFilesNsfwByDefault.ts +++ b/packages/backend/src/migration/1709305200000-markLocalFilesNsfwByDefault.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class markLocalFilesNsfwByDefault1709305200000 implements MigrationInterface diff --git a/packages/backend/src/migration/1710304584214-note-file.ts b/packages/backend/src/migration/1710304584214-note-file.ts index be0458d297..c93edaf2b2 100644 --- a/packages/backend/src/migration/1710304584214-note-file.ts +++ b/packages/backend/src/migration/1710304584214-note-file.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class NoteFile1710304584214 implements MigrationInterface { name = "NoteFile1710304584214"; diff --git a/packages/backend/src/migration/1710690239308-fix-muting-indices.ts b/packages/backend/src/migration/1710690239308-fix-muting-indices.ts index 3dc24c2531..48bcfa185e 100644 --- a/packages/backend/src/migration/1710690239308-fix-muting-indices.ts +++ b/packages/backend/src/migration/1710690239308-fix-muting-indices.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import type { MigrationInterface, QueryRunner } from "typeorm"; export class FixMutingIndices1710690239308 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/migration/1711936358554-expand-note-edit.ts b/packages/backend/src/migration/1711936358554-expand-note-edit.ts new file mode 100644 index 0000000000..1f23736fd1 --- /dev/null +++ b/packages/backend/src/migration/1711936358554-expand-note-edit.ts @@ -0,0 +1,15 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class ExpandNoteEdit1711936358554 implements MigrationInterface { + async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE "note_edit" ADD "emojis" character varying(128) array NOT NULL DEFAULT '{}'::varchar[] + `); + } + + async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE "note_edit" DROP COLUMN "emojis" + `); + } +} diff --git a/packages/backend/src/migration/1712425488543-drop-time-zone.ts b/packages/backend/src/migration/1712425488543-drop-time-zone.ts new file mode 100644 index 0000000000..7de3b60b58 --- /dev/null +++ b/packages/backend/src/migration/1712425488543-drop-time-zone.ts @@ -0,0 +1,459 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class DropTimeZone1712425488543 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "abuse_user_report" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "access_token" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "access_token" ALTER "lastUsedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "ad" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "ad" ALTER "expiresAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "announcement" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "announcement" ALTER "updatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "announcement_read" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "antenna" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "app" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "attestation_challenge" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "auth_session" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "blocking" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "channel" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "channel" ALTER "lastNotedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "channel_following" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "channel_note_pining" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "clip" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "drive_file" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "drive_folder" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "emoji" ALTER "updatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "following" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "follow_request" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "gallery_like" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "gallery_post" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "gallery_post" ALTER "updatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "caughtAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "infoUpdatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "lastCommunicatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "latestRequestReceivedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "latestRequestSentAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "messaging_message" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "moderation_log" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "muting" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "muting" ALTER "expiresAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note" ALTER "updatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_edit" ALTER "updatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_favorite" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_reaction" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_thread_muting" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_watching" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "notification" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "page" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "page" ALTER "updatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "page_like" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "password_reset_request" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "poll" ALTER "expiresAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "poll_vote" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "promo_note" ALTER "expiresAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "promo_read" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "registration_ticket" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "registry_item" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "registry_item" ALTER "updatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "renote_muting" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "reply_muting" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "signin" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "sw_subscription" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "used_username" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user" ALTER "lastActiveDate" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user" ALTER "lastFetchedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user" ALTER "updatedAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_group" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_group_invitation" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_group_invite" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_group_joining" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_ip" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_list" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_list_joining" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_note_pining" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_pending" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_security_key" ALTER "lastUsed" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "webhook" ALTER "createdAt" TYPE timestamp without time zone`, + ); + await queryRunner.query( + `ALTER TABLE "webhook" ALTER "latestSentAt" TYPE timestamp without time zone`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "abuse_user_report" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "access_token" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "access_token" ALTER "lastUsedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "ad" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "ad" ALTER "expiresAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "announcement" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "announcement" ALTER "updatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "announcement_read" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "antenna" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "app" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "attestation_challenge" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "auth_session" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "blocking" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "channel" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "channel" ALTER "lastNotedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "channel_following" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "channel_note_pining" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "clip" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "drive_file" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "drive_folder" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "emoji" ALTER "updatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "following" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "follow_request" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "gallery_like" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "gallery_post" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "gallery_post" ALTER "updatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "caughtAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "infoUpdatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "lastCommunicatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "latestRequestReceivedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "instance" ALTER "latestRequestSentAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "messaging_message" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "moderation_log" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "muting" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "muting" ALTER "expiresAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note" ALTER "updatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_edit" ALTER "updatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_favorite" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_reaction" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_thread_muting" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "note_watching" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "notification" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "page" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "page" ALTER "updatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "page_like" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "password_reset_request" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "poll" ALTER "expiresAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "poll_vote" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "promo_note" ALTER "expiresAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "promo_read" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "registration_ticket" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "registry_item" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "registry_item" ALTER "updatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "renote_muting" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "reply_muting" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "signin" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "sw_subscription" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "used_username" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user" ALTER "lastActiveDate" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user" ALTER "lastFetchedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user" ALTER "updatedAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_group" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_group_invitation" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_group_invite" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_group_joining" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_ip" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_list" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_list_joining" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_note_pining" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_pending" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "user_security_key" ALTER "lastUsed" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "webhook" ALTER "createdAt" TYPE timestamp with time zone`, + ); + await queryRunner.query( + `ALTER TABLE "webhook" ALTER "latestSentAt" TYPE timestamp with time zone`, + ); + } +} diff --git a/packages/backend/src/migration/1712855579316-fix-chat-file-constraint.ts b/packages/backend/src/migration/1712855579316-fix-chat-file-constraint.ts new file mode 100644 index 0000000000..98f10d2bb4 --- /dev/null +++ b/packages/backend/src/migration/1712855579316-fix-chat-file-constraint.ts @@ -0,0 +1,21 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class FixChatFileConstraint1712855579316 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_535def119223ac05ad3fa9ef64b"`, + ); + await queryRunner.query( + `ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_535def119223ac05ad3fa9ef64b" FOREIGN KEY ("fileId") REFERENCES "drive_file"("id") ON DELETE SET NULL ON UPDATE NO ACTION`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_535def119223ac05ad3fa9ef64b"`, + ); + await queryRunner.query( + `ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_535def119223ac05ad3fa9ef64b" FOREIGN KEY ("fileId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } +} diff --git a/packages/backend/src/migration/1712937600000-antennaLimit.ts b/packages/backend/src/migration/1712937600000-antennaLimit.ts new file mode 100644 index 0000000000..cd8f9ff658 --- /dev/null +++ b/packages/backend/src/migration/1712937600000-antennaLimit.ts @@ -0,0 +1,19 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class antennaLimit1712937600000 implements MigrationInterface { + async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "meta" ADD "antennaLimit" integer NOT NULL DEFAULT 5`, + undefined, + ); + await queryRunner.query( + `COMMENT ON COLUMN "meta"."antennaLimit" IS 'Antenna Limit'`, + ); + } + async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "meta" DROP COLUMN "antennaLimit"`, + undefined, + ); + } +} diff --git a/packages/backend/src/migration/1713225866247-convert-cw-varchar-to-text.ts b/packages/backend/src/migration/1713225866247-convert-cw-varchar-to-text.ts new file mode 100644 index 0000000000..93c87a98a8 --- /dev/null +++ b/packages/backend/src/migration/1713225866247-convert-cw-varchar-to-text.ts @@ -0,0 +1,21 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class ConvertCwVarcharToText1713225866247 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + queryRunner.query(`DROP INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f"`); + queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "cw" TYPE text`); + queryRunner.query( + `CREATE INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f" ON "note" USING "pgroonga" ("cw")`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + queryRunner.query(`DROP INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f"`); + queryRunner.query( + `ALTER TABLE "note" ALTER COLUMN "cw" TYPE character varying(512)`, + ); + queryRunner.query( + `CREATE INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f" ON "note" USING "pgroonga" ("cw" pgroonga_varchar_full_text_search_ops_v2)`, + ); + } +} diff --git a/packages/backend/src/migration/1713451569342-AddDriveFileUsage.ts b/packages/backend/src/migration/1713451569342-AddDriveFileUsage.ts new file mode 100644 index 0000000000..3bdb1aafc8 --- /dev/null +++ b/packages/backend/src/migration/1713451569342-AddDriveFileUsage.ts @@ -0,0 +1,17 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddDriveFileUsage1713451569342 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE drive_file_usage_hint_enum AS ENUM ('userAvatar', 'userBanner')`, + ); + await queryRunner.query( + `ALTER TABLE "drive_file" ADD "usageHint" drive_file_usage_hint_enum DEFAULT NULL`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "usageHint"`); + await queryRunner.query(`DROP TYPE drive_file_usage_hint_enum`); + } +} diff --git a/packages/backend/src/misc/acct.ts b/packages/backend/src/misc/acct.ts deleted file mode 100644 index cb6808b4b4..0000000000 --- a/packages/backend/src/misc/acct.ts +++ /dev/null @@ -1,14 +0,0 @@ -export type Acct = { - username: string; - host: string | null; -}; - -export function parse(acct: string): Acct { - if (acct.startsWith("@")) acct = acct.slice(1); - const split = acct.split("@", 2); - return { username: split[0], host: split[1] || null }; -} - -export function toString(acct: Acct): string { - return acct.host == null ? acct.username : `${acct.username}@${acct.host}`; -} diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index 30a50e5714..e99b17a5f7 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -1,6 +1,6 @@ import { redisClient } from "@/db/redis.js"; import { encode, decode } from "msgpackr"; -import { ChainableCommander } from "ioredis"; +import type { ChainableCommander } from "ioredis"; export class Cache { private ttl: number; diff --git a/packages/backend/src/misc/check-hit-antenna.ts b/packages/backend/src/misc/check-hit-antenna.ts index b93cb459e8..2fa764c85b 100644 --- a/packages/backend/src/misc/check-hit-antenna.ts +++ b/packages/backend/src/misc/check-hit-antenna.ts @@ -3,9 +3,7 @@ import type { Note } from "@/models/entities/note.js"; import type { User } from "@/models/entities/user.js"; import type { UserProfile } from "@/models/entities/user-profile.js"; import { Blockings, Followings, UserProfiles } from "@/models/index.js"; -import { getFullApAccount } from "@/misc/convert-host.js"; -import * as Acct from "@/misc/acct.js"; -import { getWordHardMute } from "@/misc/check-word-mute.js"; +import { checkWordMute, getFullApAccount, stringToAcct } from "backend-rs"; import type { Packed } from "@/misc/schema.js"; import { Cache } from "@/misc/cache.js"; @@ -30,7 +28,7 @@ export async function checkHitAntenna( if (antenna.src === "users") { const accts = antenna.users.map((x) => { - const { username, host } = Acct.parse(x); + const { username, host } = stringToAcct(x); return getFullApAccount(username, host).toLowerCase(); }); if ( @@ -124,7 +122,7 @@ export async function checkHitAntenna( mutes.mutedWords != null && mutes.mutedPatterns != null && antenna.userId !== note.userId && - (await getWordHardMute(note, mutes.mutedWords, mutes.mutedPatterns)) + (await checkWordMute(note, mutes.mutedWords, mutes.mutedPatterns)) ) return false; diff --git a/packages/backend/src/misc/check-word-mute.ts b/packages/backend/src/misc/check-word-mute.ts deleted file mode 100644 index f07f2a0fe5..0000000000 --- a/packages/backend/src/misc/check-word-mute.ts +++ /dev/null @@ -1,76 +0,0 @@ -import RE2 from "re2"; -import type { Note } from "@/models/entities/note.js"; - -type NoteLike = { - userId: Note["userId"]; - text: Note["text"]; - files?: Note["files"]; - cw?: Note["cw"]; - reply?: NoteLike | null; - renote?: NoteLike | null; -}; - -function checkWordMute( - note: NoteLike | null | undefined, - mutedWords: string[][], - mutedPatterns: string[], -): boolean { - if (note == null) return false; - - let text = `${note.cw ?? ""} ${note.text ?? ""}`; - if (note.files != null) - text += ` ${note.files.map((f) => f.comment ?? "").join(" ")}`; - text = text.trim(); - - if (text === "") return false; - - for (const mutedWord of mutedWords) { - // Clean up - const keywords = mutedWord.filter((keyword) => keyword !== ""); - - if ( - keywords.length > 0 && - keywords.every((keyword) => - text.toLowerCase().includes(keyword.toLowerCase()), - ) - ) - return true; - } - - for (const mutedPattern of mutedPatterns) { - // represents RegExp - const regexp = mutedPattern.match(/^\/(.+)\/(.*)$/); - - // This should never happen due to input sanitisation. - if (!regexp) { - console.warn(`Found invalid regex in word mutes: ${mutedPattern}`); - continue; - } - - try { - if (new RE2(regexp[1], regexp[2]).test(text)) return true; - } catch (err) { - // This should never happen due to input sanitisation. - } - } - - return false; -} - -export async function getWordHardMute( - note: NoteLike | null, - mutedWords: string[][], - mutedPatterns: string[], -): Promise { - if (note == null || mutedWords == null || mutedPatterns == null) return false; - - if (mutedWords.length > 0) { - return ( - checkWordMute(note, mutedWords, mutedPatterns) || - checkWordMute(note.reply, mutedWords, mutedPatterns) || - checkWordMute(note.renote, mutedWords, mutedPatterns) - ); - } - - return false; -} diff --git a/packages/backend/src/misc/convert-host.ts b/packages/backend/src/misc/convert-host.ts deleted file mode 100644 index 65cc3ca1f5..0000000000 --- a/packages/backend/src/misc/convert-host.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { URL } from "node:url"; -import config from "@/config/index.js"; -import { toASCII } from "punycode"; -import Logger from "@/services/logger.js"; -import { inspect } from "node:util"; - -const logger = new Logger("convert-host"); - -export function getFullApAccount(username: string, host: string | null) { - return host - ? `${username}@${toPuny(host)}` - : `${username}@${toPuny(config.host)}`; -} - -export function isSelfHost(host: string) { - if (host == null) return true; - return toPuny(config.host) === toPuny(host); -} - -export function isSameOrigin(src: unknown): boolean | null { - if (typeof src !== "string") { - logger.debug(`unknown origin: ${inspect(src)}`); - return null; - } - try { - const u = new URL(src); - return u.origin === config.url; - } catch (e) { - logger.debug(inspect(e)); - return false; - } -} - -export function extractDbHost(uri: string) { - const url = new URL(uri); - return toPuny(url.hostname); -} - -export function toPuny(host: string) { - return toASCII(host.toLowerCase()); -} - -export function toPunyNullable(host: string | null | undefined): string | null { - if (host == null) return null; - return toASCII(host.toLowerCase()); -} diff --git a/packages/backend/src/misc/convert-milliseconds.ts b/packages/backend/src/misc/convert-milliseconds.ts deleted file mode 100644 index d8c163ffda..0000000000 --- a/packages/backend/src/misc/convert-milliseconds.ts +++ /dev/null @@ -1,17 +0,0 @@ -export function convertMilliseconds(ms: number) { - let seconds = Math.round(ms / 1000); - let minutes = Math.round(seconds / 60); - let hours = Math.round(minutes / 60); - const days = Math.round(hours / 24); - seconds %= 60; - minutes %= 60; - hours %= 24; - - const result = []; - if (days > 0) result.push(`${days} day(s)`); - if (hours > 0) result.push(`${hours} hour(s)`); - if (minutes > 0) result.push(`${minutes} minute(s)`); - if (seconds > 0) result.push(`${seconds} second(s)`); - - return result.join(", "); -} diff --git a/packages/backend/src/misc/download-url.ts b/packages/backend/src/misc/download-url.ts index ab04e8aa9c..663d354ead 100644 --- a/packages/backend/src/misc/download-url.ts +++ b/packages/backend/src/misc/download-url.ts @@ -2,7 +2,7 @@ import * as fs from "node:fs"; import * as stream from "node:stream"; import * as util from "node:util"; import got, * as Got from "got"; -import { httpAgent, httpsAgent, StatusError } from "./fetch.js"; +import { getAgentByHostname, StatusError } from "./fetch.js"; import config from "@/config/index.js"; import chalk from "chalk"; import Logger from "@/services/logger.js"; @@ -40,10 +40,7 @@ export async function downloadUrl(url: string, path: string): Promise { send: timeout, request: operationTimeout, // whole operation timeout }, - agent: { - http: httpAgent, - https: httpsAgent, - }, + agent: getAgentByHostname(new URL(url).hostname), http2: false, // default retry: { limit: 0, diff --git a/packages/backend/src/misc/emoji-regex.ts b/packages/backend/src/misc/emoji-regex.ts deleted file mode 100644 index 72d6a62d9a..0000000000 --- a/packages/backend/src/misc/emoji-regex.ts +++ /dev/null @@ -1,5 +0,0 @@ -import twemoji from "@twemoji/parser/dist/lib/regex.js"; -const twemojiRegex = twemoji.default; - -export const emojiRegex = new RegExp(`(${twemojiRegex.source})`); -export const emojiRegexAtStartToEnd = new RegExp(`^(${twemojiRegex.source})$`); diff --git a/packages/backend/src/misc/fetch-meta.ts b/packages/backend/src/misc/fetch-meta.ts deleted file mode 100644 index fdc978b5a3..0000000000 --- a/packages/backend/src/misc/fetch-meta.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { db } from "@/db/postgre.js"; -import { Meta } from "@/models/entities/meta.js"; - -let cache: Meta; - -export function metaToPugArgs(meta: Meta): object { - let motd = ["Loading..."]; - if (meta.customMotd.length > 0) { - motd = meta.customMotd; - } - let splashIconUrl = meta.iconUrl; - if (meta.customSplashIcons.length > 0) { - splashIconUrl = - meta.customSplashIcons[ - Math.floor(Math.random() * meta.customSplashIcons.length) - ]; - } - - return { - img: meta.bannerUrl, - title: meta.name || "Firefish", - instanceName: meta.name || "Firefish", - desc: meta.description, - icon: meta.iconUrl, - splashIcon: splashIconUrl, - themeColor: meta.themeColor, - randomMOTD: motd[Math.floor(Math.random() * motd.length)], - privateMode: meta.privateMode, - }; -} - -export async function fetchMeta(noCache = false): Promise { - if (!noCache && cache) return cache; - - return await db.transaction(async (transactionalEntityManager) => { - // New IDs are prioritized because multiple records may have been created due to past bugs. - const metas = await transactionalEntityManager.find(Meta, { - order: { - id: "DESC", - }, - }); - - const meta = metas[0]; - - if (meta) { - cache = meta; - return meta; - } else { - // If fetchMeta is called at the same time when meta is empty, this part may be called at the same time, so use fail-safe upsert. - const saved = await transactionalEntityManager - .upsert( - Meta, - { - id: "x", - }, - ["id"], - ) - .then((x) => - transactionalEntityManager.findOneByOrFail(Meta, x.identifiers[0]), - ); - - cache = saved; - return saved; - } - }); -} - -setInterval(() => { - fetchMeta(true).then((meta) => { - cache = meta; - }); -}, 1000 * 10); diff --git a/packages/backend/src/misc/fetch-proxy-account.ts b/packages/backend/src/misc/fetch-proxy-account.ts index a277db6fb9..8d015da25d 100644 --- a/packages/backend/src/misc/fetch-proxy-account.ts +++ b/packages/backend/src/misc/fetch-proxy-account.ts @@ -1,9 +1,9 @@ -import { fetchMeta } from "./fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { ILocalUser } from "@/models/entities/user.js"; import { Users } from "@/models/index.js"; export async function fetchProxyAccount(): Promise { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.proxyAccountId == null) return null; return (await Users.findOneByOrFail({ id: meta.proxyAccountId, diff --git a/packages/backend/src/misc/fetch.ts b/packages/backend/src/misc/fetch.ts index 8108b13d9e..2cfd6b95f7 100644 --- a/packages/backend/src/misc/fetch.ts +++ b/packages/backend/src/misc/fetch.ts @@ -2,7 +2,7 @@ import * as http from "node:http"; import * as https from "node:https"; import type { URL } from "node:url"; import CacheableLookup from "cacheable-lookup"; -import fetch, { RequestRedirect } from "node-fetch"; +import fetch, { type RequestRedirect } from "node-fetch"; import { HttpProxyAgent, HttpsProxyAgent } from "hpagent"; import config from "@/config/index.js"; import { isValidUrl } from "./is-valid-url.js"; @@ -171,6 +171,25 @@ export function getAgentByUrl(url: URL, bypassProxy = false) { } } +/** + * Get agent by Hostname + * @param hostname Hostname + * @param bypassProxy Allways bypass proxy + */ +export function getAgentByHostname(hostname: string, bypassProxy = false) { + if (bypassProxy || (config.proxyBypassHosts || []).includes(hostname)) { + return { + http: _http, + https: _https, + }; + } else { + return { + http: httpAgent, + https: httpsAgent, + }; + } +} + export class StatusError extends Error { public statusCode: number; public statusMessage?: string; diff --git a/packages/backend/src/misc/gen-id.ts b/packages/backend/src/misc/gen-id.ts deleted file mode 100644 index e2d9b0201f..0000000000 --- a/packages/backend/src/misc/gen-id.ts +++ /dev/null @@ -1,26 +0,0 @@ -import config from "@/config/index.js"; -import { - nativeCreateId, - nativeInitIdGenerator, - nativeGetTimestamp, -} from "backend-rs"; - -const length = Math.min(Math.max(config.cuid?.length ?? 16, 16), 24); -const fingerprint = config.cuid?.fingerprint ?? ""; -nativeInitIdGenerator(length, fingerprint); - -/** - * The generated ID results in the form of `[8 chars timestamp] + [cuid2]`. - * The minimum and maximum lengths are 16 and 24, respectively. - * With the length of 16, namely 8 for cuid2, roughly 1427399 IDs are needed - * in the same millisecond to reach 50% chance of collision. - * - * Ref: https://github.com/paralleldrive/cuid2#parameterized-length - */ -export function genId(date?: Date): string { - return nativeCreateId((date ?? new Date()).getTime()); -} - -export function getTimestamp(id: string): number { - return nativeGetTimestamp(id); -} diff --git a/packages/backend/src/misc/get-note-summary.ts b/packages/backend/src/misc/get-note-summary.ts deleted file mode 100644 index 0a662e434e..0000000000 --- a/packages/backend/src/misc/get-note-summary.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { Packed } from "./schema.js"; - -/** - * 投稿を表す文字列を取得します。 - * @param {*} note (packされた)投稿 - */ -export const getNoteSummary = (note: Packed<"Note">): string => { - if (note.deletedAt) { - return "❌"; - } - - let summary = ""; - - // 本文 - if (note.cw != null) { - summary += note.cw; - } else { - summary += note.text ? note.text : ""; - } - - // ファイルが添付されているとき - if ((note.files || []).length !== 0) { - const len = note.files?.length; - summary += ` 📎${len !== 1 ? ` (${len})` : ""}`; - } - - // 投票が添付されているとき - if (note.poll) { - summary += " 📊"; - } - - /* - // 返信のとき - if (note.replyId) { - if (note.reply) { - summary += `\n\nRE: ${getNoteSummary(note.reply)}`; - } else { - summary += '\n\nRE: ...'; - } - } - - // Renoteのとき - if (note.renoteId) { - if (note.renote) { - summary += `\n\nRN: ${getNoteSummary(note.renote)}`; - } else { - summary += '\n\nRN: ...'; - } - } - */ - - return summary.trim(); -}; diff --git a/packages/backend/src/misc/nyaify.ts b/packages/backend/src/misc/nyaify.ts deleted file mode 100644 index 5829461779..0000000000 --- a/packages/backend/src/misc/nyaify.ts +++ /dev/null @@ -1,33 +0,0 @@ -export function nyaify(text: string, lang?: string): string { - text = text - // ja-JP - .replaceAll("な", "にゃ") - .replaceAll("ナ", "ニャ") - .replaceAll("ナ", "ニャ") - // en-US - .replaceAll("na", "nya") - .replaceAll("Na", "Nya") - .replaceAll("NA", "NYA") - .replace(/(?<=morn)ing/gi, (x) => (x === "ING" ? "YAN" : "yan")) - .replace(/(?<=every)one/gi, (x) => (x === "ONE" ? "NYAN" : "nyan")) - .replace(/non(?=[bcdfghjklmnpqrstvwxyz])/gi, (x) => - x === "NON" ? "NYAN" : "nyan", - ) - // ko-KR - .replace(/[나-낳]/g, (match) => - String.fromCharCode( - match.charCodeAt(0)! + "냐".charCodeAt(0) - "나".charCodeAt(0), - ), - ) - .replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥") - .replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥") - // el-GR - .replaceAll("να", "νια") - .replaceAll("ΝΑ", "ΝΙΑ") - .replaceAll("Να", "Νια"); - - // zh-CN, zh-TW - if (lang === "zh") text = text.replace(/(妙|庙|描|渺|瞄|秒|苗|藐|廟)/g, "喵"); - - return text; -} diff --git a/packages/backend/src/misc/password.ts b/packages/backend/src/misc/password.ts deleted file mode 100644 index c63f89f5c9..0000000000 --- a/packages/backend/src/misc/password.ts +++ /dev/null @@ -1,20 +0,0 @@ -import bcrypt from "bcryptjs"; -import * as argon2 from "argon2"; - -export async function hashPassword(password: string): Promise { - return argon2.hash(password); -} - -export async function comparePassword( - password: string, - hash: string, -): Promise { - if (isOldAlgorithm(hash)) return bcrypt.compare(password, hash); - - return argon2.verify(hash, password); -} - -export function isOldAlgorithm(hash: string): boolean { - // bcrypt hashes start with $2[ab]$ - return hash.startsWith("$2"); -} diff --git a/packages/backend/src/misc/populate-emojis.ts b/packages/backend/src/misc/populate-emojis.ts index 0e21d0e2ab..4ca60b222f 100644 --- a/packages/backend/src/misc/populate-emojis.ts +++ b/packages/backend/src/misc/populate-emojis.ts @@ -3,11 +3,11 @@ import { Emojis } from "@/models/index.js"; import type { Emoji } from "@/models/entities/emoji.js"; import type { Note } from "@/models/entities/note.js"; import { Cache } from "./cache.js"; -import { isSelfHost, toPunyNullable } from "./convert-host.js"; -import { decodeReaction } from "./reaction-lib.js"; +import { decodeReaction, isSelfHost, toPuny } from "backend-rs"; import config from "@/config/index.js"; import { query } from "@/prelude/url.js"; import { redisClient } from "@/db/redis.js"; +import type { NoteEdit } from "@/models/entities/note-edit.js"; const cache = new Cache("populateEmojis", 60 * 60 * 12); @@ -26,7 +26,7 @@ function normalizeHost( noteUserHost: string | null, ): string | null { // クエリに使うホスト - let host = + const host = src === "." ? null // .はローカルホスト (ここがマッチするのはリアクションのみ) : src === undefined @@ -35,9 +35,7 @@ function normalizeHost( ? null // 自ホスト指定 : src || noteUserHost; // 指定されたホスト || ノートなどの所有者のホスト (こっちがリアクションにマッチすることはない) - host = toPunyNullable(host); - - return host; + return host == null ? null : toPuny(host); } function parseEmojiStr(emojiName: string, noteUserHost: string | null) { @@ -45,11 +43,7 @@ function parseEmojiStr(emojiName: string, noteUserHost: string | null) { if (!match) return { name: null, host: null }; const name = match[1]; - - // ホスト正規化 - const host = toPunyNullable(normalizeHost(match[2], noteUserHost)); - - return { name, host }; + return { name, host: normalizeHost(match[2], noteUserHost) }; } /** @@ -110,6 +104,23 @@ export async function populateEmojis( return emojis.filter((x): x is PopulatedEmoji => x != null); } +export function aggregateNoteEditEmojis( + noteEdits: NoteEdit[], + sourceHost: string | null, +) { + let emojis: string[] = []; + for (const noteEdit of noteEdits) { + emojis = emojis.concat(noteEdit.emojis); + } + emojis = Array.from(new Set(emojis)); + return emojis + .map((e) => parseEmojiStr(e, sourceHost)) + .filter((x) => x.name != null) as { + name: string; + host: string | null; + }[]; +} + export function aggregateNoteEmojis(notes: Note[]) { let emojis: { name: string | null; host: string | null }[] = []; for (const note of notes) { @@ -145,7 +156,7 @@ export function aggregateNoteEmojis(notes: Note[]) { } /** - * 与えられた絵文字のリストをデータベースから取得し、キャッシュに追加します + * Get the given list of emojis from the database and adds them to the cache */ export async function prefetchEmojis( emojis: { name: string; host: string | null }[], diff --git a/packages/backend/src/misc/post.ts b/packages/backend/src/misc/post.ts index dbe703d1a0..0b107ed009 100644 --- a/packages/backend/src/misc/post.ts +++ b/packages/backend/src/misc/post.ts @@ -12,7 +12,7 @@ export function parse(acct: any): Post { cw: acct.cw, localOnly: acct.localOnly, createdAt: new Date(acct.createdAt), - visibility: "hidden" + (acct.visibility || ""), + visibility: `hidden${acct.visibility || ""}`, }; } diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts deleted file mode 100644 index db88b05900..0000000000 --- a/packages/backend/src/misc/reaction-lib.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { emojiRegex } from "./emoji-regex.js"; -import { fetchMeta } from "./fetch-meta.js"; -import { Emojis } from "@/models/index.js"; -import { toPunyNullable } from "./convert-host.js"; -import { IsNull } from "typeorm"; - -export function convertReactions(reactions: Record) { - const result = new Map(); - - for (const reaction in reactions) { - if (reactions[reaction] <= 0) continue; - - const decoded = decodeReaction(reaction).reaction; - result.set(decoded, (result.get(decoded) || 0) + reactions[reaction]); - } - - return Object.fromEntries(result); -} - -export async function toDbReaction( - reaction?: string | null, - reacterHost?: string | null, -): Promise { - if (!reaction) return (await fetchMeta()).defaultReaction; - - reacterHost = toPunyNullable(reacterHost); - - if (reaction.includes("❤") || reaction.includes("♥️")) return "❤️"; - - // Allow unicode reactions - const match = emojiRegex.exec(reaction); - if (match) { - const unicode = match[0]; - return unicode; - } - - const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/); - if (custom) { - const name = custom[1]; - const emoji = await Emojis.findOneBy({ - host: reacterHost || IsNull(), - name, - }); - - if (emoji) return reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; - } - - return (await fetchMeta()).defaultReaction; -} - -type DecodedReaction = { - /** - * リアクション名 (Unicode Emoji or ':name@hostname' or ':name@.') - */ - reaction: string; - - /** - * name (カスタム絵文字の場合name, Emojiクエリに使う) - */ - name?: string; - - /** - * host (カスタム絵文字の場合host, Emojiクエリに使う) - */ - host?: string | null; -}; - -export function decodeReaction(str: string): DecodedReaction { - const custom = str.match(/^:([\w+-]+)(?:@([\w.-]+))?:$/); - - if (custom) { - const name = custom[1]; - const host = custom[2] || null; - - return { - reaction: `:${name}@${host || "."}:`, // ローカル分は@以降を省略するのではなく.にする - name, - host, - }; - } - - return { - reaction: str, - name: undefined, - host: undefined, - }; -} diff --git a/packages/backend/src/misc/safe-for-sql.ts b/packages/backend/src/misc/safe-for-sql.ts deleted file mode 100644 index 02eb7f0a26..0000000000 --- a/packages/backend/src/misc/safe-for-sql.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function safeForSql(text: string): boolean { - return !/[\0\x08\x09\x1a\n\r"'\\\%]/g.test(text); -} diff --git a/packages/backend/src/misc/schema.ts b/packages/backend/src/misc/schema.ts index c793d3b2ed..73600832ce 100644 --- a/packages/backend/src/misc/schema.ts +++ b/packages/backend/src/misc/schema.ts @@ -33,8 +33,10 @@ import { packedGalleryPostSchema } from "@/models/schema/gallery-post.js"; import { packedEmojiSchema } from "@/models/schema/emoji.js"; import { packedNoteEdit } from "@/models/schema/note-edit.js"; import { packedNoteFileSchema } from "@/models/schema/note-file.js"; +import { packedAbuseUserReportSchema } from "@/models/schema/abuse-user-report.js"; export const refs = { + AbuseUserReport: packedAbuseUserReportSchema, UserLite: packedUserLiteSchema, UserDetailedNotMeOnly: packedUserDetailedNotMeOnlySchema, MeDetailedOnly: packedMeDetailedOnlySchema, diff --git a/packages/backend/src/misc/secure-rndstr.ts b/packages/backend/src/misc/secure-rndstr.ts deleted file mode 100644 index f98985592b..0000000000 --- a/packages/backend/src/misc/secure-rndstr.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { nativeRandomStr } from "backend-rs"; - -export function secureRndstr(length = 32, _ = true): string { - return nativeRandomStr(length); -} diff --git a/packages/backend/src/misc/should-block-instance.ts b/packages/backend/src/misc/should-block-instance.ts index 35ed307931..465be41f2a 100644 --- a/packages/backend/src/misc/should-block-instance.ts +++ b/packages/backend/src/misc/should-block-instance.ts @@ -1,4 +1,4 @@ -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { Instance } from "@/models/entities/instance.js"; import type { Meta } from "@/models/entities/meta.js"; @@ -13,7 +13,7 @@ export async function shouldBlockInstance( host: Instance["host"], meta?: Meta, ): Promise { - const { blockedHosts } = meta ?? (await fetchMeta()); + const { blockedHosts } = meta ?? (await fetchMeta(true)); return blockedHosts.some( (blockedHost) => host === blockedHost || host.endsWith(`.${blockedHost}`), ); @@ -30,7 +30,7 @@ export async function shouldSilenceInstance( host: Instance["host"], meta?: Meta, ): Promise { - const { silencedHosts } = meta ?? (await fetchMeta()); + const { silencedHosts } = meta ?? (await fetchMeta(true)); return silencedHosts.some( (silencedHost) => host === silencedHost || host.endsWith(`.${silencedHost}`), diff --git a/packages/backend/src/misc/skipped-instances.ts b/packages/backend/src/misc/skipped-instances.ts index 785393022a..14b26a3032 100644 --- a/packages/backend/src/misc/skipped-instances.ts +++ b/packages/backend/src/misc/skipped-instances.ts @@ -1,5 +1,5 @@ import { Brackets } from "typeorm"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Instances } from "@/models/index.js"; import type { Instance } from "@/models/entities/instance.js"; import { DAY } from "@/const.js"; @@ -19,7 +19,7 @@ export async function skippedInstances( hosts: Instance["host"][], ): Promise { // first check for blocked instances since that info may already be in memory - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const shouldSkip = await Promise.all( hosts.map((host) => shouldBlockInstance(host, meta)), ); diff --git a/packages/backend/src/misc/sql-like-escape.ts b/packages/backend/src/misc/sql-like-escape.ts deleted file mode 100644 index 453947d6ec..0000000000 --- a/packages/backend/src/misc/sql-like-escape.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function sqlLikeEscape(s: string) { - return s.replace(/([%_])/g, "\\$1"); -} diff --git a/packages/backend/src/misc/translate.ts b/packages/backend/src/misc/translate.ts index 8592d639db..3395ce93be 100644 --- a/packages/backend/src/misc/translate.ts +++ b/packages/backend/src/misc/translate.ts @@ -1,10 +1,13 @@ import fetch from "node-fetch"; import { Converter } from "opencc-js"; import { getAgentByUrl } from "@/misc/fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { PostLanguage } from "@/misc/langmap"; import * as deepl from "deepl-node"; +// DeepL translate and LibreTranslate don't provide +// zh-Hant-TW translations, so we convert zh-Hans-CN +// translations into zh-Hant-TW using opencc-js. function convertChinese(convert: boolean, src: string) { if (!convert) return src; const converter = Converter({ from: "cn", to: "twp" }); @@ -23,7 +26,7 @@ export async function translate( from: PostLanguage | null, to: PostLanguage, ) { - const instance = await fetchMeta(); + const instance = await fetchMeta(true); if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) { throw Error("No translator is set up on this server."); @@ -78,6 +81,8 @@ export async function translate( const result = await deeplTranslator.translateText( text, source as deepl.SourceLanguageCode | null, + // DeepL API requires us to specify "en-US" or "en-GB" for English + // translations ("en" does not work), so we need to address it (target === "en" ? to : target) as deepl.TargetLanguageCode, ); diff --git a/packages/backend/src/models/entities/abuse-user-report.ts b/packages/backend/src/models/entities/abuse-user-report.ts index cb4d55851d..88f24d130d 100644 --- a/packages/backend/src/models/entities/abuse-user-report.ts +++ b/packages/backend/src/models/entities/abuse-user-report.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -15,7 +16,7 @@ export class AbuseUserReport { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the AbuseUserReport.", }) public createdAt: Date; @@ -24,34 +25,16 @@ export class AbuseUserReport { @Column(id()) public targetUserId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public targetUser: User | null; - @Index() @Column(id()) public reporterId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public reporter: User | null; - @Column({ ...id(), nullable: true, }) public assigneeId: User["id"] | null; - @ManyToOne((type) => User, { - onDelete: "SET NULL", - }) - @JoinColumn() - public assignee: User | null; - @Index() @Column("boolean", { default: false, @@ -85,4 +68,25 @@ export class AbuseUserReport { }) public reporterHost: string | null; //#endregion + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public targetUser: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public reporter: Relation; + + @ManyToOne(() => User, { + onDelete: "SET NULL", + nullable: true, + }) + @JoinColumn() + public assignee: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/access-token.ts b/packages/backend/src/models/entities/access-token.ts index 8b950b171b..a10cf7a907 100644 --- a/packages/backend/src/models/entities/access-token.ts +++ b/packages/backend/src/models/entities/access-token.ts @@ -5,6 +5,7 @@ import { Column, ManyToOne, JoinColumn, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { App } from "./app.js"; @@ -15,12 +16,12 @@ export class AccessToken { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the AccessToken.", }) public createdAt: Date; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public lastUsedAt: Date | null; @@ -48,24 +49,12 @@ export class AccessToken { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column({ ...id(), nullable: true, }) public appId: App["id"] | null; - @ManyToOne((type) => App, { - onDelete: "CASCADE", - }) - @JoinColumn() - public app: App | null; - @Column("varchar", { length: 128, nullable: true, @@ -95,4 +84,18 @@ export class AccessToken { default: false, }) public fetched: boolean; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + + @ManyToOne(() => App, { + onDelete: "CASCADE", + }) + @JoinColumn() + public app: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/ad.ts b/packages/backend/src/models/entities/ad.ts index 80d54ddd52..a7a630d425 100644 --- a/packages/backend/src/models/entities/ad.ts +++ b/packages/backend/src/models/entities/ad.ts @@ -7,13 +7,13 @@ export class Ad { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Ad.", }) public createdAt: Date; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The expired date of the Ad.", }) public expiresAt: Date; diff --git a/packages/backend/src/models/entities/announcement-read.ts b/packages/backend/src/models/entities/announcement-read.ts index 79af9e48e3..3adff38dab 100644 --- a/packages/backend/src/models/entities/announcement-read.ts +++ b/packages/backend/src/models/entities/announcement-read.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { Announcement } from "./announcement.js"; @@ -16,7 +17,7 @@ export class AnnouncementRead { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the AnnouncementRead.", }) public createdAt: Date; @@ -25,19 +26,21 @@ export class AnnouncementRead { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column(id()) public announcementId: Announcement["id"]; - @ManyToOne((type) => Announcement, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public announcement: Announcement | null; + public user: Relation; + + @ManyToOne(() => Announcement, { + onDelete: "CASCADE", + }) + @JoinColumn() + public announcement: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/announcement.ts b/packages/backend/src/models/entities/announcement.ts index 7872c0fe1c..cd6ae77bc4 100644 --- a/packages/backend/src/models/entities/announcement.ts +++ b/packages/backend/src/models/entities/announcement.ts @@ -7,12 +7,12 @@ export class Announcement { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Announcement.", }) public createdAt: Date; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The updated date of the Announcement.", nullable: true, }) diff --git a/packages/backend/src/models/entities/antenna.ts b/packages/backend/src/models/entities/antenna.ts index 633dcc1d27..7f3bea0be8 100644 --- a/packages/backend/src/models/entities/antenna.ts +++ b/packages/backend/src/models/entities/antenna.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -16,7 +17,7 @@ export class Antenna { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Antenna.", }) public createdAt: Date; @@ -28,12 +29,6 @@ export class Antenna { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 128, comment: "The name of the Antenna.", @@ -51,24 +46,12 @@ export class Antenna { }) public userListId: UserList["id"] | null; - @ManyToOne((type) => UserList, { - onDelete: "CASCADE", - }) - @JoinColumn() - public userList: UserList | null; - @Column({ ...id(), nullable: true, }) public userGroupJoiningId: UserGroupJoining["id"] | null; - @ManyToOne((type) => UserGroupJoining, { - onDelete: "CASCADE", - }) - @JoinColumn() - public userGroupJoining: UserGroupJoining | null; - @Column("varchar", { length: 1024, array: true, @@ -112,4 +95,27 @@ export class Antenna { @Column("boolean") public notify: boolean; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public user: Relation; + + @ManyToOne(() => UserList, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public userList: Relation; + + @ManyToOne(() => UserGroupJoining, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public userGroupJoining: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/app.ts b/packages/backend/src/models/entities/app.ts index a41e35aa91..cddfb18ee3 100644 --- a/packages/backend/src/models/entities/app.ts +++ b/packages/backend/src/models/entities/app.ts @@ -1,4 +1,11 @@ -import { Entity, PrimaryColumn, Column, Index, ManyToOne } from "typeorm"; +import { + Entity, + PrimaryColumn, + Column, + Index, + ManyToOne, + type Relation, +} from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -8,7 +15,7 @@ export class App { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the App.", }) public createdAt: Date; @@ -21,12 +28,6 @@ export class App { }) public userId: User["id"] | null; - @ManyToOne((type) => User, { - onDelete: "SET NULL", - nullable: true, - }) - public user: User | null; - @Index() @Column("varchar", { length: 64, @@ -59,4 +60,12 @@ export class App { comment: "The callbackUrl of the App.", }) public callbackUrl: string | null; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "SET NULL", + nullable: true, + }) + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/attestation-challenge.ts b/packages/backend/src/models/entities/attestation-challenge.ts index 6a3a9c8ed7..9121ef5368 100644 --- a/packages/backend/src/models/entities/attestation-challenge.ts +++ b/packages/backend/src/models/entities/attestation-challenge.ts @@ -5,6 +5,7 @@ import { Column, ManyToOne, Index, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -18,12 +19,6 @@ export class AttestationChallenge { @PrimaryColumn(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column("varchar", { length: 64, @@ -31,7 +26,7 @@ export class AttestationChallenge { }) public challenge: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The date challenge was created for expiry purposes.", }) public createdAt: Date; @@ -43,6 +38,14 @@ export class AttestationChallenge { }) public registrationChallenge: boolean; + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/auth-session.ts b/packages/backend/src/models/entities/auth-session.ts index b31dca56cf..9f86709889 100644 --- a/packages/backend/src/models/entities/auth-session.ts +++ b/packages/backend/src/models/entities/auth-session.ts @@ -5,6 +5,7 @@ import { Column, ManyToOne, JoinColumn, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { App } from "./app.js"; @@ -15,7 +16,7 @@ export class AuthSession { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the AuthSession.", }) public createdAt: Date; @@ -32,19 +33,20 @@ export class AuthSession { }) public userId: User["id"] | null; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - nullable: true, - }) - @JoinColumn() - public user: User | null; - @Column(id()) public appId: App["id"]; - @ManyToOne((type) => App, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public app: App | null; + public user: Relation; + + @ManyToOne(() => App, { + onDelete: "CASCADE", + }) + @JoinColumn() + public app: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/blocking.ts b/packages/backend/src/models/entities/blocking.ts index 55f677a981..b530834075 100644 --- a/packages/backend/src/models/entities/blocking.ts +++ b/packages/backend/src/models/entities/blocking.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -16,7 +17,7 @@ export class Blocking { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Blocking.", }) public createdAt: Date; @@ -28,12 +29,6 @@ export class Blocking { }) public blockeeId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public blockee: User | null; - @Index() @Column({ ...id(), @@ -41,9 +36,17 @@ export class Blocking { }) public blockerId: User["id"]; - @ManyToOne((type) => User, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public blocker: User | null; + public blockee: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public blocker: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/channel-following.ts b/packages/backend/src/models/entities/channel-following.ts index ee329fa50f..7314366636 100644 --- a/packages/backend/src/models/entities/channel-following.ts +++ b/packages/backend/src/models/entities/channel-following.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -17,7 +18,7 @@ export class ChannelFollowing { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the ChannelFollowing.", }) public createdAt: Date; @@ -29,12 +30,6 @@ export class ChannelFollowing { }) public followeeId: Channel["id"]; - @ManyToOne((type) => Channel, { - onDelete: "CASCADE", - }) - @JoinColumn() - public followee: Channel | null; - @Index() @Column({ ...id(), @@ -42,9 +37,17 @@ export class ChannelFollowing { }) public followerId: User["id"]; - @ManyToOne((type) => User, { + //#region Relations + @ManyToOne(() => Channel, { onDelete: "CASCADE", }) @JoinColumn() - public follower: User | null; + public followee: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public follower: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/channel-note-pining.ts b/packages/backend/src/models/entities/channel-note-pining.ts index 67d1d48ccd..7061b83504 100644 --- a/packages/backend/src/models/entities/channel-note-pining.ts +++ b/packages/backend/src/models/entities/channel-note-pining.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { Note } from "./note.js"; import { Channel } from "./channel.js"; @@ -16,7 +17,7 @@ export class ChannelNotePining { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the ChannelNotePining.", }) public createdAt: Date; @@ -25,18 +26,20 @@ export class ChannelNotePining { @Column(id()) public channelId: Channel["id"]; - @ManyToOne((type) => Channel, { - onDelete: "CASCADE", - }) - @JoinColumn() - public channel: Channel | null; - @Column(id()) public noteId: Note["id"]; - @ManyToOne((type) => Note, { + //#region Relations + @ManyToOne(() => Channel, { onDelete: "CASCADE", }) @JoinColumn() - public note: Note | null; + public channel: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/channel.ts b/packages/backend/src/models/entities/channel.ts index ea22fed50b..99cd3d283f 100644 --- a/packages/backend/src/models/entities/channel.ts +++ b/packages/backend/src/models/entities/channel.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -16,13 +17,13 @@ export class Channel { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Channel.", }) public createdAt: Date; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public lastNotedAt: Date | null; @@ -35,12 +36,6 @@ export class Channel { }) public userId: User["id"] | null; - @ManyToOne((type) => User, { - onDelete: "SET NULL", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 128, comment: "The name of the Channel.", @@ -61,12 +56,6 @@ export class Channel { }) public bannerId: DriveFile["id"] | null; - @ManyToOne((type) => DriveFile, { - onDelete: "SET NULL", - }) - @JoinColumn() - public banner: DriveFile | null; - @Index() @Column("integer", { default: 0, @@ -80,4 +69,18 @@ export class Channel { comment: "The count of users.", }) public usersCount: number; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "SET NULL", + }) + @JoinColumn() + public user: Relation; + + @ManyToOne(() => DriveFile, { + onDelete: "SET NULL", + }) + @JoinColumn() + public banner: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/clip-note.ts b/packages/backend/src/models/entities/clip-note.ts index 1697474a84..b54820a442 100644 --- a/packages/backend/src/models/entities/clip-note.ts +++ b/packages/backend/src/models/entities/clip-note.ts @@ -5,6 +5,7 @@ import { Column, ManyToOne, PrimaryColumn, + type Relation, } from "typeorm"; import { Note } from "./note.js"; import { Clip } from "./clip.js"; @@ -23,12 +24,6 @@ export class ClipNote { }) public noteId: Note["id"]; - @ManyToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note: Note | null; - @Index() @Column({ ...id(), @@ -36,9 +31,17 @@ export class ClipNote { }) public clipId: Clip["id"]; - @ManyToOne((type) => Clip, { + //#region Relations + @ManyToOne(() => Note, { onDelete: "CASCADE", }) @JoinColumn() - public clip: Clip | null; + public note: Relation; + + @ManyToOne(() => Clip, { + onDelete: "CASCADE", + }) + @JoinColumn() + public clip: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/clip.ts b/packages/backend/src/models/entities/clip.ts index 9554703a4c..389d008f74 100644 --- a/packages/backend/src/models/entities/clip.ts +++ b/packages/backend/src/models/entities/clip.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -14,7 +15,7 @@ export class Clip { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Clip.", }) public createdAt: Date; @@ -26,12 +27,6 @@ export class Clip { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 128, comment: "The name of the Clip.", @@ -49,4 +44,12 @@ export class Clip { comment: "The description of the Clip.", }) public description: string | null; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/drive-file.ts b/packages/backend/src/models/entities/drive-file.ts index 3c4510b533..81f564115f 100644 --- a/packages/backend/src/models/entities/drive-file.ts +++ b/packages/backend/src/models/entities/drive-file.ts @@ -16,6 +16,8 @@ import { DriveFolder } from "./drive-folder.js"; import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js"; import { NoteFile } from "./note-file.js"; +export type DriveFileUsageHint = "userAvatar" | "userBanner" | null; + @Entity() @Index(["userId", "folderId", "id"]) export class DriveFile { @@ -23,7 +25,7 @@ export class DriveFile { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the DriveFile.", }) public createdAt: Date; @@ -177,6 +179,14 @@ export class DriveFile { }) public isSensitive: boolean; + // Hint for what this file is used for + @Column({ + type: "enum", + enum: ["userAvatar", "userBanner"], + nullable: true, + }) + public usageHint: DriveFileUsageHint; + /** * 外部の(信頼されていない)URLへの直リンクか否か */ @@ -214,12 +224,14 @@ export class DriveFile { @ManyToOne(() => User, { onDelete: "SET NULL", + nullable: true, }) @JoinColumn() public user: User | null; @ManyToOne(() => DriveFolder, { onDelete: "SET NULL", + nullable: true, }) @JoinColumn() public folder: DriveFolder | null; diff --git a/packages/backend/src/models/entities/drive-folder.ts b/packages/backend/src/models/entities/drive-folder.ts index 0bb2c7a3d2..17580f3c8d 100644 --- a/packages/backend/src/models/entities/drive-folder.ts +++ b/packages/backend/src/models/entities/drive-folder.ts @@ -5,6 +5,7 @@ import { PrimaryColumn, Index, Column, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -15,7 +16,7 @@ export class DriveFolder { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the DriveFolder.", }) public createdAt: Date; @@ -34,12 +35,6 @@ export class DriveFolder { }) public userId: User["id"] | null; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column({ ...id(), @@ -49,9 +44,19 @@ export class DriveFolder { }) public parentId: DriveFolder["id"] | null; - @ManyToOne((type) => DriveFolder, { - onDelete: "SET NULL", + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + nullable: true, }) @JoinColumn() - public parent: DriveFolder | null; + public user: Relation; + + @ManyToOne(() => DriveFolder, { + onDelete: "SET NULL", + nullable: true, + }) + @JoinColumn() + public parent: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/emoji.ts b/packages/backend/src/models/entities/emoji.ts index 87b525dc59..1f40052389 100644 --- a/packages/backend/src/models/entities/emoji.ts +++ b/packages/backend/src/models/entities/emoji.ts @@ -7,7 +7,7 @@ export class Emoji { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public updatedAt: Date | null; diff --git a/packages/backend/src/models/entities/follow-request.ts b/packages/backend/src/models/entities/follow-request.ts index 281eab9174..1631d8c965 100644 --- a/packages/backend/src/models/entities/follow-request.ts +++ b/packages/backend/src/models/entities/follow-request.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -15,7 +16,7 @@ export class FollowRequest { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the FollowRequest.", }) public createdAt: Date; @@ -27,12 +28,6 @@ export class FollowRequest { }) public followeeId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public followee: User | null; - @Index() @Column({ ...id(), @@ -40,12 +35,6 @@ export class FollowRequest { }) public followerId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public follower: User | null; - @Column("varchar", { length: 128, nullable: true, @@ -96,4 +85,18 @@ export class FollowRequest { }) public followeeSharedInbox: string | null; //#endregion + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public followee: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public follower: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/following.ts b/packages/backend/src/models/entities/following.ts index ea8f325650..855b9f1745 100644 --- a/packages/backend/src/models/entities/following.ts +++ b/packages/backend/src/models/entities/following.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -16,7 +17,7 @@ export class Following { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Following.", }) public createdAt: Date; @@ -28,12 +29,6 @@ export class Following { }) public followeeId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public followee: User | null; - @Index() @Column({ ...id(), @@ -41,12 +36,6 @@ export class Following { }) public followerId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public follower: User | null; - //#region Denormalized fields @Index() @Column("varchar", { @@ -92,4 +81,18 @@ export class Following { }) public followeeSharedInbox: string | null; //#endregion + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public followee: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public follower: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/gallery-like.ts b/packages/backend/src/models/entities/gallery-like.ts index 259feb8bbb..f8ec098f68 100644 --- a/packages/backend/src/models/entities/gallery-like.ts +++ b/packages/backend/src/models/entities/gallery-like.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -16,25 +17,27 @@ export class GalleryLike { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone") + @Column("timestamp without time zone") public createdAt: Date; @Index() @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column(id()) public postId: GalleryPost["id"]; - @ManyToOne((type) => GalleryPost, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public post: GalleryPost | null; + public user: Relation; + + @ManyToOne(() => GalleryPost, { + onDelete: "CASCADE", + }) + @JoinColumn() + public post: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/gallery-post.ts b/packages/backend/src/models/entities/gallery-post.ts index 938348659d..711e7a7860 100644 --- a/packages/backend/src/models/entities/gallery-post.ts +++ b/packages/backend/src/models/entities/gallery-post.ts @@ -5,6 +5,7 @@ import { Column, PrimaryColumn, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -16,13 +17,13 @@ export class GalleryPost { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the GalleryPost.", }) public createdAt: Date; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The updated date of the GalleryPost.", }) public updatedAt: Date; @@ -45,12 +46,6 @@ export class GalleryPost { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column({ ...id(), @@ -80,6 +75,14 @@ export class GalleryPost { }) public tags: string[]; + //#region Relations + @ManyToOne((type) => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/instance.ts b/packages/backend/src/models/entities/instance.ts index 7b7701d07d..afdedd2d3f 100644 --- a/packages/backend/src/models/entities/instance.ts +++ b/packages/backend/src/models/entities/instance.ts @@ -1,6 +1,19 @@ import { Entity, PrimaryColumn, Index, Column } from "typeorm"; import { id } from "../id.js"; +export const MAX_LENGTH_INSTANCE = { + host: 512, + softwareName: 64, + softwareVersion: 64, + name: 256, + description: 4096, + maintainerName: 128, + maintainerEmail: 256, + iconUrl: 4096, + faviconUrl: 4096, + themeColor: 64, +}; + @Entity() export class Instance { @PrimaryColumn(id()) @@ -10,7 +23,7 @@ export class Instance { * このインスタンスを捕捉した日時 */ @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The caught date of the Instance.", }) public caughtAt: Date; @@ -20,7 +33,7 @@ export class Instance { */ @Index({ unique: true }) @Column("varchar", { - length: 512, + length: MAX_LENGTH_INSTANCE.host, comment: "The host of the Instance.", }) public host: string; @@ -62,7 +75,7 @@ export class Instance { /** * 直近のリクエスト送信日時 */ - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public latestRequestSentAt: Date | null; @@ -78,7 +91,7 @@ export class Instance { /** * 直近のリクエスト受信日時 */ - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public latestRequestReceivedAt: Date | null; @@ -86,7 +99,7 @@ export class Instance { /** * このインスタンスと最後にやり取りした日時 */ - @Column("timestamp with time zone") + @Column("timestamp without time zone") public lastCommunicatedAt: Date; /** @@ -107,14 +120,14 @@ export class Instance { public isSuspended: boolean; @Column("varchar", { - length: 64, + length: MAX_LENGTH_INSTANCE.softwareName, nullable: true, comment: "The software of the Instance.", }) public softwareName: string | null; @Column("varchar", { - length: 64, + length: MAX_LENGTH_INSTANCE.softwareVersion, nullable: true, }) public softwareVersion: string | null; @@ -125,48 +138,48 @@ export class Instance { public openRegistrations: boolean | null; @Column("varchar", { - length: 256, + length: MAX_LENGTH_INSTANCE.name, nullable: true, }) public name: string | null; @Column("varchar", { - length: 4096, + length: MAX_LENGTH_INSTANCE.description, nullable: true, }) public description: string | null; @Column("varchar", { - length: 128, + length: MAX_LENGTH_INSTANCE.maintainerName, nullable: true, }) public maintainerName: string | null; @Column("varchar", { - length: 256, + length: MAX_LENGTH_INSTANCE.maintainerEmail, nullable: true, }) public maintainerEmail: string | null; @Column("varchar", { - length: 4096, + length: MAX_LENGTH_INSTANCE.iconUrl, nullable: true, }) public iconUrl: string | null; @Column("varchar", { - length: 4096, + length: MAX_LENGTH_INSTANCE.faviconUrl, nullable: true, }) public faviconUrl: string | null; @Column("varchar", { - length: 64, + length: MAX_LENGTH_INSTANCE.themeColor, nullable: true, }) public themeColor: string | null; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public infoUpdatedAt: Date | null; diff --git a/packages/backend/src/models/entities/messaging-message.ts b/packages/backend/src/models/entities/messaging-message.ts index d1da00eaef..5c9c17a027 100644 --- a/packages/backend/src/models/entities/messaging-message.ts +++ b/packages/backend/src/models/entities/messaging-message.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { DriveFile } from "./drive-file.js"; @@ -17,7 +18,7 @@ export class MessagingMessage { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the MessagingMessage.", }) public createdAt: Date; @@ -29,12 +30,6 @@ export class MessagingMessage { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column({ ...id(), @@ -43,12 +38,6 @@ export class MessagingMessage { }) public recipientId: User["id"] | null; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public recipient: User | null; - @Index() @Column({ ...id(), @@ -57,12 +46,6 @@ export class MessagingMessage { }) public groupId: UserGroup["id"] | null; - @ManyToOne((type) => UserGroup, { - onDelete: "CASCADE", - }) - @JoinColumn() - public group: UserGroup | null; - @Column("varchar", { length: 4096, nullable: true, @@ -93,9 +76,31 @@ export class MessagingMessage { }) public fileId: DriveFile["id"] | null; - @ManyToOne((type) => DriveFile, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public file: DriveFile | null; + public user: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public recipient: Relation; + + @ManyToOne(() => UserGroup, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public group: Relation; + + @ManyToOne(() => DriveFile, { + onDelete: "SET NULL", + nullable: true, + }) + @JoinColumn() + public file: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index 286aa7f68f..5e267a8e24 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -1,4 +1,11 @@ -import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from "typeorm"; +import { + Entity, + Column, + PrimaryColumn, + ManyToOne, + JoinColumn, + type Relation, +} from "typeorm"; import { id } from "../id.js"; import { User } from "./user.js"; import type { Clip } from "./clip.js"; @@ -218,12 +225,6 @@ export class Meta { }) public proxyAccountId: User["id"] | null; - @ManyToOne((type) => User, { - onDelete: "SET NULL", - }) - @JoinColumn() - public proxyAccount: User | null; - @Column("boolean", { default: false, }) @@ -275,6 +276,12 @@ export class Meta { }) public remoteDriveCapacityMb: number; + @Column("integer", { + default: 5, + comment: "Antenna Limit", + }) + public antennaLimit: number; + @Column("varchar", { length: 128, nullable: true, @@ -500,4 +507,13 @@ export class Meta { nullable: true, }) public donationLink: string | null; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "SET NULL", + nullable: true, + }) + @JoinColumn() + public proxyAccount: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/moderation-log.ts b/packages/backend/src/models/entities/moderation-log.ts index 26bf1cdfa4..6eb3ec27ff 100644 --- a/packages/backend/src/models/entities/moderation-log.ts +++ b/packages/backend/src/models/entities/moderation-log.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -14,7 +15,7 @@ export class ModerationLog { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the ModerationLog.", }) public createdAt: Date; @@ -23,12 +24,6 @@ export class ModerationLog { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 128, }) @@ -36,4 +31,12 @@ export class ModerationLog { @Column("jsonb") public info: Record; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/muted-note.ts b/packages/backend/src/models/entities/muted-note.ts index 5c570c5a56..506b9ad81a 100644 --- a/packages/backend/src/models/entities/muted-note.ts +++ b/packages/backend/src/models/entities/muted-note.ts @@ -5,6 +5,7 @@ import { Column, ManyToOne, PrimaryColumn, + type Relation, } from "typeorm"; import { Note } from "./note.js"; import { User } from "./user.js"; @@ -24,12 +25,6 @@ export class MutedNote { }) public noteId: Note["id"]; - @ManyToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note: Note | null; - @Index() @Column({ ...id(), @@ -37,12 +32,6 @@ export class MutedNote { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - /** * ミュートされた理由。 */ @@ -52,4 +41,18 @@ export class MutedNote { comment: "The reason of the MutedNote.", }) public reason: (typeof mutedNoteReasons)[number]; + + //#region Relations + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/muting.ts b/packages/backend/src/models/entities/muting.ts index 603619b468..dd6ee0bf44 100644 --- a/packages/backend/src/models/entities/muting.ts +++ b/packages/backend/src/models/entities/muting.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -16,13 +17,13 @@ export class Muting { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Muting.", }) public createdAt: Date; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public expiresAt: Date | null; @@ -34,12 +35,6 @@ export class Muting { }) public muteeId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public mutee: User | null; - @Index() @Column({ ...id(), @@ -47,9 +42,17 @@ export class Muting { }) public muterId: User["id"]; - @ManyToOne((type) => User, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public muter: User | null; + public mutee: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public muter: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/note-edit.ts b/packages/backend/src/models/entities/note-edit.ts index 8761e2b153..aed85c7614 100644 --- a/packages/backend/src/models/entities/note-edit.ts +++ b/packages/backend/src/models/entities/note-edit.ts @@ -8,7 +8,7 @@ import { } from "typeorm"; import { Note } from "./note.js"; import { id } from "../id.js"; -import { DriveFile } from "./drive-file.js"; +import type { DriveFile } from "./drive-file.js"; @Entity() export class NoteEdit { @@ -22,12 +22,6 @@ export class NoteEdit { }) public noteId: Note["id"]; - @ManyToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note: Note | null; - @Column("text", { nullable: true, }) @@ -46,8 +40,23 @@ export class NoteEdit { }) public fileIds: DriveFile["id"][]; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The updated date of the Note.", }) public updatedAt: Date; + + @Column("varchar", { + length: 128, + array: true, + default: "{}", + }) + public emojis: string[]; + + //#region Relations + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Note; + //#endregion } diff --git a/packages/backend/src/models/entities/note-favorite.ts b/packages/backend/src/models/entities/note-favorite.ts index 19641ecf45..200655e929 100644 --- a/packages/backend/src/models/entities/note-favorite.ts +++ b/packages/backend/src/models/entities/note-favorite.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { Note } from "./note.js"; import { User } from "./user.js"; @@ -16,7 +17,7 @@ export class NoteFavorite { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the NoteFavorite.", }) public createdAt: Date; @@ -25,18 +26,20 @@ export class NoteFavorite { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column(id()) public noteId: Note["id"]; - @ManyToOne((type) => Note, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public note: Note | null; + public user: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/note-reaction.ts b/packages/backend/src/models/entities/note-reaction.ts index 5e2a8d3e89..fc57bb6a07 100644 --- a/packages/backend/src/models/entities/note-reaction.ts +++ b/packages/backend/src/models/entities/note-reaction.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { Note } from "./note.js"; @@ -17,7 +18,7 @@ export class NoteReaction { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the NoteReaction.", }) public createdAt: Date; @@ -26,26 +27,28 @@ export class NoteReaction { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user?: User | null; - @Index() @Column(id()) public noteId: Note["id"]; - @ManyToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note?: Note | null; - // TODO: 対象noteのuserIdを非正規化したい(「受け取ったリアクション一覧」のようなものを(JOIN無しで)実装したいため) @Column("varchar", { length: 260, }) public reaction: string; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/note-thread-muting.ts b/packages/backend/src/models/entities/note-thread-muting.ts index 7e5fad59a4..9566d6d89f 100644 --- a/packages/backend/src/models/entities/note-thread-muting.ts +++ b/packages/backend/src/models/entities/note-thread-muting.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -15,7 +16,7 @@ export class NoteThreadMuting { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", {}) + @Column("timestamp without time zone", {}) public createdAt: Date; @Index() @@ -24,15 +25,17 @@ export class NoteThreadMuting { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column("varchar", { length: 256, }) public threadId: string; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/note-unread.ts b/packages/backend/src/models/entities/note-unread.ts index 95695cbc8e..4ab24dfd51 100644 --- a/packages/backend/src/models/entities/note-unread.ts +++ b/packages/backend/src/models/entities/note-unread.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { Note } from "./note.js"; @@ -21,22 +22,10 @@ export class NoteUnread { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column(id()) public noteId: Note["id"]; - @ManyToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note: Note | null; - /** * メンションか否か */ @@ -67,4 +56,18 @@ export class NoteUnread { }) public noteChannelId: Channel["id"] | null; //#endregion + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/note-watching.ts b/packages/backend/src/models/entities/note-watching.ts index 724b084af2..37b48b75b8 100644 --- a/packages/backend/src/models/entities/note-watching.ts +++ b/packages/backend/src/models/entities/note-watching.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { Note } from "./note.js"; @@ -17,7 +18,7 @@ export class NoteWatching { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the NoteWatching.", }) public createdAt: Date; @@ -29,12 +30,6 @@ export class NoteWatching { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column({ ...id(), @@ -42,12 +37,6 @@ export class NoteWatching { }) public noteId: Note["id"]; - @ManyToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note: Note | null; - //#region Denormalized fields @Index() @Column({ @@ -56,4 +45,18 @@ export class NoteWatching { }) public noteUserId: Note["userId"]; //#endregion + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/note.ts b/packages/backend/src/models/entities/note.ts index 613fb7b11a..94cd8c7b66 100644 --- a/packages/backend/src/models/entities/note.ts +++ b/packages/backend/src/models/entities/note.ts @@ -26,7 +26,7 @@ export class Note { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Note.", }) public createdAt: Date; @@ -72,9 +72,8 @@ export class Note { }) public name: string | null; - @Index() // USING pgroonga pgroonga_varchar_full_text_search_ops_v2 - @Column("varchar", { - length: 512, + @Index() // USING pgroonga + @Column("text", { nullable: true, }) public cw: string | null; @@ -206,55 +205,6 @@ export class Note { }) public channelId: Channel["id"] | null; - //#region Relations - @OneToMany( - () => NoteFile, - (noteFile: NoteFile) => noteFile.note, - ) - public noteFiles: Relation; - - @ManyToMany( - () => DriveFile, - (file: DriveFile) => file.notes, - ) - @JoinTable({ - name: "note_file", - joinColumn: { - name: "noteId", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "fileId", - referencedColumnName: "id", - }, - }) - public files: Relation; - - @ManyToOne(() => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public reply: Note | null; - - @ManyToOne(() => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public renote: Note | null; - - @ManyToOne(() => Channel, { - onDelete: "CASCADE", - }) - @JoinColumn() - public channel: Channel | null; - - @ManyToOne(() => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - //#endregion Relations - //#region Denormalized fields @Index() @Column("varchar", { @@ -292,13 +242,66 @@ export class Note { }) public renoteUserHost: string | null; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, comment: "The updated date of the Note.", }) public updatedAt: Date | null; //#endregion + //#region Relations + @OneToMany( + () => NoteFile, + (noteFile: NoteFile) => noteFile.note, + ) + public noteFiles: Relation; + + @ManyToMany( + () => DriveFile, + (file: DriveFile) => file.notes, + ) + @JoinTable({ + name: "note_file", + joinColumn: { + name: "noteId", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "fileId", + referencedColumnName: "id", + }, + }) + public files: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public reply: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public renote: Relation; + + @ManyToOne(() => Channel, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public channel: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public user: Relation; + //#endregion Relations + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/notification.ts b/packages/backend/src/models/entities/notification.ts index 425cd55700..58fc86a72c 100644 --- a/packages/backend/src/models/entities/notification.ts +++ b/packages/backend/src/models/entities/notification.ts @@ -5,6 +5,7 @@ import { ManyToOne, Column, PrimaryColumn, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -20,7 +21,7 @@ export class Notification { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Notification.", }) public createdAt: Date; @@ -35,12 +36,6 @@ export class Notification { }) public notifieeId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public notifiee: User | null; - /** * Notification sender (initiator) */ @@ -52,12 +47,6 @@ export class Notification { }) public notifierId: User["id"] | null; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public notifier: User | null; - /** * Notification types: * follow - Follow request @@ -96,36 +85,18 @@ export class Notification { }) public noteId: Note["id"] | null; - @ManyToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note: Note | null; - @Column({ ...id(), nullable: true, }) public followRequestId: FollowRequest["id"] | null; - @ManyToOne((type) => FollowRequest, { - onDelete: "CASCADE", - }) - @JoinColumn() - public followRequest: FollowRequest | null; - @Column({ ...id(), nullable: true, }) public userGroupInvitationId: UserGroupInvitation["id"] | null; - @ManyToOne((type) => UserGroupInvitation, { - onDelete: "CASCADE", - }) - @JoinColumn() - public userGroupInvitation: UserGroupInvitation | null; - @Column("varchar", { length: 128, nullable: true, @@ -176,9 +147,46 @@ export class Notification { }) public appAccessTokenId: AccessToken["id"] | null; - @ManyToOne((type) => AccessToken, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public appAccessToken: AccessToken | null; + public notifiee: Relation; + + @ManyToOne(() => User, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public notifier: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public note: Relation; + + @ManyToOne(() => FollowRequest, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public followRequest: Relation; + + @ManyToOne(() => UserGroupInvitation, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public userGroupInvitation: Relation; + + @ManyToOne(() => AccessToken, { + onDelete: "CASCADE", + nullable: true, + }) + @JoinColumn() + public appAccessToken: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/page-like.ts b/packages/backend/src/models/entities/page-like.ts index 6304e0b24c..fba142375d 100644 --- a/packages/backend/src/models/entities/page-like.ts +++ b/packages/backend/src/models/entities/page-like.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -16,25 +17,27 @@ export class PageLike { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone") + @Column("timestamp without time zone") public createdAt: Date; @Index() @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column(id()) public pageId: Page["id"]; - @ManyToOne((type) => Page, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public page: Page | null; + public user: Relation; + + @ManyToOne(() => Page, { + onDelete: "CASCADE", + }) + @JoinColumn() + public page: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/page.ts b/packages/backend/src/models/entities/page.ts index d0733c8ce4..af8e095dd5 100644 --- a/packages/backend/src/models/entities/page.ts +++ b/packages/backend/src/models/entities/page.ts @@ -5,6 +5,7 @@ import { Column, PrimaryColumn, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -17,13 +18,13 @@ export class Page { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Page.", }) public createdAt: Date; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The updated date of the Page.", }) public updatedAt: Date; @@ -68,24 +69,12 @@ export class Page { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column({ ...id(), nullable: true, }) public eyeCatchingImageId: DriveFile["id"] | null; - @ManyToOne((type) => DriveFile, { - onDelete: "CASCADE", - }) - @JoinColumn() - public eyeCatchingImage: DriveFile | null; - @Column("jsonb", { default: [], }) @@ -123,6 +112,20 @@ export class Page { }) public likedCount: number; + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + + @ManyToOne(() => DriveFile, { + onDelete: "CASCADE", // TODO: this should be SET NULL + }) + @JoinColumn() + public eyeCatchingImage: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/password-reset-request.ts b/packages/backend/src/models/entities/password-reset-request.ts index ab0bccbbef..23ec16e38b 100644 --- a/packages/backend/src/models/entities/password-reset-request.ts +++ b/packages/backend/src/models/entities/password-reset-request.ts @@ -5,6 +5,7 @@ import { Column, ManyToOne, JoinColumn, + type Relation, } from "typeorm"; import { id } from "../id.js"; import { User } from "./user.js"; @@ -14,7 +15,7 @@ export class PasswordResetRequest { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone") + @Column("timestamp without time zone") public createdAt: Date; @Index({ unique: true }) @@ -29,9 +30,11 @@ export class PasswordResetRequest { }) public userId: User["id"]; - @ManyToOne((type) => User, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public user: User | null; + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/poll-vote.ts b/packages/backend/src/models/entities/poll-vote.ts index d59a720c37..7b9cc19c3c 100644 --- a/packages/backend/src/models/entities/poll-vote.ts +++ b/packages/backend/src/models/entities/poll-vote.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { Note } from "./note.js"; @@ -17,7 +18,7 @@ export class PollVote { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the PollVote.", }) public createdAt: Date; @@ -26,22 +27,24 @@ export class PollVote { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column(id()) public noteId: Note["id"]; - @ManyToOne((type) => Note, { + @Column("integer") + public choice: number; + + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public note: Note | null; + public user: Relation; - @Column("integer") - public choice: number; + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/poll.ts b/packages/backend/src/models/entities/poll.ts index f84e5fb8f6..3cc6df17cf 100644 --- a/packages/backend/src/models/entities/poll.ts +++ b/packages/backend/src/models/entities/poll.ts @@ -5,24 +5,19 @@ import { JoinColumn, Column, OneToOne, + type Relation, } from "typeorm"; import { id } from "../id.js"; import { Note } from "./note.js"; import type { User } from "./user.js"; -import { noteVisibilities } from "../../types.js"; +import { noteVisibilities } from "@/types.js"; @Entity() export class Poll { @PrimaryColumn(id()) public noteId: Note["id"]; - @OneToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note: Note | null; - - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public expiresAt: Date | null; @@ -65,6 +60,14 @@ export class Poll { public userHost: string | null; //#endregion + //#region Relations + @OneToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/promo-note.ts b/packages/backend/src/models/entities/promo-note.ts index caa64927e9..18ff3ac63c 100644 --- a/packages/backend/src/models/entities/promo-note.ts +++ b/packages/backend/src/models/entities/promo-note.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, OneToOne, + type Relation, } from "typeorm"; import { Note } from "./note.js"; import type { User } from "./user.js"; @@ -15,13 +16,7 @@ export class PromoNote { @PrimaryColumn(id()) public noteId: Note["id"]; - @OneToOne((type) => Note, { - onDelete: "CASCADE", - }) - @JoinColumn() - public note: Note | null; - - @Column("timestamp with time zone") + @Column("timestamp without time zone") public expiresAt: Date; //#region Denormalized fields @@ -32,4 +27,12 @@ export class PromoNote { }) public userId: User["id"]; //#endregion + + //#region Relations + @OneToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/promo-read.ts b/packages/backend/src/models/entities/promo-read.ts index b31877dc34..efda0757c6 100644 --- a/packages/backend/src/models/entities/promo-read.ts +++ b/packages/backend/src/models/entities/promo-read.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { Note } from "./note.js"; import { User } from "./user.js"; @@ -16,7 +17,7 @@ export class PromoRead { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the PromoRead.", }) public createdAt: Date; @@ -25,18 +26,20 @@ export class PromoRead { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column(id()) public noteId: Note["id"]; - @ManyToOne((type) => Note, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public note: Note | null; + public user: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/registration-tickets.ts b/packages/backend/src/models/entities/registration-tickets.ts index 549f05d07a..db0a416550 100644 --- a/packages/backend/src/models/entities/registration-tickets.ts +++ b/packages/backend/src/models/entities/registration-tickets.ts @@ -6,7 +6,7 @@ export class RegistrationTicket { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone") + @Column("timestamp without time zone") public createdAt: Date; @Index({ unique: true }) diff --git a/packages/backend/src/models/entities/registry-item.ts b/packages/backend/src/models/entities/registry-item.ts index d044222e6e..e9e54b7122 100644 --- a/packages/backend/src/models/entities/registry-item.ts +++ b/packages/backend/src/models/entities/registry-item.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -15,12 +16,12 @@ export class RegistryItem { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the RegistryItem.", }) public createdAt: Date; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The updated date of the RegistryItem.", }) public updatedAt: Date; @@ -32,12 +33,6 @@ export class RegistryItem { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 1024, comment: "The key of the RegistryItem.", @@ -66,4 +61,12 @@ export class RegistryItem { nullable: true, }) public domain: string | null; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/renote-muting.ts b/packages/backend/src/models/entities/renote-muting.ts index e8856492f1..42cb14127b 100644 --- a/packages/backend/src/models/entities/renote-muting.ts +++ b/packages/backend/src/models/entities/renote-muting.ts @@ -2,12 +2,13 @@ import { PrimaryColumn, Entity, Index, - JoinColumn, + // JoinColumn, Column, - ManyToOne, + // ManyToOne, + // type Relation, } from "typeorm"; import { id } from "../id.js"; -import { User } from "./user.js"; +import type { User } from "./user.js"; @Entity() @Index(["muterId", "muteeId"], { unique: true }) @@ -16,7 +17,7 @@ export class RenoteMuting { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Muting.", }) public createdAt: Date; @@ -28,12 +29,6 @@ export class RenoteMuting { }) public muteeId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public mutee: User | null; - @Index() @Column({ ...id(), @@ -41,9 +36,19 @@ export class RenoteMuting { }) public muterId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public muter: User | null; + //#region Relations + /* FIXME: There is no such relation */ + // @ManyToOne(() => User, { + // onDelete: "CASCADE", + // }) + // @JoinColumn() + // public mutee: Relation; + + /* FIXME: There is no such relation */ + // @ManyToOne(() => User, { + // onDelete: "CASCADE", + // }) + // @JoinColumn() + // public muter: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/reply-muting.ts b/packages/backend/src/models/entities/reply-muting.ts index 19c2418fae..e48463e683 100644 --- a/packages/backend/src/models/entities/reply-muting.ts +++ b/packages/backend/src/models/entities/reply-muting.ts @@ -2,12 +2,13 @@ import { PrimaryColumn, Entity, Index, - JoinColumn, + // JoinColumn, Column, - ManyToOne, + // ManyToOne, + // type Relation, } from "typeorm"; import { id } from "../id.js"; -import { User } from "./user.js"; +import type { User } from "./user.js"; @Entity() @Index(["muterId", "muteeId"], { unique: true }) @@ -16,7 +17,7 @@ export class ReplyMuting { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Muting.", }) public createdAt: Date; @@ -28,12 +29,6 @@ export class ReplyMuting { }) public muteeId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public mutee: User | null; - @Index() @Column({ ...id(), @@ -41,9 +36,19 @@ export class ReplyMuting { }) public muterId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public muter: User | null; + //#region Relations + /* FIXME: There is no such relation */ + // @ManyToOne(() => User, { + // onDelete: "CASCADE", + // }) + // @JoinColumn() + // public mutee: Relation; + + /* FIXME: There is no such relation */ + // @ManyToOne(() => User, { + // onDelete: "CASCADE", + // }) + // @JoinColumn() + // public muter: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/signin.ts b/packages/backend/src/models/entities/signin.ts index 517e71c8fd..89d50a6b5f 100644 --- a/packages/backend/src/models/entities/signin.ts +++ b/packages/backend/src/models/entities/signin.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -14,7 +15,7 @@ export class Signin { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Signin.", }) public createdAt: Date; @@ -23,12 +24,6 @@ export class Signin { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 128, }) @@ -39,4 +34,12 @@ export class Signin { @Column("boolean") public success: boolean; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/sw-subscription.ts b/packages/backend/src/models/entities/sw-subscription.ts index f7823fbaaa..a4a6ae7711 100644 --- a/packages/backend/src/models/entities/sw-subscription.ts +++ b/packages/backend/src/models/entities/sw-subscription.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -14,19 +15,13 @@ export class SwSubscription { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone") + @Column("timestamp without time zone") public createdAt: Date; @Index() @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 512, }) @@ -46,4 +41,12 @@ export class SwSubscription { default: false, }) public sendReadMessage: boolean; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/used-username.ts b/packages/backend/src/models/entities/used-username.ts index d00a25991e..4504301b14 100644 --- a/packages/backend/src/models/entities/used-username.ts +++ b/packages/backend/src/models/entities/used-username.ts @@ -7,7 +7,7 @@ export class UsedUsername { }) public username: string; - @Column("timestamp with time zone") + @Column("timestamp without time zone") public createdAt: Date; constructor(data: Partial) { diff --git a/packages/backend/src/models/entities/user-group-invitation.ts b/packages/backend/src/models/entities/user-group-invitation.ts index fa2655ab67..be34fdc757 100644 --- a/packages/backend/src/models/entities/user-group-invitation.ts +++ b/packages/backend/src/models/entities/user-group-invitation.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { UserGroup } from "./user-group.js"; @@ -16,7 +17,7 @@ export class UserGroupInvitation { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the UserGroupInvitation.", }) public createdAt: Date; @@ -28,12 +29,6 @@ export class UserGroupInvitation { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column({ ...id(), @@ -41,9 +36,17 @@ export class UserGroupInvitation { }) public userGroupId: UserGroup["id"]; - @ManyToOne((type) => UserGroup, { + //#region Relation + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public userGroup: UserGroup | null; + public user: Relation; + + @ManyToOne(() => UserGroup, { + onDelete: "CASCADE", + }) + @JoinColumn() + public userGroup: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/user-group-joining.ts b/packages/backend/src/models/entities/user-group-joining.ts index 78f820d0e8..d7af03bf8f 100644 --- a/packages/backend/src/models/entities/user-group-joining.ts +++ b/packages/backend/src/models/entities/user-group-joining.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { UserGroup } from "./user-group.js"; @@ -16,7 +17,7 @@ export class UserGroupJoining { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the UserGroupJoining.", }) public createdAt: Date; @@ -28,12 +29,6 @@ export class UserGroupJoining { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column({ ...id(), @@ -41,9 +36,17 @@ export class UserGroupJoining { }) public userGroupId: UserGroup["id"]; - @ManyToOne((type) => UserGroup, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public userGroup: UserGroup | null; + public user: Relation; + + @ManyToOne(() => UserGroup, { + onDelete: "CASCADE", + }) + @JoinColumn() + public userGroup: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/user-group.ts b/packages/backend/src/models/entities/user-group.ts index 23876ec8b8..801b4e619f 100644 --- a/packages/backend/src/models/entities/user-group.ts +++ b/packages/backend/src/models/entities/user-group.ts @@ -5,6 +5,7 @@ import { Column, PrimaryColumn, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -15,7 +16,7 @@ export class UserGroup { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the UserGroup.", }) public createdAt: Date; @@ -32,17 +33,19 @@ export class UserGroup { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("boolean", { default: false, }) public isPrivate: boolean; + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/user-ip.ts b/packages/backend/src/models/entities/user-ip.ts index adef48e4c4..7c43816b66 100644 --- a/packages/backend/src/models/entities/user-ip.ts +++ b/packages/backend/src/models/entities/user-ip.ts @@ -8,7 +8,7 @@ export class UserIp { @PrimaryGeneratedColumn() public id: string; - @Column("timestamp with time zone", {}) + @Column("timestamp without time zone", {}) public createdAt: Date; @Index() diff --git a/packages/backend/src/models/entities/user-keypair.ts b/packages/backend/src/models/entities/user-keypair.ts index f98384f538..0c1b90c868 100644 --- a/packages/backend/src/models/entities/user-keypair.ts +++ b/packages/backend/src/models/entities/user-keypair.ts @@ -1,4 +1,11 @@ -import { PrimaryColumn, Entity, JoinColumn, Column, OneToOne } from "typeorm"; +import { + PrimaryColumn, + Entity, + JoinColumn, + Column, + OneToOne, + type Relation, +} from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -7,12 +14,6 @@ export class UserKeypair { @PrimaryColumn(id()) public userId: User["id"]; - @OneToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 4096, }) @@ -23,6 +24,14 @@ export class UserKeypair { }) public privateKey: string; + //#region Relations + @OneToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/user-list-joining.ts b/packages/backend/src/models/entities/user-list-joining.ts index 4caa71ad32..bd3ef8bde1 100644 --- a/packages/backend/src/models/entities/user-list-joining.ts +++ b/packages/backend/src/models/entities/user-list-joining.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { UserList } from "./user-list.js"; @@ -16,7 +17,7 @@ export class UserListJoining { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the UserListJoining.", }) public createdAt: Date; @@ -28,12 +29,6 @@ export class UserListJoining { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column({ ...id(), @@ -41,9 +36,17 @@ export class UserListJoining { }) public userListId: UserList["id"]; - @ManyToOne((type) => UserList, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public userList: UserList | null; + public user: Relation; + + @ManyToOne(() => UserList, { + onDelete: "CASCADE", + }) + @JoinColumn() + public userList: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/user-list.ts b/packages/backend/src/models/entities/user-list.ts index 3c95d44d6b..6f192c6bab 100644 --- a/packages/backend/src/models/entities/user-list.ts +++ b/packages/backend/src/models/entities/user-list.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -14,7 +15,7 @@ export class UserList { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the UserList.", }) public createdAt: Date; @@ -26,15 +27,17 @@ export class UserList { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 128, comment: "The name of the UserList.", }) public name: string; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/user-note-pining.ts b/packages/backend/src/models/entities/user-note-pining.ts index c30fe1e028..d262c3f5b3 100644 --- a/packages/backend/src/models/entities/user-note-pining.ts +++ b/packages/backend/src/models/entities/user-note-pining.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { Note } from "./note.js"; import { User } from "./user.js"; @@ -16,7 +17,7 @@ export class UserNotePining { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the UserNotePinings.", }) public createdAt: Date; @@ -25,18 +26,20 @@ export class UserNotePining { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column(id()) public noteId: Note["id"]; - @ManyToOne((type) => Note, { + //#region Relations + @ManyToOne(() => User, { onDelete: "CASCADE", }) @JoinColumn() - public note: Note | null; + public user: Relation; + + @ManyToOne(() => Note, { + onDelete: "CASCADE", + }) + @JoinColumn() + public note: Relation; + //#endregion } diff --git a/packages/backend/src/models/entities/user-pending.ts b/packages/backend/src/models/entities/user-pending.ts index 18ae5ad993..1383c4d4da 100644 --- a/packages/backend/src/models/entities/user-pending.ts +++ b/packages/backend/src/models/entities/user-pending.ts @@ -6,7 +6,7 @@ export class UserPending { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone") + @Column("timestamp without time zone") public createdAt: Date; @Index({ unique: true }) diff --git a/packages/backend/src/models/entities/user-profile.ts b/packages/backend/src/models/entities/user-profile.ts index 2a99d58226..2fe2b7a58a 100644 --- a/packages/backend/src/models/entities/user-profile.ts +++ b/packages/backend/src/models/entities/user-profile.ts @@ -5,6 +5,7 @@ import { OneToOne, JoinColumn, PrimaryColumn, + type Relation, } from "typeorm"; import { ffVisibility, notificationTypes } from "@/types.js"; import { id } from "../id.js"; @@ -18,12 +19,6 @@ export class UserProfile { @PrimaryColumn(id()) public userId: User["id"]; - @OneToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 128, nullable: true, @@ -246,6 +241,14 @@ export class UserProfile { public userHost: string | null; //#endregion + //#region Relations + @OneToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/user-publickey.ts b/packages/backend/src/models/entities/user-publickey.ts index e39b084d32..6ec46b0cca 100644 --- a/packages/backend/src/models/entities/user-publickey.ts +++ b/packages/backend/src/models/entities/user-publickey.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, OneToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -14,12 +15,6 @@ export class UserPublickey { @PrimaryColumn(id()) public userId: User["id"]; - @OneToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index({ unique: true }) @Column("varchar", { length: 512, @@ -31,6 +26,14 @@ export class UserPublickey { }) public keyPem: string; + //#region Relations + @OneToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/user-security-key.ts b/packages/backend/src/models/entities/user-security-key.ts index 511cab4ae4..b2853f0aa9 100644 --- a/packages/backend/src/models/entities/user-security-key.ts +++ b/packages/backend/src/models/entities/user-security-key.ts @@ -5,6 +5,7 @@ import { Column, ManyToOne, Index, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -20,12 +21,6 @@ export class UserSecurityKey { @Column(id()) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Index() @Column("varchar", { comment: @@ -33,7 +28,7 @@ export class UserSecurityKey { }) public publicKey: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The date of the last time the UserSecurityKey was successfully validated.", }) @@ -45,6 +40,14 @@ export class UserSecurityKey { }) public name: string; + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts index 6a2d3ee017..152acfedb7 100644 --- a/packages/backend/src/models/entities/user.ts +++ b/packages/backend/src/models/entities/user.ts @@ -5,6 +5,7 @@ import { OneToOne, JoinColumn, PrimaryColumn, + type Relation, } from "typeorm"; import { id } from "../id.js"; import { DriveFile } from "./drive-file.js"; @@ -18,25 +19,25 @@ export class User { public id: string; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the User.", }) public createdAt: Date; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, comment: "The updated date of the User.", }) public updatedAt: Date | null; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public lastFetchedAt: Date | null; @Index() - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public lastActiveDate: Date | null; @@ -106,12 +107,6 @@ export class User { }) public avatarId: DriveFile["id"] | null; - @OneToOne((type) => DriveFile, { - onDelete: "SET NULL", - }) - @JoinColumn() - public avatar: DriveFile | null; - @Column({ ...id(), nullable: true, @@ -119,12 +114,6 @@ export class User { }) public bannerId: DriveFile["id"] | null; - @OneToOne((type) => DriveFile, { - onDelete: "SET NULL", - }) - @JoinColumn() - public banner: DriveFile | null; - @Index() @Column("varchar", { length: 128, @@ -286,6 +275,22 @@ export class User { }) public isIndexable: boolean; + //#region Relations + @OneToOne(() => DriveFile, { + onDelete: "SET NULL", + nullable: true, + }) + @JoinColumn() + public avatar: Relation; + + @OneToOne(() => DriveFile, { + onDelete: "SET NULL", + nullable: true, + }) + @JoinColumn() + public banner: Relation; + //#endregion + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/entities/webhook.ts b/packages/backend/src/models/entities/webhook.ts index 9573390b36..bc48e537ae 100644 --- a/packages/backend/src/models/entities/webhook.ts +++ b/packages/backend/src/models/entities/webhook.ts @@ -5,6 +5,7 @@ import { JoinColumn, Column, ManyToOne, + type Relation, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -25,7 +26,7 @@ export class Webhook { @PrimaryColumn(id()) public id: string; - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { comment: "The created date of the Antenna.", }) public createdAt: Date; @@ -37,12 +38,6 @@ export class Webhook { }) public userId: User["id"]; - @ManyToOne((type) => User, { - onDelete: "CASCADE", - }) - @JoinColumn() - public user: User | null; - @Column("varchar", { length: 128, comment: "The name of the Antenna.", @@ -76,7 +71,7 @@ export class Webhook { /** * 直近のリクエスト送信日時 */ - @Column("timestamp with time zone", { + @Column("timestamp without time zone", { nullable: true, }) public latestSentAt: Date | null; @@ -88,4 +83,12 @@ export class Webhook { nullable: true, }) public latestStatus: number | null; + + //#region Relations + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + @JoinColumn() + public user: Relation; + //#endregion } diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts index 5d4ff52198..c578d9d409 100644 --- a/packages/backend/src/models/index.ts +++ b/packages/backend/src/models/index.ts @@ -65,14 +65,14 @@ import { UserPending } from "./entities/user-pending.js"; import { InstanceRepository } from "./repositories/instance.js"; import { Webhook } from "./entities/webhook.js"; import { UserIp } from "./entities/user-ip.js"; -import { NoteEdit } from "./entities/note-edit.js"; import { NoteFileRepository } from "./repositories/note-file.js"; +import { NoteEditRepository } from "./repositories/note-edit.js"; export const Announcements = db.getRepository(Announcement); export const AnnouncementReads = db.getRepository(AnnouncementRead); export const Apps = AppRepository; export const Notes = NoteRepository; -export const NoteEdits = db.getRepository(NoteEdit); +export const NoteEdits = NoteEditRepository; export const NoteFiles = NoteFileRepository; export const NoteFavorites = NoteFavoriteRepository; export const NoteWatchings = db.getRepository(NoteWatching); diff --git a/packages/backend/src/models/repositories/abuse-user-report.ts b/packages/backend/src/models/repositories/abuse-user-report.ts index 16ce159955..b8d953d052 100644 --- a/packages/backend/src/models/repositories/abuse-user-report.ts +++ b/packages/backend/src/models/repositories/abuse-user-report.ts @@ -2,6 +2,7 @@ import { db } from "@/db/postgre.js"; import { Users } from "../index.js"; import { AbuseUserReport } from "@/models/entities/abuse-user-report.js"; import { awaitAll } from "@/prelude/await-all.js"; +import type { Packed } from "@/misc/schema.js"; export const AbuseUserReportRepository = db .getRepository(AbuseUserReport) @@ -10,7 +11,7 @@ export const AbuseUserReportRepository = db const report = typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); - return await awaitAll({ + const packed: Packed<"AbuseUserReport"> = await awaitAll({ id: report.id, createdAt: report.createdAt.toISOString(), comment: report.comment, @@ -31,9 +32,10 @@ export const AbuseUserReportRepository = db : null, forwarded: report.forwarded, }); + return packed; }, - packMany(reports: any[]) { + packMany(reports: (AbuseUserReport["id"] | AbuseUserReport)[]) { return Promise.all(reports.map((x) => this.pack(x))); }, }); diff --git a/packages/backend/src/models/repositories/channel.ts b/packages/backend/src/models/repositories/channel.ts index 857470f4ec..809129db6c 100644 --- a/packages/backend/src/models/repositories/channel.ts +++ b/packages/backend/src/models/repositories/channel.ts @@ -40,6 +40,7 @@ export const ChannelRepository = db.getRepository(Channel).extend({ name: channel.name, description: channel.description, userId: channel.userId, + bannerId: channel.bannerId, bannerUrl: banner ? DriveFiles.getPublicUrl(banner, false) : null, usersCount: channel.usersCount, notesCount: channel.notesCount, diff --git a/packages/backend/src/models/repositories/drive-file.ts b/packages/backend/src/models/repositories/drive-file.ts index b550745c5b..18b139caff 100644 --- a/packages/backend/src/models/repositories/drive-file.ts +++ b/packages/backend/src/models/repositories/drive-file.ts @@ -1,7 +1,7 @@ import { db } from "@/db/postgre.js"; import { DriveFile } from "@/models/entities/drive-file.js"; import type { User } from "@/models/entities/user.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { toPuny } from "backend-rs"; import { awaitAll } from "@/prelude/await-all.js"; import type { Packed } from "@/misc/schema.js"; import config from "@/config/index.js"; @@ -152,6 +152,7 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({ md5: file.md5, size: file.size, isSensitive: file.isSensitive, + usageHint: file.usageHint, blurhash: file.blurhash, properties: opts.self ? file.properties : this.getPublicProperties(file), url: opts.self ? file.url : this.getPublicUrl(file, false), @@ -193,6 +194,7 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({ md5: file.md5, size: file.size, isSensitive: file.isSensitive, + usageHint: file.usageHint, blurhash: file.blurhash, properties: opts.self ? file.properties : this.getPublicProperties(file), url: opts.self ? file.url : this.getPublicUrl(file, false), diff --git a/packages/backend/src/models/repositories/gallery-post.ts b/packages/backend/src/models/repositories/gallery-post.ts index d91fb9de2a..c4078e9091 100644 --- a/packages/backend/src/models/repositories/gallery-post.ts +++ b/packages/backend/src/models/repositories/gallery-post.ts @@ -19,7 +19,9 @@ export const GalleryPostRepository = db.getRepository(GalleryPost).extend({ createdAt: post.createdAt.toISOString(), updatedAt: post.updatedAt.toISOString(), userId: post.userId, - user: Users.pack(post.user || post.userId, me), + user: Users.pack(post.user || post.userId, me, { + detail: true, + }), title: post.title, description: post.description, fileIds: post.fileIds, diff --git a/packages/backend/src/models/repositories/note-edit.ts b/packages/backend/src/models/repositories/note-edit.ts new file mode 100644 index 0000000000..210d489712 --- /dev/null +++ b/packages/backend/src/models/repositories/note-edit.ts @@ -0,0 +1,44 @@ +import { db } from "@/db/postgre.js"; +import { NoteEdit } from "@/models/entities/note-edit.js"; +import type { Note } from "@/models/entities/note.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { Packed } from "@/misc/schema.js"; +import { DriveFiles } from "../index.js"; +import { + aggregateNoteEditEmojis, + populateEmojis, + prefetchEmojis, +} from "@/misc/populate-emojis.js"; + +export const NoteEditRepository = db.getRepository(NoteEdit).extend({ + async pack(noteEdit: NoteEdit, sourceNote: Note) { + const packed: Packed<"NoteEdit"> = await awaitAll({ + id: noteEdit.id, + noteId: noteEdit.noteId, + updatedAt: noteEdit.updatedAt.toISOString(), + text: noteEdit.text, + cw: noteEdit.cw, + fileIds: noteEdit.fileIds, + files: DriveFiles.packMany(noteEdit.fileIds), + emojis: populateEmojis(noteEdit.emojis, sourceNote.userHost), + }); + + return packed; + }, + async packMany(noteEdits: NoteEdit[], sourceNote: Note) { + if (noteEdits.length === 0) return []; + + await prefetchEmojis( + aggregateNoteEditEmojis(noteEdits, sourceNote.userHost), + ); + + const promises = await Promise.allSettled( + noteEdits.map((n) => this.pack(n, sourceNote)), + ); + + // filter out rejected promises, only keep fulfilled values + return promises.flatMap((result) => + result.status === "fulfilled" ? [result.value] : [], + ); + }, +}); diff --git a/packages/backend/src/models/repositories/note-reaction.ts b/packages/backend/src/models/repositories/note-reaction.ts index 20aae2876f..47e16ced0c 100644 --- a/packages/backend/src/models/repositories/note-reaction.ts +++ b/packages/backend/src/models/repositories/note-reaction.ts @@ -2,7 +2,7 @@ import { db } from "@/db/postgre.js"; import { NoteReaction } from "@/models/entities/note-reaction.js"; import { Notes, Users } from "../index.js"; import type { Packed } from "@/misc/schema.js"; -import { decodeReaction } from "@/misc/reaction-lib.js"; +import { decodeReaction } from "backend-rs"; import type { User } from "@/models/entities/user.js"; export const NoteReactionRepository = db.getRepository(NoteReaction).extend({ diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index 2921f68be3..c877048709 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -12,9 +12,8 @@ import { Channels, } from "../index.js"; import type { Packed } from "@/misc/schema.js"; -import { nyaify } from "@/misc/nyaify.js"; +import { countReactions, decodeReaction, nyaify } from "backend-rs"; import { awaitAll } from "@/prelude/await-all.js"; -import { convertReactions, decodeReaction } from "@/misc/reaction-lib.js"; import type { NoteReaction } from "@/models/entities/note-reaction.js"; import { aggregateNoteEmojis, @@ -214,7 +213,7 @@ export const NoteRepository = db.getRepository(Note).extend({ note.visibility === "specified" ? note.visibleUserIds : undefined, renoteCount: note.renoteCount, repliesCount: note.repliesCount, - reactions: convertReactions(note.reactions), + reactions: countReactions(note.reactions), reactionEmojis: reactionEmoji, emojis: noteEmoji, tags: note.tags.length > 0 ? note.tags : undefined, @@ -233,6 +232,7 @@ export const NoteRepository = db.getRepository(Note).extend({ uri: note.uri || undefined, url: note.url || undefined, updatedAt: note.updatedAt?.toISOString() || undefined, + hasPoll: note.hasPoll, poll: note.hasPoll ? populatePoll(note, meId) : undefined, ...(meId ? { diff --git a/packages/backend/src/models/schema/abuse-user-report.ts b/packages/backend/src/models/schema/abuse-user-report.ts new file mode 100644 index 0000000000..47e56c7415 --- /dev/null +++ b/packages/backend/src/models/schema/abuse-user-report.ts @@ -0,0 +1,69 @@ +export const packedAbuseUserReportSchema = { + type: "object", + properties: { + id: { + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", + }, + createdAt: { + type: "string", + optional: false, + nullable: false, + format: "date-time", + }, + comment: { + type: "string", + optional: false, + nullable: false, + }, + resolved: { + type: "boolean", + optional: false, + nullable: false, + }, + reporterId: { + type: "string", + optional: false, + nullable: false, + format: "id", + }, + targetUserId: { + type: "string", + optional: false, + nullable: false, + format: "id", + }, + assigneeId: { + type: "string", + optional: false, + nullable: true, + format: "id", + }, + reporter: { + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", + }, + targetUser: { + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", + }, + assignee: { + type: "object", + optional: true, + nullable: true, + ref: "UserDetailed", + }, + forwarded: { + type: "boolean", + optional: false, + nullable: false, + }, + }, +} as const; diff --git a/packages/backend/src/models/schema/channel.ts b/packages/backend/src/models/schema/channel.ts index 67833cb0dd..d3ec222c8d 100644 --- a/packages/backend/src/models/schema/channel.ts +++ b/packages/backend/src/models/schema/channel.ts @@ -36,6 +36,13 @@ export const packedChannelSchema = { nullable: true, optional: false, }, + bannerId: { + type: "string", + optional: false, + nullable: true, + format: "id", + example: "xxxxxxxxxx", + }, notesCount: { type: "number", nullable: false, @@ -57,5 +64,10 @@ export const packedChannelSchema = { optional: false, format: "id", }, + hasUnreadNote: { + type: "boolean", + optional: true, + nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/schema/drive-file.ts b/packages/backend/src/models/schema/drive-file.ts index 30db9e7d48..929dbb472e 100644 --- a/packages/backend/src/models/schema/drive-file.ts +++ b/packages/backend/src/models/schema/drive-file.ts @@ -44,6 +44,12 @@ export const packedDriveFileSchema = { optional: false, nullable: false, }, + usageHint: { + type: "string", + optional: false, + nullable: true, + enum: ["userAvatar", "userBanner"], + }, blurhash: { type: "string", optional: false, diff --git a/packages/backend/src/models/schema/gallery-post.ts b/packages/backend/src/models/schema/gallery-post.ts index 9ac348e1fb..ae22507643 100644 --- a/packages/backend/src/models/schema/gallery-post.ts +++ b/packages/backend/src/models/schema/gallery-post.ts @@ -38,7 +38,7 @@ export const packedGalleryPostSchema = { }, user: { type: "object", - ref: "UserLite", + ref: "UserDetailed", optional: false, nullable: false, }, @@ -79,5 +79,15 @@ export const packedGalleryPostSchema = { optional: false, nullable: false, }, + isLiked: { + type: "boolean", + optional: true, + nullable: false, + }, + likedCount: { + type: "number", + optional: false, + nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/schema/note-edit.ts b/packages/backend/src/models/schema/note-edit.ts index e877f3f946..478eece67c 100644 --- a/packages/backend/src/models/schema/note-edit.ts +++ b/packages/backend/src/models/schema/note-edit.ts @@ -16,7 +16,7 @@ export const packedNoteEdit = { }, note: { type: "object", - optional: false, + optional: true, nullable: false, ref: "Note", }, @@ -39,11 +39,27 @@ export const packedNoteEdit = { fileIds: { type: "array", optional: true, - nullable: true, + nullable: false, items: { type: "string", format: "id", }, }, + files: { + type: "array", + optional: true, + nullable: false, + items: { + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", + }, + }, + emojis: { + type: "object", + optional: true, + nullable: true, + }, }, } as const; diff --git a/packages/backend/src/models/schema/note.ts b/packages/backend/src/models/schema/note.ts index 7dcdbc9b03..fff872b69f 100644 --- a/packages/backend/src/models/schema/note.ts +++ b/packages/backend/src/models/schema/note.ts @@ -28,7 +28,7 @@ export const packedNoteSchema = { }, cw: { type: "string", - optional: true, + optional: false, nullable: true, }, userId: { @@ -98,7 +98,7 @@ export const packedNoteSchema = { }, fileIds: { type: "array", - optional: true, + optional: false, nullable: false, items: { type: "string", @@ -128,6 +128,11 @@ export const packedNoteSchema = { nullable: false, }, }, + hasPoll: { + type: "boolean", + optional: false, + nullable: false, + }, poll: { type: "object", optional: true, diff --git a/packages/backend/src/queue/index.ts b/packages/backend/src/queue/index.ts index 58a0ae7486..e4e413be52 100644 --- a/packages/backend/src/queue/index.ts +++ b/packages/backend/src/queue/index.ts @@ -5,7 +5,7 @@ import config from "@/config/index.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import type { IActivity } from "@/remote/activitypub/type.js"; import type { Webhook, webhookEventTypes } from "@/models/entities/webhook.js"; -import { envOption } from "../env.js"; +import { envOption } from "@/config/index.js"; import processDeliver from "./processors/deliver.js"; import processInbox from "./processors/inbox.js"; diff --git a/packages/backend/src/queue/initialize.ts b/packages/backend/src/queue/initialize.ts index 0f9c83132f..a874005fbd 100644 --- a/packages/backend/src/queue/initialize.ts +++ b/packages/backend/src/queue/initialize.ts @@ -34,7 +34,7 @@ export function initialize(name: string, limitPerSec = -1) { function apBackoff(attemptsMade: number, err: Error) { const baseDelay = 60 * 1000; // 1min const maxBackoff = 8 * 60 * 60 * 1000; // 8hours - let backoff = (Math.pow(2, attemptsMade) - 1) * baseDelay; + let backoff = (2 ** attemptsMade - 1) * baseDelay; backoff = Math.min(backoff, maxBackoff); backoff += Math.round(backoff * Math.random() * 0.2); return backoff; diff --git a/packages/backend/src/queue/processors/db/export-blocking.ts b/packages/backend/src/queue/processors/db/export-blocking.ts index 90da76b872..4fd222b3ef 100644 --- a/packages/backend/src/queue/processors/db/export-blocking.ts +++ b/packages/backend/src/queue/processors/db/export-blocking.ts @@ -4,7 +4,7 @@ import * as fs from "node:fs"; import { queueLogger } from "../../logger.js"; import { addFile } from "@/services/drive/add-file.js"; import { format as dateFormat } from "date-fns"; -import { getFullApAccount } from "@/misc/convert-host.js"; +import { getFullApAccount } from "backend-rs"; import { createTemp } from "@/misc/create-temp.js"; import { Users, Blockings } from "@/models/index.js"; import { MoreThan } from "typeorm"; diff --git a/packages/backend/src/queue/processors/db/export-following.ts b/packages/backend/src/queue/processors/db/export-following.ts index 552f8d40c0..65d3673e70 100644 --- a/packages/backend/src/queue/processors/db/export-following.ts +++ b/packages/backend/src/queue/processors/db/export-following.ts @@ -4,7 +4,7 @@ import * as fs from "node:fs"; import { queueLogger } from "../../logger.js"; import { addFile } from "@/services/drive/add-file.js"; import { format as dateFormat } from "date-fns"; -import { getFullApAccount } from "@/misc/convert-host.js"; +import { getFullApAccount } from "backend-rs"; import { createTemp } from "@/misc/create-temp.js"; import { Users, Followings, Mutings } from "@/models/index.js"; import { In, MoreThan, Not } from "typeorm"; diff --git a/packages/backend/src/queue/processors/db/export-mute.ts b/packages/backend/src/queue/processors/db/export-mute.ts index 87b140b762..f7906ac9f0 100644 --- a/packages/backend/src/queue/processors/db/export-mute.ts +++ b/packages/backend/src/queue/processors/db/export-mute.ts @@ -4,7 +4,7 @@ import * as fs from "node:fs"; import { queueLogger } from "../../logger.js"; import { addFile } from "@/services/drive/add-file.js"; import { format as dateFormat } from "date-fns"; -import { getFullApAccount } from "@/misc/convert-host.js"; +import { getFullApAccount } from "backend-rs"; import { createTemp } from "@/misc/create-temp.js"; import { Users, Mutings } from "@/models/index.js"; import { IsNull, MoreThan } from "typeorm"; diff --git a/packages/backend/src/queue/processors/db/export-user-lists.ts b/packages/backend/src/queue/processors/db/export-user-lists.ts index e0c9cd8f3f..e6877f31fc 100644 --- a/packages/backend/src/queue/processors/db/export-user-lists.ts +++ b/packages/backend/src/queue/processors/db/export-user-lists.ts @@ -4,7 +4,7 @@ import * as fs from "node:fs"; import { queueLogger } from "../../logger.js"; import { addFile } from "@/services/drive/add-file.js"; import { format as dateFormat } from "date-fns"; -import { getFullApAccount } from "@/misc/convert-host.js"; +import { getFullApAccount } from "backend-rs"; import { createTemp } from "@/misc/create-temp.js"; import { Users, UserLists, UserListJoinings } from "@/models/index.js"; import { In } from "typeorm"; diff --git a/packages/backend/src/queue/processors/db/import-blocking.ts b/packages/backend/src/queue/processors/db/import-blocking.ts index 159ccbfd4a..e933b60783 100644 --- a/packages/backend/src/queue/processors/db/import-blocking.ts +++ b/packages/backend/src/queue/processors/db/import-blocking.ts @@ -1,10 +1,9 @@ import type Bull from "bull"; import { queueLogger } from "../../logger.js"; -import * as Acct from "@/misc/acct.js"; +import { isSelfHost, stringToAcct, toPuny } from "backend-rs"; import { resolveUser } from "@/remote/resolve-user.js"; import { downloadTextFile } from "@/misc/download-text-file.js"; -import { isSelfHost, toPuny } from "@/misc/convert-host.js"; import { Users, DriveFiles } from "@/models/index.js"; import type { DbUserImportJobData } from "@/queue/types.js"; import block from "@/services/blocking/create.js"; @@ -42,7 +41,7 @@ export async function importBlocking( try { const acct = line.split(",")[0].trim(); - const { username, host } = Acct.parse(acct); + const { username, host } = stringToAcct(acct); let target = isSelfHost(host!) ? await Users.findOneBy({ diff --git a/packages/backend/src/queue/processors/db/import-custom-emojis.ts b/packages/backend/src/queue/processors/db/import-custom-emojis.ts index 9e8b3b174e..f2371429f2 100644 --- a/packages/backend/src/queue/processors/db/import-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/import-custom-emojis.ts @@ -8,7 +8,7 @@ import { downloadUrl } from "@/misc/download-url.js"; import { DriveFiles, Emojis } from "@/models/index.js"; import type { DbUserImportJobData } from "@/queue/types.js"; import { addFile } from "@/services/drive/add-file.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { db } from "@/db/postgre.js"; import probeImageSize from "probe-image-size"; import * as path from "path"; diff --git a/packages/backend/src/queue/processors/db/import-firefish-post.ts b/packages/backend/src/queue/processors/db/import-firefish-post.ts index 4ec88d32cc..be412fc490 100644 --- a/packages/backend/src/queue/processors/db/import-firefish-post.ts +++ b/packages/backend/src/queue/processors/db/import-firefish-post.ts @@ -9,7 +9,7 @@ import type Bull from "bull"; import { createImportCkPostJob } from "@/queue/index.js"; import { Notes, NoteEdits } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; const logger = queueLogger.createSubLogger("import-firefish-post"); diff --git a/packages/backend/src/queue/processors/db/import-following.ts b/packages/backend/src/queue/processors/db/import-following.ts index d2c2430fa3..77017fa9ff 100644 --- a/packages/backend/src/queue/processors/db/import-following.ts +++ b/packages/backend/src/queue/processors/db/import-following.ts @@ -1,10 +1,9 @@ import { IsNull } from "typeorm"; import follow from "@/services/following/create.js"; -import * as Acct from "@/misc/acct.js"; +import { isSelfHost, stringToAcct, toPuny } from "backend-rs"; import { resolveUser } from "@/remote/resolve-user.js"; import { downloadTextFile } from "@/misc/download-text-file.js"; -import { isSelfHost, toPuny } from "@/misc/convert-host.js"; import { Users, DriveFiles } from "@/models/index.js"; import type { DbUserImportJobData } from "@/queue/types.js"; import { queueLogger } from "../../logger.js"; @@ -40,7 +39,7 @@ export async function importFollowing( if (file.type.endsWith("json")) { for (const acct of JSON.parse(csv)) { try { - const { username, host } = Acct.parse(acct); + const { username, host } = stringToAcct(acct); let target = isSelfHost(host!) ? await Users.findOneBy({ @@ -78,7 +77,7 @@ export async function importFollowing( try { const acct = line.split(",")[0].trim(); - const { username, host } = Acct.parse(acct); + const { username, host } = stringToAcct(acct); let target = isSelfHost(host!) ? await Users.findOneBy({ diff --git a/packages/backend/src/queue/processors/db/import-masto-post.ts b/packages/backend/src/queue/processors/db/import-masto-post.ts index f42b003e9a..d8f848d206 100644 --- a/packages/backend/src/queue/processors/db/import-masto-post.ts +++ b/packages/backend/src/queue/processors/db/import-masto-post.ts @@ -9,7 +9,7 @@ import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import { Notes, NoteEdits } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; const logger = queueLogger.createSubLogger("import-masto-post"); diff --git a/packages/backend/src/queue/processors/db/import-muting.ts b/packages/backend/src/queue/processors/db/import-muting.ts index acb7f22d55..b0d8f40956 100644 --- a/packages/backend/src/queue/processors/db/import-muting.ts +++ b/packages/backend/src/queue/processors/db/import-muting.ts @@ -1,14 +1,12 @@ import type Bull from "bull"; import { queueLogger } from "../../logger.js"; -import * as Acct from "@/misc/acct.js"; import { resolveUser } from "@/remote/resolve-user.js"; import { downloadTextFile } from "@/misc/download-text-file.js"; -import { isSelfHost, toPuny } from "@/misc/convert-host.js"; import { Users, DriveFiles, Mutings } from "@/models/index.js"; import type { DbUserImportJobData } from "@/queue/types.js"; import type { User } from "@/models/entities/user.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId, isSelfHost, stringToAcct, toPuny } from "backend-rs"; import { IsNull } from "typeorm"; import { inspect } from "node:util"; @@ -43,7 +41,7 @@ export async function importMuting( try { const acct = line.split(",")[0].trim(); - const { username, host } = Acct.parse(acct); + const { username, host } = stringToAcct(acct); let target = isSelfHost(host!) ? await Users.findOneBy({ diff --git a/packages/backend/src/queue/processors/db/import-user-lists.ts b/packages/backend/src/queue/processors/db/import-user-lists.ts index 9c7d49c265..2bdecfd389 100644 --- a/packages/backend/src/queue/processors/db/import-user-lists.ts +++ b/packages/backend/src/queue/processors/db/import-user-lists.ts @@ -1,18 +1,16 @@ import type Bull from "bull"; import { queueLogger } from "../../logger.js"; -import * as Acct from "@/misc/acct.js"; import { resolveUser } from "@/remote/resolve-user.js"; import { pushUserToUserList } from "@/services/user-list/push.js"; import { downloadTextFile } from "@/misc/download-text-file.js"; -import { isSelfHost, toPuny } from "@/misc/convert-host.js"; import { DriveFiles, Users, UserLists, UserListJoinings, } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId, isSelfHost, stringToAcct, toPuny } from "backend-rs"; import type { DbUserImportJobData } from "@/queue/types.js"; import { IsNull } from "typeorm"; import { inspect } from "node:util"; @@ -48,7 +46,7 @@ export async function importUserLists( try { const listName = line.split(",")[0].trim(); - const { username, host } = Acct.parse(line.split(",")[1].trim()); + const { username, host } = stringToAcct(line.split(",")[1].trim()); let list = await UserLists.findOneBy({ userId: user.id, diff --git a/packages/backend/src/queue/processors/deliver.ts b/packages/backend/src/queue/processors/deliver.ts index 45c2d3dc95..2abadeb9c4 100644 --- a/packages/backend/src/queue/processors/deliver.ts +++ b/packages/backend/src/queue/processors/deliver.ts @@ -4,7 +4,7 @@ import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instanc import Logger from "@/services/logger.js"; import { Instances } from "@/models/index.js"; import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { toPuny } from "backend-rs"; import { StatusError } from "@/misc/fetch.js"; import { shouldSkipInstance } from "@/misc/skipped-instances.js"; import type { DeliverJobData } from "@/queue/types.js"; diff --git a/packages/backend/src/queue/processors/inbox.ts b/packages/backend/src/queue/processors/inbox.ts index b0e1089246..0ea72306b6 100644 --- a/packages/backend/src/queue/processors/inbox.ts +++ b/packages/backend/src/queue/processors/inbox.ts @@ -5,8 +5,8 @@ import perform from "@/remote/activitypub/perform.js"; import Logger from "@/services/logger.js"; import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js"; import { Instances } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { toPuny, extractDbHost } from "@/misc/convert-host.js"; +import { fetchMeta } from "backend-rs"; +import { toPuny, extractHost } from "backend-rs"; import { getApId } from "@/remote/activitypub/type.js"; import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; import type { InboxJobData } from "../types.js"; @@ -41,7 +41,7 @@ export default async (job: Bull.Job): Promise => { const host = toPuny(new URL(signature.keyId).hostname); // interrupt if blocked - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (await shouldBlockInstance(host, meta)) { return `Blocked request: ${host}`; } @@ -157,7 +157,7 @@ export default async (job: Bull.Job): Promise => { } // ブロックしてたら中断 - const ldHost = extractDbHost(authUser.user.uri); + const ldHost = extractHost(authUser.user.uri); if (await shouldBlockInstance(ldHost, meta)) { return `Blocked request: ${ldHost}`; } @@ -168,8 +168,8 @@ export default async (job: Bull.Job): Promise => { // activity.idがあればホストが署名者のホストであることを確認する if (typeof activity.id === "string") { - const signerHost = extractDbHost(authUser.user.uri!); - const activityIdHost = extractDbHost(activity.id); + const signerHost = extractHost(authUser.user.uri!); + const activityIdHost = extractHost(activity.id); if (signerHost !== activityIdHost) { return `skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`; } diff --git a/packages/backend/src/remote/activitypub/check-fetch.ts b/packages/backend/src/remote/activitypub/check-fetch.ts index a170e3eb3a..12ea63a931 100644 --- a/packages/backend/src/remote/activitypub/check-fetch.ts +++ b/packages/backend/src/remote/activitypub/check-fetch.ts @@ -1,8 +1,8 @@ import { URL } from "url"; import httpSignature, { IParsedSignature } from "@peertube/http-signature"; import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { fetchMeta } from "backend-rs"; +import { toPuny } from "backend-rs"; import DbResolver from "@/remote/activitypub/db-resolver.js"; import { getApId } from "@/remote/activitypub/type.js"; import { shouldBlockInstance } from "@/misc/should-block-instance.js"; @@ -12,7 +12,7 @@ import type { UserPublickey } from "@/models/entities/user-publickey.js"; import { verify } from "node:crypto"; export async function hasSignature(req: IncomingMessage): Promise { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const required = meta.secureMode || meta.privateMode; try { @@ -27,7 +27,7 @@ export async function hasSignature(req: IncomingMessage): Promise { } export async function checkFetch(req: IncomingMessage): Promise { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { if (req.headers.host !== config.host) return 400; diff --git a/packages/backend/src/remote/activitypub/kernel/announce/note.ts b/packages/backend/src/remote/activitypub/kernel/announce/note.ts index cc33b681eb..ae16c77dbd 100644 --- a/packages/backend/src/remote/activitypub/kernel/announce/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/announce/note.ts @@ -5,7 +5,7 @@ import type { IAnnounce } from "../../type.js"; import { getApId } from "../../type.js"; import { fetchNote, resolveNote } from "../../models/note.js"; import { apLogger } from "../../logger.js"; -import { extractDbHost } from "@/misc/convert-host.js"; +import { extractHost } from "backend-rs"; import { getApLock } from "@/misc/app-lock.js"; import { parseAudience } from "../../audience.js"; import { StatusError } from "@/misc/fetch.js"; @@ -31,7 +31,7 @@ export default async function ( } // Interrupt if you block the announcement destination - if (await shouldBlockInstance(extractDbHost(uri))) return; + if (await shouldBlockInstance(extractHost(uri))) return; const lock = await getApLock(uri); diff --git a/packages/backend/src/remote/activitypub/kernel/create/note.ts b/packages/backend/src/remote/activitypub/kernel/create/note.ts index 92b0ffb1e0..512972f63a 100644 --- a/packages/backend/src/remote/activitypub/kernel/create/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/create/note.ts @@ -4,7 +4,7 @@ import { createNote, fetchNote } from "../../models/note.js"; import type { IObject, ICreate } from "../../type.js"; import { getApId } from "../../type.js"; import { getApLock } from "@/misc/app-lock.js"; -import { extractDbHost } from "@/misc/convert-host.js"; +import { extractHost } from "backend-rs"; import { StatusError } from "@/misc/fetch.js"; /** @@ -25,7 +25,7 @@ export default async function ( } if (typeof note.id === "string") { - if (extractDbHost(actor.uri) !== extractDbHost(note.id)) { + if (extractHost(actor.uri) !== extractHost(note.id)) { return "skip: host in actor.uri !== note.id"; } } diff --git a/packages/backend/src/remote/activitypub/kernel/delete/note.ts b/packages/backend/src/remote/activitypub/kernel/delete/note.ts index 4656480c2f..ae3a593d05 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/note.ts @@ -1,5 +1,5 @@ import type { CacheableRemoteUser } from "@/models/entities/user.js"; -import deleteNode from "@/services/note/delete.js"; +import deleteNote from "@/services/note/delete.js"; import { apLogger } from "../../logger.js"; import DbResolver from "../../db-resolver.js"; import { getApLock } from "@/misc/app-lock.js"; @@ -36,7 +36,7 @@ export default async function ( return "The user trying to delete the post is not the post author"; } - await deleteNode(actor, note); + await deleteNote(actor, note); return "ok: note deleted"; } finally { await lock.release(); diff --git a/packages/backend/src/remote/activitypub/kernel/flag/index.ts b/packages/backend/src/remote/activitypub/kernel/flag/index.ts index 39ba8b3f4f..0f83f6b449 100644 --- a/packages/backend/src/remote/activitypub/kernel/flag/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/flag/index.ts @@ -4,7 +4,7 @@ import type { IFlag } from "../../type.js"; import { getApIds } from "../../type.js"; import { AbuseUserReports, Users } from "@/models/index.js"; import { In } from "typeorm"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export default async ( actor: CacheableRemoteUser, diff --git a/packages/backend/src/remote/activitypub/kernel/index.ts b/packages/backend/src/remote/activitypub/kernel/index.ts index aa99f6c320..f64a0e2ee8 100644 --- a/packages/backend/src/remote/activitypub/kernel/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/index.ts @@ -38,7 +38,7 @@ import block from "./block/index.js"; import flag from "./flag/index.js"; import move from "./move/index.js"; import type { IObject, IActivity } from "../type.js"; -import { extractDbHost } from "@/misc/convert-host.js"; +import { extractHost } from "backend-rs"; import { shouldBlockInstance } from "@/misc/should-block-instance.js"; import { inspect } from "node:util"; @@ -70,7 +70,7 @@ async function performOneActivity( if (actor.isSuspended) return; if (typeof activity.id !== "undefined") { - const host = extractDbHost(getApId(activity)); + const host = extractHost(getApId(activity)); if (await shouldBlockInstance(host)) return; } diff --git a/packages/backend/src/remote/activitypub/kernel/read.ts b/packages/backend/src/remote/activitypub/kernel/read.ts index 53fa7fe63b..bdcb2e8b76 100644 --- a/packages/backend/src/remote/activitypub/kernel/read.ts +++ b/packages/backend/src/remote/activitypub/kernel/read.ts @@ -1,7 +1,7 @@ import type { CacheableRemoteUser } from "@/models/entities/user.js"; import type { IRead } from "../type.js"; import { getApId } from "../type.js"; -import { isSelfHost, extractDbHost } from "@/misc/convert-host.js"; +import { isSelfHost, extractHost } from "backend-rs"; import { MessagingMessages } from "@/models/index.js"; import { readUserMessagingMessage } from "@/server/api/common/read-messaging-message.js"; @@ -11,7 +11,7 @@ export const performReadActivity = async ( ): Promise => { const id = await getApId(activity.object); - if (!isSelfHost(extractDbHost(id))) { + if (!isSelfHost(extractHost(id))) { return `skip: Read to foreign host (${id})`; } diff --git a/packages/backend/src/remote/activitypub/models/image.ts b/packages/backend/src/remote/activitypub/models/image.ts index 2cf0c6c152..a6ac698feb 100644 --- a/packages/backend/src/remote/activitypub/models/image.ts +++ b/packages/backend/src/remote/activitypub/models/image.ts @@ -1,9 +1,12 @@ import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; import type { CacheableRemoteUser } from "@/models/entities/user.js"; import Resolver from "../resolver.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { apLogger } from "../logger.js"; -import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { + DriveFile, + DriveFileUsageHint, +} from "@/models/entities/drive-file.js"; import { DriveFiles } from "@/models/index.js"; import { truncate } from "@/misc/truncate.js"; import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js"; @@ -16,6 +19,7 @@ const logger = apLogger; export async function createImage( actor: CacheableRemoteUser, value: any, + usage: DriveFileUsageHint, ): Promise { // Skip if author is frozen. if (actor.isSuspended) { @@ -34,7 +38,7 @@ export async function createImage( logger.info(`Creating the Image: ${image.url}`); - const instance = await fetchMeta(); + const instance = await fetchMeta(true); let file = await uploadFromUrl({ url: image.url, @@ -43,6 +47,7 @@ export async function createImage( sensitive: image.sensitive, isLink: !instance.cacheRemoteFiles, comment: truncate(image.name, DB_MAX_IMAGE_COMMENT_LENGTH), + usageHint: usage, }); if (file.isLink) { @@ -73,9 +78,10 @@ export async function createImage( export async function resolveImage( actor: CacheableRemoteUser, value: any, + usage: DriveFileUsageHint, ): Promise { // TODO // Fetch from remote server and register - return await createImage(actor, value); + return await createImage(actor, value, usage); } diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index 0d706df5d7..b2fd67288c 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -13,7 +13,7 @@ import { extractPollFromQuestion } from "./question.js"; import vote from "@/services/note/polls/vote.js"; import { apLogger } from "../logger.js"; import { DriveFile } from "@/models/entities/drive-file.js"; -import { extractDbHost, isSameOrigin, toPuny } from "@/misc/convert-host.js"; +import { extractHost, isSameOrigin, toPuny } from "backend-rs"; import { Emojis, Polls, @@ -33,7 +33,7 @@ import { getApType, } from "../type.js"; import type { Emoji } from "@/models/entities/emoji.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { getApLock } from "@/misc/app-lock.js"; import { createMessage } from "@/services/messages/create.js"; import { parseAudience } from "../audience.js"; @@ -54,7 +54,7 @@ import { inspect } from "node:util"; const logger = apLogger; export function validateNote(object: any, uri: string) { - const expectHost = extractDbHost(uri); + const expectHost = extractHost(uri); if (object == null) { return new Error("invalid Note: object is null"); @@ -64,9 +64,9 @@ export function validateNote(object: any, uri: string) { return new Error(`invalid Note: invalid object type ${getApType(object)}`); } - if (object.id && extractDbHost(object.id) !== expectHost) { + if (object.id && extractHost(object.id) !== expectHost) { return new Error( - `invalid Note: id has different host. expected: ${expectHost}, actual: ${extractDbHost( + `invalid Note: id has different host. expected: ${expectHost}, actual: ${extractHost( object.id, )}`, ); @@ -74,10 +74,10 @@ export function validateNote(object: any, uri: string) { if ( object.attributedTo && - extractDbHost(getOneApId(object.attributedTo)) !== expectHost + extractHost(getOneApId(object.attributedTo)) !== expectHost ) { return new Error( - `invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractDbHost( + `invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractHost( object.attributedTo, )}`, ); @@ -213,7 +213,8 @@ export async function createNote( ? ( await Promise.all( note.attachment.map( - (x) => limit(() => resolveImage(actor, x)) as Promise, + (x) => + limit(() => resolveImage(actor, x, null)) as Promise, ), ) ).filter((image) => image != null) @@ -420,11 +421,11 @@ export async function resolveNote( if (uri == null) throw new Error("missing uri"); // Abort if origin host is blocked - if (await shouldBlockInstance(extractDbHost(uri))) + if (await shouldBlockInstance(extractHost(uri))) throw new StatusError( "host blocked", 451, - `host ${extractDbHost(uri)} is blocked`, + `host ${extractHost(uri)} is blocked`, ); const lock = await getApLock(uri); @@ -616,7 +617,7 @@ export async function updateNote(value: string | IObject, resolver?: Resolver) { fileList.map( (x) => limit(async () => { - const file = await resolveImage(actor, x); + const file = await resolveImage(actor, x, null); const update: Partial = {}; const altText = truncate(x.name, DB_MAX_IMAGE_COMMENT_LENGTH); @@ -773,6 +774,7 @@ export async function updateNote(value: string | IObject, resolver?: Resolver) { cw: note.cw, fileIds: note.fileIds, updatedAt: update.updatedAt, + emojis: note.emojis, }); publishing = true; diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index be8ba4a73f..4baa2c021b 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -1,7 +1,6 @@ import { URL } from "node:url"; import promiseLimit from "promise-limit"; -import config from "@/config/index.js"; import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js"; import type { Note } from "@/models/entities/note.js"; import { updateUsertags } from "@/services/update-hashtag.js"; @@ -11,15 +10,16 @@ import { Followings, UserProfiles, UserPublickeys, + DriveFiles, } from "@/models/index.js"; import type { IRemoteUser, CacheableUser } from "@/models/entities/user.js"; import { User } from "@/models/entities/user.js"; import type { Emoji } from "@/models/entities/emoji.js"; import { UserNotePining } from "@/models/entities/user-note-pining.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { UserPublickey } from "@/models/entities/user-publickey.js"; import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; -import { isSameOrigin, toPuny } from "@/misc/convert-host.js"; +import { isSameOrigin, toPuny } from "backend-rs"; import { UserProfile } from "@/models/entities/user-profile.js"; import { toArray } from "@/prelude/array.js"; import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; @@ -164,8 +164,6 @@ export async function createPerson( uri: string, resolver?: Resolver, ): Promise { - if (typeof uri !== "string") throw new Error("uri is not string"); - if (isSameOrigin(uri)) { throw new StatusError( "cannot resolve local user", @@ -365,10 +363,14 @@ export async function createPerson( //#region Fetch avatar and header image const [avatar, banner] = await Promise.all( - [person.icon, person.image].map((img) => + [person.icon, person.image].map((img, index) => img == null ? Promise.resolve(null) - : resolveImage(user!, img).catch(() => null), + : resolveImage( + user, + img, + index === 0 ? "userAvatar" : index === 1 ? "userBanner" : null, + ).catch(() => null), ), ); @@ -441,10 +443,14 @@ export async function updatePerson( // Fetch avatar and header image const [avatar, banner] = await Promise.all( - [person.icon, person.image].map((img) => + [person.icon, person.image].map((img, index) => img == null ? Promise.resolve(null) - : resolveImage(user, img).catch(() => null), + : resolveImage( + user, + img, + index === 0 ? "userAvatar" : index === 1 ? "userBanner" : null, + ).catch(() => null), ), ); @@ -564,10 +570,14 @@ export async function updatePerson( } as Partial; if (avatar) { + if (user?.avatarId) + await DriveFiles.update(user.avatarId, { usageHint: null }); updates.avatarId = avatar.id; } if (banner) { + if (user?.bannerId) + await DriveFiles.update(user.bannerId, { usageHint: null }); updates.bannerId = banner.id; } diff --git a/packages/backend/src/remote/activitypub/models/question.ts b/packages/backend/src/remote/activitypub/models/question.ts index 98d2f27a58..292e220dee 100644 --- a/packages/backend/src/remote/activitypub/models/question.ts +++ b/packages/backend/src/remote/activitypub/models/question.ts @@ -4,7 +4,7 @@ import { getApId, isQuestion } from "../type.js"; import { apLogger } from "../logger.js"; import { Notes, Polls } from "@/models/index.js"; import type { IPoll } from "@/models/entities/poll.js"; -import { isSameOrigin } from "@/misc/convert-host.js"; +import { isSameOrigin } from "backend-rs"; export async function extractPollFromQuestion( source: string | IObject, diff --git a/packages/backend/src/remote/activitypub/renderer/update.ts b/packages/backend/src/remote/activitypub/renderer/update.ts index 765a52f06d..ecb0ed2192 100644 --- a/packages/backend/src/remote/activitypub/renderer/update.ts +++ b/packages/backend/src/remote/activitypub/renderer/update.ts @@ -3,7 +3,7 @@ import type { User } from "@/models/entities/user.js"; export default (object: any, user: { id: User["id"] }) => { const activity = { - id: `${config.url}/users/${user.id}#updates/${new Date().getTime()}`, + id: `${config.url}/users/${user.id}#updates/${Date.now()}`, actor: `${config.url}/users/${user.id}`, type: "Update", to: ["https://www.w3.org/ns/activitystreams#Public"], diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts index 7c0bd6e102..79b7962b72 100644 --- a/packages/backend/src/remote/activitypub/resolver.ts +++ b/packages/backend/src/remote/activitypub/resolver.ts @@ -1,8 +1,8 @@ import config from "@/config/index.js"; import type { ILocalUser } from "@/models/entities/user.js"; import { getInstanceActor } from "@/services/instance-actor.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { extractDbHost, isSelfHost } from "@/misc/convert-host.js"; +import { fetchMeta } from "backend-rs"; +import { extractHost, isSelfHost } from "backend-rs"; import { apGet } from "./request.js"; import type { IObject, ICollection, IOrderedCollection } from "./type.js"; import { isCollectionOrOrderedCollection, getApId } from "./type.js"; @@ -68,7 +68,7 @@ export default class Resolver { if (typeof value !== "string") { apLogger.debug("Object to resolve is not a string"); if (typeof value.id !== "undefined") { - const host = extractDbHost(getApId(value)); + const host = extractHost(getApId(value)); if (await shouldBlockInstance(host)) { throw new Error("instance is blocked"); } @@ -95,12 +95,12 @@ export default class Resolver { } this.history.add(value); - const host = extractDbHost(value); + const host = extractHost(value); if (isSelfHost(host)) { return await this.resolveLocal(value); } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (await shouldBlockInstance(host, meta)) { throw new Error("Instance is blocked"); } diff --git a/packages/backend/src/remote/resolve-user.ts b/packages/backend/src/remote/resolve-user.ts index f73b670273..0883386371 100644 --- a/packages/backend/src/remote/resolve-user.ts +++ b/packages/backend/src/remote/resolve-user.ts @@ -4,7 +4,7 @@ import { IsNull } from "typeorm"; import config from "@/config/index.js"; import type { User, IRemoteUser } from "@/models/entities/user.js"; import { Users } from "@/models/index.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { toPuny } from "backend-rs"; import webFinger from "./webfinger.js"; import { createPerson, updatePerson } from "./activitypub/models/person.js"; import { remoteLogger } from "./logger.js"; diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index 7c437d3d6d..71d95709b7 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -9,7 +9,7 @@ import renderKey from "@/remote/activitypub/renderer/key.js"; import { renderPerson } from "@/remote/activitypub/renderer/person.js"; import renderEmoji from "@/remote/activitypub/renderer/emoji.js"; import { inbox as processInbox } from "@/queue/index.js"; -import { isSelfHost } from "@/misc/convert-host.js"; +import { fetchMeta, isSelfHost } from "backend-rs"; import { Notes, Users, @@ -25,7 +25,6 @@ import { getSignatureUser, } from "@/remote/activitypub/check-fetch.js"; import { getInstanceActor } from "@/services/instance-actor.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; import renderFollow from "@/remote/activitypub/renderer/follow.js"; import Featured from "./activitypub/featured.js"; import Following from "./activitypub/following.js"; @@ -33,7 +32,7 @@ import Followers from "./activitypub/followers.js"; import Outbox, { packActivity } from "./activitypub/outbox.js"; import { serverLogger } from "./index.js"; import config from "@/config/index.js"; -import Koa from "koa"; +import type Koa from "koa"; import * as crypto from "node:crypto"; import { inspect } from "node:util"; import type { IActivity } from "@/remote/activitypub/type.js"; @@ -238,7 +237,7 @@ router.get("/notes/:note", async (ctx, next) => { ctx.body = renderActivity(await renderNote(note, false)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -268,7 +267,7 @@ router.get("/notes/:note/activity", async (ctx) => { } ctx.body = renderActivity(await packActivity(note)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -323,7 +322,7 @@ router.get("/users/:user/publickey", async (ctx) => { if (Users.isLocalUser(user)) { ctx.body = renderActivity(renderKey(user, keypair)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -343,7 +342,7 @@ async function userInfo(ctx: Router.RouterContext, user: User | null) { } ctx.body = renderActivity(await renderPerson(user as ILocalUser)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -426,8 +425,8 @@ router.get("/emojis/:emoji", async (ctx) => { return; } - ctx.body = renderActivity(await renderEmoji(emoji)); - const meta = await fetchMeta(); + ctx.body = renderActivity(renderEmoji(emoji)); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -459,7 +458,7 @@ router.get("/likes/:like", async (ctx) => { } ctx.body = renderActivity(await renderLike(reaction, note)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -497,7 +496,7 @@ router.get( } ctx.body = renderActivity(renderFollow(follower, followee)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -540,7 +539,7 @@ router.get("/follows/:followRequestId", async (ctx: Router.RouterContext) => { return; } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/activitypub/featured.ts b/packages/backend/src/server/activitypub/featured.ts index 464a7f769d..e7ea6f238e 100644 --- a/packages/backend/src/server/activitypub/featured.ts +++ b/packages/backend/src/server/activitypub/featured.ts @@ -5,7 +5,7 @@ import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-colle import renderNote from "@/remote/activitypub/renderer/note.js"; import { Users, Notes, UserNotePinings } from "@/models/index.js"; import { checkFetch } from "@/remote/activitypub/check-fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { setResponseType } from "../activitypub.js"; import type Router from "@koa/router"; @@ -57,7 +57,7 @@ export default async (ctx: Router.RouterContext) => { ctx.body = renderActivity(rendered); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/activitypub/followers.ts b/packages/backend/src/server/activitypub/followers.ts index 3c9e5fa201..576a672d6d 100644 --- a/packages/backend/src/server/activitypub/followers.ts +++ b/packages/backend/src/server/activitypub/followers.ts @@ -8,7 +8,7 @@ import renderFollowUser from "@/remote/activitypub/renderer/follow-user.js"; import { Users, Followings, UserProfiles } from "@/models/index.js"; import type { Following } from "@/models/entities/following.js"; import { checkFetch } from "@/remote/activitypub/check-fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { setResponseType } from "../activitypub.js"; import type { FindOptionsWhere } from "typeorm"; import type Router from "@koa/router"; @@ -110,7 +110,7 @@ export default async (ctx: Router.RouterContext) => { ctx.body = renderActivity(rendered); setResponseType(ctx); } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/activitypub/following.ts b/packages/backend/src/server/activitypub/following.ts index cfbe985911..76b4e79716 100644 --- a/packages/backend/src/server/activitypub/following.ts +++ b/packages/backend/src/server/activitypub/following.ts @@ -8,7 +8,7 @@ import renderFollowUser from "@/remote/activitypub/renderer/follow-user.js"; import { Users, Followings, UserProfiles } from "@/models/index.js"; import type { Following } from "@/models/entities/following.js"; import { checkFetch } from "@/remote/activitypub/check-fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { setResponseType } from "../activitypub.js"; import type { FindOptionsWhere } from "typeorm"; import type Router from "@koa/router"; @@ -110,7 +110,7 @@ export default async (ctx: Router.RouterContext) => { ctx.body = renderActivity(rendered); setResponseType(ctx); } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index 53aa6f4ad5..305102cf12 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -11,7 +11,7 @@ import * as url from "@/prelude/url.js"; import { Users, Notes } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; import { checkFetch } from "@/remote/activitypub/check-fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { makePaginationQuery } from "../api/common/make-pagination-query.js"; import { setResponseType } from "../activitypub.js"; import type Router from "@koa/router"; @@ -117,7 +117,7 @@ export default async (ctx: Router.RouterContext) => { setResponseType(ctx); } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/api/api-handler.ts b/packages/backend/src/server/api/api-handler.ts index 620b754f30..5e65636427 100644 --- a/packages/backend/src/server/api/api-handler.ts +++ b/packages/backend/src/server/api/api-handler.ts @@ -2,7 +2,7 @@ import type Koa from "koa"; import type { User } from "@/models/entities/user.js"; import { UserIps } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { IEndpoint } from "./endpoints.js"; import authenticate, { AuthenticationError } from "./authenticate.js"; import call from "./call.js"; @@ -84,7 +84,7 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => // Log IP if (user) { - fetchMeta().then((meta) => { + fetchMeta(true).then((meta) => { if (!meta.enableIpLogging) return; const ip = ctx.ip; const ips = userIpHistories.get(user.id); diff --git a/packages/backend/src/server/api/call.ts b/packages/backend/src/server/api/call.ts index 2faef7b0e8..3107156a9b 100644 --- a/packages/backend/src/server/api/call.ts +++ b/packages/backend/src/server/api/call.ts @@ -10,7 +10,7 @@ import endpoints from "./endpoints.js"; import compatibility from "./compatibility.js"; import { ApiError } from "./error.js"; import { apiLogger } from "./logger.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; const accessDenied = { message: "Access denied.", @@ -117,7 +117,7 @@ export default async ( } // private mode - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( meta.privateMode && ep.meta.requireCredentialPrivateMode && diff --git a/packages/backend/src/server/api/common/generate-native-user-token.ts b/packages/backend/src/server/api/common/generate-native-user-token.ts index 5a8b41b70e..495a1150d2 100644 --- a/packages/backend/src/server/api/common/generate-native-user-token.ts +++ b/packages/backend/src/server/api/common/generate-native-user-token.ts @@ -1,3 +1,3 @@ -import { secureRndstr } from "@/misc/secure-rndstr.js"; +import { secureRndstr } from "backend-rs"; -export default () => secureRndstr(16, true); +export default () => secureRndstr(16); diff --git a/packages/backend/src/server/api/common/signin.ts b/packages/backend/src/server/api/common/signin.ts index a8a435843f..e59a39ac41 100644 --- a/packages/backend/src/server/api/common/signin.ts +++ b/packages/backend/src/server/api/common/signin.ts @@ -3,7 +3,7 @@ import type Koa from "koa"; import config from "@/config/index.js"; import type { ILocalUser } from "@/models/entities/user.js"; import { Signins } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { publishMainStream } from "@/services/stream.js"; export default function (ctx: Koa.Context, user: ILocalUser, redirect = false) { diff --git a/packages/backend/src/server/api/common/signup.ts b/packages/backend/src/server/api/common/signup.ts index dc76c264ae..58b88b7d02 100644 --- a/packages/backend/src/server/api/common/signup.ts +++ b/packages/backend/src/server/api/common/signup.ts @@ -4,13 +4,11 @@ import { User } from "@/models/entities/user.js"; import { Users, UsedUsernames } from "@/models/index.js"; import { UserProfile } from "@/models/entities/user-profile.js"; import { IsNull } from "typeorm"; -import { genId } from "@/misc/gen-id.js"; -import { toPunyNullable } from "@/misc/convert-host.js"; +import { genId, hashPassword, toPuny } from "backend-rs"; import { UserKeypair } from "@/models/entities/user-keypair.js"; import { UsedUsername } from "@/models/entities/used-username.js"; import { db } from "@/db/postgre.js"; import config from "@/config/index.js"; -import { hashPassword } from "@/misc/password.js"; export async function signup(opts: { username: User["username"]; @@ -41,7 +39,7 @@ export async function signup(opts: { } // Generate hash of password - hash = await hashPassword(password); + hash = hashPassword(password); } // Generate secret @@ -100,7 +98,7 @@ export async function signup(opts: { createdAt: new Date(), username: username, usernameLower: username.toLowerCase(), - host: toPunyNullable(host), + host: host == null ? null : toPuny(host), token: secret, isAdmin: (await Users.countBy({ diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 52dd3382f7..734534b3ea 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -240,6 +240,7 @@ import * as ep___notes_conversation from "./endpoints/notes/conversation.js"; import * as ep___notes_create from "./endpoints/notes/create.js"; import * as ep___notes_delete from "./endpoints/notes/delete.js"; import * as ep___notes_edit from "./endpoints/notes/edit.js"; +import * as ep___notes_history from "./endpoints/notes/history.js"; import * as ep___notes_favorites_create from "./endpoints/notes/favorites/create.js"; import * as ep___notes_favorites_delete from "./endpoints/notes/favorites/delete.js"; import * as ep___notes_featured from "./endpoints/notes/featured.js"; @@ -285,7 +286,6 @@ import * as ep___pinnedUsers from "./endpoints/pinned-users.js"; import * as ep___customMotd from "./endpoints/custom-motd.js"; import * as ep___customSplashIcons from "./endpoints/custom-splash-icons.js"; import * as ep___latestVersion from "./endpoints/latest-version.js"; -import * as ep___patrons from "./endpoints/patrons.js"; import * as ep___release from "./endpoints/release.js"; import * as ep___promo_read from "./endpoints/promo/read.js"; import * as ep___requestResetPassword from "./endpoints/request-reset-password.js"; @@ -583,6 +583,7 @@ const eps = [ ["notes/create", ep___notes_create], ["notes/delete", ep___notes_delete], ["notes/edit", ep___notes_edit], + ["notes/history", ep___notes_history], ["notes/favorites/create", ep___notes_favorites_create], ["notes/favorites/delete", ep___notes_favorites_delete], ["notes/featured", ep___notes_featured], @@ -634,7 +635,6 @@ const eps = [ ["custom-motd", ep___customMotd], ["custom-splash-icons", ep___customSplashIcons], ["latest-version", ep___latestVersion], - ["patrons", ep___patrons], ["release", ep___release], ["promo/read", ep___promo_read], ["request-reset-password", ep___requestResetPassword], diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts index 78034917f0..4063af5c5c 100644 --- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts +++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts @@ -16,68 +16,7 @@ export const meta = { type: "object", optional: false, nullable: false, - properties: { - id: { - type: "string", - nullable: false, - optional: false, - format: "id", - example: "xxxxxxxxxx", - }, - createdAt: { - type: "string", - nullable: false, - optional: false, - format: "date-time", - }, - comment: { - type: "string", - nullable: false, - optional: false, - }, - resolved: { - type: "boolean", - nullable: false, - optional: false, - example: false, - }, - reporterId: { - type: "string", - nullable: false, - optional: false, - format: "id", - }, - targetUserId: { - type: "string", - nullable: false, - optional: false, - format: "id", - }, - assigneeId: { - type: "string", - nullable: true, - optional: false, - format: "id", - }, - reporter: { - type: "object", - nullable: false, - optional: false, - ref: "User", - }, - targetUser: { - type: "object", - nullable: false, - optional: false, - ref: "User", - }, - assignee: { - type: "object", - nullable: true, - optional: true, - ref: "User", - }, - }, + ref: "AbuseUserReport", }, }, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts index bfe4d54461..c7a56d3a98 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Ads } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export const meta = { tags: ["admin"], diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 8af778486c..1ae25e62d0 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Announcements } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export const meta = { tags: ["admin"], diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index 8d4e756797..8fa7579ceb 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Emojis, DriveFiles } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { insertModerationLog } from "@/services/insert-moderation-log.js"; import { ApiError } from "@/server/api/error.js"; import rndstr from "rndstr"; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts index fad735b207..424baf4409 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Emojis } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { ApiError } from "@/server/api/error.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index f6a88b8366..9c7a5180d3 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -1,8 +1,7 @@ import define from "@/server/api/define.js"; import { Emojis } from "@/models/index.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { sqlLikeEscape, toPuny } from "backend-rs"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; import { ApiError } from "@/server/api/error.js"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts index 434b679608..98a69090db 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts @@ -1,8 +1,8 @@ import define from "@/server/api/define.js"; import { Emojis } from "@/models/index.js"; -import { makePaginationQuery } from "../../../common/make-pagination-query.js"; +import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import type { Emoji } from "@/models/entities/emoji.js"; -//import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +//import { sqlLikeEscape } from "backend-rs"; import { ApiError } from "@/server/api/error.js"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index bf71cd2503..d4fb8c6e73 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Instances } from "@/models/index.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { toPuny } from "backend-rs"; import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index 653d187c2d..2ebad12ab7 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Instances } from "@/models/index.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { toPuny } from "backend-rs"; export const meta = { tags: ["admin"], diff --git a/packages/backend/src/server/api/endpoints/admin/invite.ts b/packages/backend/src/server/api/endpoints/admin/invite.ts index ebc523d418..d220ae5e4a 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite.ts @@ -1,7 +1,7 @@ import rndstr from "rndstr"; import define from "@/server/api/define.js"; import { RegistrationTickets } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export const meta = { tags: ["admin"], diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index a22fbab8f1..ab04800944 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -1,5 +1,5 @@ import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js"; import define from "@/server/api/define.js"; @@ -24,6 +24,11 @@ export const meta = { optional: false, nullable: false, }, + antennaLimit: { + type: "number", + optional: false, + nullable: false, + }, cacheRemoteFiles: { type: "boolean", optional: false, @@ -466,7 +471,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); return { maintainerName: instance.maintainerName, @@ -487,6 +492,7 @@ export default define(meta, paramDef, async () => { enableGuestTimeline: instance.enableGuestTimeline, driveCapacityPerLocalUserMb: instance.localDriveCapacityMb, driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb, + antennaLimit: instance.antennaLimit, emailRequiredForSignup: instance.emailRequiredForSignup, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index 5fbed130e6..ace0b581d7 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -1,8 +1,7 @@ import define from "@/server/api/define.js"; -// import bcrypt from "bcryptjs"; import rndstr from "rndstr"; import { Users, UserProfiles } from "@/models/index.js"; -import { hashPassword } from "@/misc/password.js"; +import { hashPassword } from "backend-rs"; export const meta = { tags: ["admin"], @@ -48,8 +47,7 @@ export default define(meta, paramDef, async (ps) => { const passwd = rndstr("a-zA-Z0-9", 8); // Generate hash of password - // const hash = bcrypt.hashSync(passwd); - const hash = await hashPassword(passwd); + const hash = hashPassword(passwd); await UserProfiles.update( { diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index 1e6ebeda93..8a892c3606 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -1,6 +1,6 @@ import { Users } from "@/models/index.js"; import define from "@/server/api/define.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["admin"], diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 604ef3a0fc..e5234ea720 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -94,6 +94,7 @@ export const paramDef = { defaultDarkTheme: { type: "string", nullable: true }, localDriveCapacityMb: { type: "integer" }, remoteDriveCapacityMb: { type: "integer" }, + antennaLimit: { type: "integer" }, cacheRemoteFiles: { type: "boolean" }, markLocalFilesNsfwByDefault: { type: "boolean" }, emailRequiredForSignup: { type: "boolean" }, @@ -327,6 +328,10 @@ export default define(meta, paramDef, async (ps, me) => { set.remoteDriveCapacityMb = ps.remoteDriveCapacityMb; } + if (ps.antennaLimit !== undefined) { + set.antennaLimit = ps.antennaLimit; + } + if (ps.cacheRemoteFiles !== undefined) { set.cacheRemoteFiles = ps.cacheRemoteFiles; } diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts index 46df3aa813..aa5dcee044 100644 --- a/packages/backend/src/server/api/endpoints/antennas/create.ts +++ b/packages/backend/src/server/api/endpoints/antennas/create.ts @@ -1,5 +1,5 @@ import define from "@/server/api/define.js"; -import { genId } from "@/misc/gen-id.js"; +import { fetchMeta, genId } from "backend-rs"; import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js"; import { ApiError } from "@/server/api/error.js"; import { publishInternalEvent } from "@/services/stream.js"; @@ -109,10 +109,12 @@ export default define(meta, paramDef, async (ps, user) => { let userList; let userGroupJoining; + const instance = await fetchMeta(true); + const antennas = await Antennas.findBy({ userId: user.id, }); - if (antennas.length > 5 && !user.isAdmin) { + if (antennas.length >= instance.antennaLimit) { throw new ApiError(meta.errors.tooManyAntennas); } diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index cbe0318525..f14b04372f 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -2,7 +2,7 @@ import define from "@/server/api/define.js"; import readNote from "@/services/note/read.js"; import { Antennas, Notes } from "@/models/index.js"; import { redisClient } from "@/db/redis.js"; -import { getTimestamp } from "@/misc/gen-id.js"; +import { getTimestamp } from "backend-rs"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js"; import { generateMutedUserQuery } from "@/server/api/common/generate-muted-user-query.js"; diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index ec9209ecd3..f1d42d8d93 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -4,7 +4,7 @@ import { createNote } from "@/remote/activitypub/models/note.js"; import DbResolver from "@/remote/activitypub/db-resolver.js"; import Resolver from "@/remote/activitypub/resolver.js"; import { ApiError } from "@/server/api/error.js"; -import { extractDbHost } from "@/misc/convert-host.js"; +import { extractHost } from "backend-rs"; import { Users, Notes } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; import type { CacheableLocalUser, User } from "@/models/entities/user.js"; @@ -101,7 +101,7 @@ async function fetchAny( me: CacheableLocalUser | null | undefined, ): Promise | null> { // Wait if blocked. - if (await shouldBlockInstance(extractDbHost(uri))) return null; + if (await shouldBlockInstance(extractHost(uri))) return null; const dbResolver = new DbResolver(); diff --git a/packages/backend/src/server/api/endpoints/app/create.ts b/packages/backend/src/server/api/endpoints/app/create.ts index e32edf1293..0d52d5fbcf 100644 --- a/packages/backend/src/server/api/endpoints/app/create.ts +++ b/packages/backend/src/server/api/endpoints/app/create.ts @@ -1,8 +1,7 @@ import define from "@/server/api/define.js"; import { Apps } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId, secureRndstr } from "backend-rs"; import { unique } from "@/prelude/array.js"; -import { secureRndstr } from "@/misc/secure-rndstr.js"; export const meta = { tags: ["app"], @@ -41,7 +40,7 @@ export default define(meta, paramDef, async (ps, user) => { includeSecret: true, }); // Generate secret - const secret = secureRndstr(32, true); + const secret = secureRndstr(32); // for backward compatibility const permission = unique( diff --git a/packages/backend/src/server/api/endpoints/auth/accept.ts b/packages/backend/src/server/api/endpoints/auth/accept.ts index 088de7863b..f14fa5529e 100644 --- a/packages/backend/src/server/api/endpoints/auth/accept.ts +++ b/packages/backend/src/server/api/endpoints/auth/accept.ts @@ -2,8 +2,7 @@ import * as crypto from "node:crypto"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { AuthSessions, AccessTokens, Apps } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; -import { secureRndstr } from "@/misc/secure-rndstr.js"; +import { genId, secureRndstr } from "backend-rs"; export const meta = { tags: ["auth"], @@ -38,7 +37,7 @@ export default define(meta, paramDef, async (ps, user) => { } // Generate access token - const accessToken = secureRndstr(32, true); + const accessToken = secureRndstr(32); // Fetch exist access token const exist = await AccessTokens.exist({ diff --git a/packages/backend/src/server/api/endpoints/auth/session/generate.ts b/packages/backend/src/server/api/endpoints/auth/session/generate.ts index bd17211044..26a1fddfcb 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/generate.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/generate.ts @@ -3,7 +3,7 @@ import config from "@/config/index.js"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { Apps, AuthSessions } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export const meta = { tags: ["auth"], diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts index 177492ed29..29c6ca029a 100644 --- a/packages/backend/src/server/api/endpoints/channels/create.ts +++ b/packages/backend/src/server/api/endpoints/channels/create.ts @@ -2,7 +2,7 @@ import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { Channels, DriveFiles } from "@/models/index.js"; import type { Channel } from "@/models/entities/channel.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export const meta = { tags: ["channels"], diff --git a/packages/backend/src/server/api/endpoints/channels/follow.ts b/packages/backend/src/server/api/endpoints/channels/follow.ts index 878339827a..fea6ca797b 100644 --- a/packages/backend/src/server/api/endpoints/channels/follow.ts +++ b/packages/backend/src/server/api/endpoints/channels/follow.ts @@ -1,7 +1,7 @@ import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { Channels, ChannelFollowings } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { publishUserEvent } from "@/services/stream.js"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/channels/search.ts b/packages/backend/src/server/api/endpoints/channels/search.ts index b2fab701c5..ed44250a37 100644 --- a/packages/backend/src/server/api/endpoints/channels/search.ts +++ b/packages/backend/src/server/api/endpoints/channels/search.ts @@ -2,7 +2,7 @@ import define from "@/server/api/define.js"; import { Brackets } from "typeorm"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import { Channels } from "@/models/index.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["channels"], diff --git a/packages/backend/src/server/api/endpoints/channels/update.ts b/packages/backend/src/server/api/endpoints/channels/update.ts index 0de7a837a1..fdd21da65f 100644 --- a/packages/backend/src/server/api/endpoints/channels/update.ts +++ b/packages/backend/src/server/api/endpoints/channels/update.ts @@ -83,7 +83,7 @@ export default define(meta, paramDef, async (ps, me) => { await Channels.update(channel.id, { ...(ps.name !== undefined ? { name: ps.name } : {}), ...(ps.description !== undefined ? { description: ps.description } : {}), - ...(banner ? { bannerId: banner.id } : {}), + ...(banner ? { bannerId: banner.id } : { bannerId: null }), }); return await Channels.pack(channel.id, me); diff --git a/packages/backend/src/server/api/endpoints/clips/add-note.ts b/packages/backend/src/server/api/endpoints/clips/add-note.ts index 887c8af083..2c34db5603 100644 --- a/packages/backend/src/server/api/endpoints/clips/add-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/add-note.ts @@ -1,7 +1,7 @@ import define from "@/server/api/define.js"; import { ClipNotes, Clips } from "@/models/index.js"; import { ApiError } from "@/server/api/error.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { getNote } from "@/server/api/common/getters.js"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/clips/create.ts b/packages/backend/src/server/api/endpoints/clips/create.ts index df03b87b04..ae652d75c2 100644 --- a/packages/backend/src/server/api/endpoints/clips/create.ts +++ b/packages/backend/src/server/api/endpoints/clips/create.ts @@ -1,5 +1,5 @@ import define from "@/server/api/define.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { Clips } from "@/models/index.js"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/custom-motd.ts b/packages/backend/src/server/api/endpoints/custom-motd.ts index 2939355b94..ac1012258d 100644 --- a/packages/backend/src/server/api/endpoints/custom-motd.ts +++ b/packages/backend/src/server/api/endpoints/custom-motd.ts @@ -1,5 +1,5 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import define from "@/server/api/define.js"; export const meta = { @@ -27,7 +27,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const motd = await Promise.all(meta.customMotd.map((x) => x)); return motd; }); diff --git a/packages/backend/src/server/api/endpoints/custom-splash-icons.ts b/packages/backend/src/server/api/endpoints/custom-splash-icons.ts index f63a1b9600..4eb35aa3e5 100644 --- a/packages/backend/src/server/api/endpoints/custom-splash-icons.ts +++ b/packages/backend/src/server/api/endpoints/custom-splash-icons.ts @@ -1,5 +1,5 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import define from "@/server/api/define.js"; export const meta = { @@ -27,7 +27,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const icons = await Promise.all(meta.customSplashIcons.map((x) => x)); return icons; }); diff --git a/packages/backend/src/server/api/endpoints/drive.ts b/packages/backend/src/server/api/endpoints/drive.ts index 164e7b8f93..c04f219a9b 100644 --- a/packages/backend/src/server/api/endpoints/drive.ts +++ b/packages/backend/src/server/api/endpoints/drive.ts @@ -1,4 +1,4 @@ -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { DriveFiles } from "@/models/index.js"; import define from "@/server/api/define.js"; @@ -35,7 +35,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); // Calculate drive usage const usage = await DriveFiles.calcDriveUsageOf(user.id); diff --git a/packages/backend/src/server/api/endpoints/drive/files/create.ts b/packages/backend/src/server/api/endpoints/drive/files/create.ts index a3e3fafa2f..44e388a9bd 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/create.ts @@ -2,7 +2,7 @@ import { addFile } from "@/services/drive/add-file.js"; import { DriveFiles } from "@/models/index.js"; import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js"; import { IdentifiableError } from "@/misc/identifiable-error.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { MINUTE } from "@/const.js"; import define from "@/server/api/define.js"; import { apiLogger } from "@/server/api/logger.js"; @@ -96,7 +96,7 @@ export default define( name = null; } - const instanceMeta = await fetchMeta(); + const instanceMeta = await fetchMeta(true); try { // Create file diff --git a/packages/backend/src/server/api/endpoints/drive/folders/create.ts b/packages/backend/src/server/api/endpoints/drive/folders/create.ts index 5581441980..9ea570a6b7 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/create.ts @@ -2,7 +2,7 @@ import { publishDriveStream } from "@/services/stream.js"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { DriveFolders } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export const meta = { tags: ["drive"], diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 27a6dabb49..362ab098fb 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -1,7 +1,6 @@ import define from "@/server/api/define.js"; import { Instances } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { fetchMeta, sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["federation"], @@ -101,7 +100,7 @@ export default define(meta, paramDef, async (ps, me) => { } if (typeof ps.blocked === "boolean") { - const meta = await fetchMeta(true); + const meta = await fetchMeta(false); if (ps.blocked) { if (meta.blockedHosts.length === 0) { return []; @@ -117,7 +116,7 @@ export default define(meta, paramDef, async (ps, me) => { } if (typeof ps.silenced === "boolean") { - const meta = await fetchMeta(true); + const meta = await fetchMeta(false); if (ps.silenced) { if (meta.silencedHosts.length === 0) { return []; diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index c4a6304d05..809d3ee0b1 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Instances } from "@/models/index.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { toPuny } from "backend-rs"; export const meta = { tags: ["federation"], diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts index a74f2165c2..7cf1d9f7c0 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { DriveFiles, GalleryPosts } from "@/models/index.js"; -import { genId } from "@/server/api/../../misc/gen-id.js"; +import { genId } from "backend-rs"; import { GalleryPost } from "@/models/entities/gallery-post.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import { HOUR } from "@/const.js"; diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts index f5ccc5bc68..13f7d82bb2 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts @@ -1,7 +1,7 @@ import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { GalleryPosts, GalleryLikes } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export const meta = { tags: ["gallery"], diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts index 1dc1fb4922..8fb5b23f62 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/search.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Hashtags } from "@/models/index.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["hashtags"], diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index fe8bba95fd..531a494248 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -1,9 +1,8 @@ import { Brackets } from "typeorm"; import define from "@/server/api/define.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta, safeForSql } from "backend-rs"; import { Notes } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; -import { safeForSql } from "@/misc/safe-for-sql.js"; import { normalizeForSearch } from "@/misc/normalize-for-search.js"; /* @@ -67,7 +66,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); const hiddenTags = instance.hiddenTags.map((t) => normalizeForSearch(t)); const now = new Date(); // 5分単位で丸めた現在日時 diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index b4bfadfd02..6c99217e7d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -9,7 +9,7 @@ import { import config from "@/config/index.js"; import { procedures, hash } from "@/server/api/2fa.js"; import { publishMainStream } from "@/services/stream.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8")); @@ -40,8 +40,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); @@ -117,10 +117,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Expired challenge (> 5min old) - if ( - new Date().getTime() - attestationChallenge.createdAt.getTime() >= - 5 * 60 * 1000 - ) { + if (Date.now() - attestationChallenge.createdAt.getTime() >= 5 * 60 * 1000) { throw new Error("expired challenge"); } diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index 78b68216ad..4991e8fc90 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -2,9 +2,8 @@ import define from "@/server/api/define.js"; import { UserProfiles, AttestationChallenges } from "@/models/index.js"; import { promisify } from "node:util"; import * as crypto from "node:crypto"; -import { genId } from "@/misc/gen-id.js"; +import { genId, verifyPassword } from "backend-rs"; import { hash } from "@/server/api/2fa.js"; -import { comparePassword } from "@/misc/password.js"; const randomBytes = promisify(crypto.randomBytes); @@ -25,8 +24,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts index 52e1df39f4..c0e6137d5d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts @@ -3,7 +3,7 @@ import * as QRCode from "qrcode"; import config from "@/config/index.js"; import { UserProfiles } from "@/models/index.js"; import define from "@/server/api/define.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -22,8 +22,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts index 0cdf8780ef..4259d8f70d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts @@ -1,4 +1,4 @@ -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; import define from "@/server/api/define.js"; import { UserProfiles, UserSecurityKeys, Users } from "@/models/index.js"; import { publishMainStream } from "@/services/stream.js"; @@ -21,8 +21,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts index c4e78eecb5..240ff2b34e 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts @@ -1,7 +1,7 @@ import { publishMainStream } from "@/services/stream.js"; import define from "@/server/api/define.js"; import { Users, UserProfiles } from "@/models/index.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -20,8 +20,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/change-password.ts b/packages/backend/src/server/api/endpoints/i/change-password.ts index b0dc8bba60..1634676748 100644 --- a/packages/backend/src/server/api/endpoints/i/change-password.ts +++ b/packages/backend/src/server/api/endpoints/i/change-password.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { UserProfiles } from "@/models/index.js"; -import { hashPassword, comparePassword } from "@/misc/password.js"; +import { hashPassword, verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -20,8 +20,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.currentPassword, profile.password!); + // Compare passwords + const same = verifyPassword(ps.currentPassword, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/delete-account.ts b/packages/backend/src/server/api/endpoints/i/delete-account.ts index 606cde82e1..538798261d 100644 --- a/packages/backend/src/server/api/endpoints/i/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/i/delete-account.ts @@ -1,7 +1,7 @@ import { UserProfiles, Users } from "@/models/index.js"; import { deleteAccount } from "@/services/delete-account.js"; import define from "@/server/api/define.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -24,8 +24,8 @@ export default define(meta, paramDef, async (ps, user) => { return; } - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/import-posts.ts b/packages/backend/src/server/api/endpoints/i/import-posts.ts index b8b52be98f..225306ebc5 100644 --- a/packages/backend/src/server/api/endpoints/i/import-posts.ts +++ b/packages/backend/src/server/api/endpoints/i/import-posts.ts @@ -3,7 +3,7 @@ import { createImportPostsJob } from "@/queue/index.js"; import { ApiError } from "@/server/api/error.js"; import { DriveFiles } from "@/models/index.js"; import { DAY } from "@/const.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; export const meta = { secure: true, @@ -45,7 +45,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); - const instanceMeta = await fetchMeta(); + const instanceMeta = await fetchMeta(true); if (instanceMeta.experimentalFeatures?.postImports === false) throw new ApiError(meta.errors.importsDisabled); diff --git a/packages/backend/src/server/api/endpoints/i/known-as.ts b/packages/backend/src/server/api/endpoints/i/known-as.ts index 070d6d7f00..9eaeedb39f 100644 --- a/packages/backend/src/server/api/endpoints/i/known-as.ts +++ b/packages/backend/src/server/api/endpoints/i/known-as.ts @@ -8,7 +8,7 @@ import { DAY } from "@/const.js"; import { apiLogger } from "@/server/api/logger.js"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; -import { parse } from "@/misc/acct.js"; +import { stringToAcct } from "backend-rs"; import { inspect } from "node:util"; export const meta = { @@ -72,7 +72,7 @@ export default define(meta, paramDef, async (ps, user) => { for (const line of ps.alsoKnownAs) { if (!line) throw new ApiError(meta.errors.noSuchUser); - const { username, host } = parse(line); + const { username, host } = stringToAcct(line); const aka = await resolveUser(username, host).catch((e) => { apiLogger.warn(`failed to resolve remote user:\n${inspect(e)}`); diff --git a/packages/backend/src/server/api/endpoints/i/move.ts b/packages/backend/src/server/api/endpoints/i/move.ts index 53379c76c3..4784d3ee20 100644 --- a/packages/backend/src/server/api/endpoints/i/move.ts +++ b/packages/backend/src/server/api/endpoints/i/move.ts @@ -12,7 +12,7 @@ import { getUser } from "@/server/api/common/getters.js"; import { Followings, Users } from "@/models/index.js"; import config from "@/config/index.js"; import { publishMainStream } from "@/services/stream.js"; -import { parse } from "@/misc/acct.js"; +import { stringToAcct } from "backend-rs"; import { inspect } from "node:util"; export const meta = { @@ -90,7 +90,7 @@ export default define(meta, paramDef, async (ps, user) => { if (!ps.moveToAccount) throw new ApiError(meta.errors.noSuchMoveTarget); if (user.movedToUri) throw new ApiError(meta.errors.alreadyMoved); - const { username, host } = parse(ps.moveToAccount); + const { username, host } = stringToAcct(ps.moveToAccount); if (!host) throw new ApiError(meta.errors.notRemote); const moveTo: User = await resolveUser(username, host).catch((e) => { diff --git a/packages/backend/src/server/api/endpoints/i/read-announcement.ts b/packages/backend/src/server/api/endpoints/i/read-announcement.ts index a59d15b994..140eecfe67 100644 --- a/packages/backend/src/server/api/endpoints/i/read-announcement.ts +++ b/packages/backend/src/server/api/endpoints/i/read-announcement.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { AnnouncementReads, Announcements, Users } from "@/models/index.js"; import { publishMainStream } from "@/services/stream.js"; diff --git a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts index c1b4325adb..fd3023ab7a 100644 --- a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts +++ b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts @@ -6,7 +6,7 @@ import { import generateUserToken from "@/server/api/common/generate-native-user-token.js"; import define from "@/server/api/define.js"; import { Users, UserProfiles } from "@/models/index.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -28,8 +28,8 @@ export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/registry/set.ts b/packages/backend/src/server/api/endpoints/i/registry/set.ts index 7a1f8ab5f7..7090f0914b 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/set.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/set.ts @@ -1,7 +1,7 @@ import { publishMainStream } from "@/services/stream.js"; import define from "@/server/api/define.js"; import { RegistryItems } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export const meta = { requireCredential: true, diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts index a48252ed1a..234127f584 100644 --- a/packages/backend/src/server/api/endpoints/i/update-email.ts +++ b/packages/backend/src/server/api/endpoints/i/update-email.ts @@ -7,7 +7,7 @@ import { sendEmail } from "@/services/send-email.js"; import { ApiError } from "@/server/api/error.js"; import { validateEmailForAccount } from "@/services/validate-email-for-account.js"; import { HOUR } from "@/const.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -46,8 +46,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new ApiError(meta.errors.incorrectPassword); diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 08bf885d49..4f65c59a9e 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -1,4 +1,3 @@ -import RE2 from "re2"; import * as mfm from "mfm-js"; import { publishMainStream, publishUserEvent } from "@/services/stream.js"; import acceptAllFollowRequests from "@/services/following/requests/accept-all.js"; @@ -14,6 +13,7 @@ import { normalizeForSearch } from "@/misc/normalize-for-search.js"; import { verifyLink } from "@/services/fetch-rel-me.js"; import { ApiError } from "@/server/api/error.js"; import define from "@/server/api/define.js"; +import { DriveFile } from "@/models/entities/drive-file"; export const meta = { tags: ["account"], @@ -242,8 +242,9 @@ export default define(meta, paramDef, async (ps, _user, token) => { if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes; + let avatar: DriveFile | null = null; if (ps.avatarId) { - const avatar = await DriveFiles.findOneBy({ id: ps.avatarId }); + avatar = await DriveFiles.findOneBy({ id: ps.avatarId }); if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar); @@ -251,8 +252,9 @@ export default define(meta, paramDef, async (ps, _user, token) => { throw new ApiError(meta.errors.avatarNotAnImage); } + let banner: DriveFile | null = null; if (ps.bannerId) { - const banner = await DriveFiles.findOneBy({ id: ps.bannerId }); + banner = await DriveFiles.findOneBy({ id: ps.bannerId }); if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner); @@ -329,6 +331,20 @@ export default define(meta, paramDef, async (ps, _user, token) => { updateUsertags(user, tags); //#endregion + // Update old/new avatar usage hints + if (avatar) { + if (user.avatarId) + await DriveFiles.update(user.avatarId, { usageHint: null }); + await DriveFiles.update(avatar.id, { usageHint: "userAvatar" }); + } + + // Update old/new banner usage hints + if (banner) { + if (user.bannerId) + await DriveFiles.update(user.bannerId, { usageHint: null }); + await DriveFiles.update(banner.id, { usageHint: "userBanner" }); + } + if (Object.keys(updates).length > 0) await Users.update(user.id, updates); if (Object.keys(profileUpdates).length > 0) await UserProfiles.update(user.id, profileUpdates); diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts index ee38b76372..4faae058c3 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts @@ -1,5 +1,5 @@ import define from "@/server/api/define.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { Webhooks } from "@/models/index.js"; import { publishInternalEvent } from "@/services/stream.js"; import { webhookEventTypes } from "@/models/entities/webhook.js"; diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 2a674b52c3..ec8f701976 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -1,7 +1,7 @@ import JSON5 from "json5"; import { IsNull, MoreThan } from "typeorm"; import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Ads, Emojis, Users } from "@/models/index.js"; import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js"; import define from "@/server/api/define.js"; @@ -126,6 +126,11 @@ export const meta = { optional: false, nullable: false, }, + antennaLimit: { + type: "number", + optional: false, + nullable: false, + }, cacheRemoteFiles: { type: "boolean", optional: false, @@ -398,7 +403,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, me) => { - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); const emojis = await Emojis.find({ where: { @@ -445,6 +450,7 @@ export default define(meta, paramDef, async (ps, me) => { enableGuestTimeline: instance.enableGuestTimeline, driveCapacityPerLocalUserMb: instance.localDriveCapacityMb, driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb, + antennaLimit: instance.antennaLimit, emailRequiredForSignup: instance.emailRequiredForSignup, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, diff --git a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts index bca09d3f07..d1527c51cf 100644 --- a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts +++ b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts @@ -1,7 +1,6 @@ import define from "@/server/api/define.js"; import { AccessTokens } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; -import { secureRndstr } from "@/misc/secure-rndstr.js"; +import { genId, secureRndstr } from "backend-rs"; export const meta = { tags: ["auth"], @@ -44,7 +43,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { // Generate access token - const accessToken = secureRndstr(32, true); + const accessToken = secureRndstr(32); const now = new Date(); diff --git a/packages/backend/src/server/api/endpoints/mute/create.ts b/packages/backend/src/server/api/endpoints/mute/create.ts index 2eb935198e..a8d37153a4 100644 --- a/packages/backend/src/server/api/endpoints/mute/create.ts +++ b/packages/backend/src/server/api/endpoints/mute/create.ts @@ -1,7 +1,7 @@ import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { getUser } from "@/server/api/common/getters.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { Mutings, NoteWatchings } from "@/models/index.js"; import type { Muting } from "@/models/entities/muting.js"; import { publishUserEvent } from "@/services/stream.js"; diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 270c33abd0..c2302f4c8d 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -114,7 +114,7 @@ export const paramDef = { enum: Object.keys(langmap), nullable: true, }, - cw: { type: "string", nullable: true, maxLength: 100 }, + cw: { type: "string", nullable: true, maxLength: MAX_NOTE_TEXT_LENGTH }, localOnly: { type: "boolean", default: false }, noExtractMentions: { type: "boolean", default: false }, noExtractHashtags: { type: "boolean", default: false }, diff --git a/packages/backend/src/server/api/endpoints/notes/edit.ts b/packages/backend/src/server/api/endpoints/notes/edit.ts index 34d94157e6..60d5258ce9 100644 --- a/packages/backend/src/server/api/endpoints/notes/edit.ts +++ b/packages/backend/src/server/api/endpoints/notes/edit.ts @@ -26,7 +26,7 @@ import { concat } from "@/prelude/array.js"; import { extractHashtags } from "@/misc/extract-hashtags.js"; import { extractCustomEmojisFromMfm } from "@/misc/extract-custom-emojis-from-mfm.js"; import { extractMentionedUsers } from "@/services/note/create.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { publishNoteStream } from "@/services/stream.js"; import DeliverManager from "@/remote/activitypub/deliver-manager.js"; import { renderActivity } from "@/remote/activitypub/renderer/index.js"; @@ -621,6 +621,7 @@ export default define(meta, paramDef, async (ps, user) => { cw: note.cw, fileIds: note.fileIds, updatedAt: new Date(), + emojis: note.emojis, }); publishing = true; @@ -639,7 +640,7 @@ export default define(meta, paramDef, async (ps, user) => { (async () => { const noteActivity = await renderNote(note, false); - noteActivity.updated = note.updatedAt.toISOString(); + noteActivity.updated = new Date().toISOString(); const updateActivity = renderUpdate(noteActivity, user); updateActivity.to = noteActivity.to; updateActivity.cc = noteActivity.cc; diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts index 8b2c7ad3a4..e2c7ca951f 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts @@ -1,5 +1,5 @@ import { NoteFavorites } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { getNote } from "@/server/api/common/getters.js"; diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index 142b380f71..476375dc0b 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -1,4 +1,4 @@ -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Notes } from "@/models/index.js"; import { activeUsersChart } from "@/services/chart/index.js"; import define from "@/server/api/define.js"; @@ -64,7 +64,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const m = await fetchMeta(); + const m = await fetchMeta(true); if (m.disableGlobalTimeline) { if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.gtlDisabled); diff --git a/packages/backend/src/server/api/endpoints/notes/history.ts b/packages/backend/src/server/api/endpoints/notes/history.ts new file mode 100644 index 0000000000..b6677743bb --- /dev/null +++ b/packages/backend/src/server/api/endpoints/notes/history.ts @@ -0,0 +1,67 @@ +import { NoteEdits } from "@/models/index.js"; +import define from "@/server/api/define.js"; +import { ApiError } from "@/server/api/error.js"; +import { getNote } from "@/server/api/common/getters.js"; +import type { NoteEdit } from "@/models/entities/note-edit.js"; + +export const meta = { + tags: ["notes"], + + requireCredential: false, + requireCredentialPrivateMode: true, + description: "Get edit history of a note", + + res: { + type: "array", + optional: false, + nullable: true, + items: { + type: "object", + optional: false, + nullable: false, + ref: "NoteEdit", + }, + }, + + errors: { + noSuchNote: { + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "e1035875-9551-45ec-afa8-1ded1fcb53c8", + }, + }, +} as const; + +export const paramDef = { + type: "object", + properties: { + noteId: { + type: "string", + format: "misskey:id", + }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, + }, + required: ["noteId"], +} as const; + +export default define(meta, paramDef, async (ps, user) => { + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); + throw err; + }); + + const history: NoteEdit[] = await NoteEdits.find({ + where: { + noteId: note.id, + }, + take: ps.limit, + skip: ps.offset, + order: { + id: "DESC", + }, + }); + + return await NoteEdits.packMany(history, note); +}); diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index c9800f2e1f..e6ab910040 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -1,5 +1,5 @@ import { Brackets } from "typeorm"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Followings, Notes } from "@/models/index.js"; import { activeUsersChart } from "@/services/chart/index.js"; import define from "@/server/api/define.js"; @@ -71,7 +71,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const m = await fetchMeta(); + const m = await fetchMeta(true); if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { throw new ApiError(meta.errors.stlDisabled); } diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index b9cb68c2a0..2a99c1236c 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -1,5 +1,5 @@ import { Brackets } from "typeorm"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Notes } from "@/models/index.js"; import { activeUsersChart } from "@/services/chart/index.js"; import define from "@/server/api/define.js"; @@ -74,7 +74,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const m = await fetchMeta(); + const m = await fetchMeta(true); if (m.disableLocalTimeline) { if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.ltlDisabled); diff --git a/packages/backend/src/server/api/endpoints/notes/make-private.ts b/packages/backend/src/server/api/endpoints/notes/make-private.ts index 7b9ebc4d1a..5ddf1f3bf1 100644 --- a/packages/backend/src/server/api/endpoints/notes/make-private.ts +++ b/packages/backend/src/server/api/endpoints/notes/make-private.ts @@ -53,7 +53,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.accessDenied); } - await deleteNote(user, note, false, false); + await deleteNote(user, note, false); await Notes.update(note.id, { visibility: "specified", visibleUserIds: [], diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index 1680eca640..9f67404875 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -12,7 +12,7 @@ import { Blockings, } from "@/models/index.js"; import type { IRemoteUser } from "@/models/entities/user.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { getNote } from "@/server/api/common/getters.js"; import { ApiError } from "@/server/api/error.js"; import define from "@/server/api/define.js"; diff --git a/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts b/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts index f71822f926..073a8f8569 100644 --- a/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts @@ -1,5 +1,5 @@ import { Brackets } from "typeorm"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Notes } from "@/models/index.js"; import { activeUsersChart } from "@/services/chart/index.js"; import define from "@/server/api/define.js"; @@ -74,7 +74,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const m = await fetchMeta(); + const m = await fetchMeta(true); if (m.disableRecommendedTimeline) { if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.rtlDisabled); diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index e87725e342..f449ea081a 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -1,6 +1,6 @@ import { Brackets } from "typeorm"; import { Notes } from "@/models/index.js"; -import { safeForSql } from "@/misc/safe-for-sql.js"; +import { safeForSql } from "backend-rs"; import { normalizeForSearch } from "@/misc/normalize-for-search.js"; import define from "@/server/api/define.js"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index b159a91944..f28208cba9 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -1,11 +1,11 @@ import { Notes } from "@/models/index.js"; -import { Note } from "@/models/entities/note.js"; +import type { Note } from "@/models/entities/note.js"; import define from "@/server/api/define.js"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js"; import { generateMutedUserQuery } from "@/server/api/common/generate-muted-user-query.js"; import { generateBlockedUserQuery } from "@/server/api/common/generate-block-query.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; import type { SelectQueryBuilder } from "typeorm"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts index 7c40a45923..b666e05835 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts @@ -1,5 +1,5 @@ import { Notes, NoteThreadMutings } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import readNote from "@/services/note/read.js"; import define from "@/server/api/define.js"; import { getNote } from "@/server/api/common/getters.js"; diff --git a/packages/backend/src/server/api/endpoints/pages/create.ts b/packages/backend/src/server/api/endpoints/pages/create.ts index ea0f8ba83e..35ab2d0450 100644 --- a/packages/backend/src/server/api/endpoints/pages/create.ts +++ b/packages/backend/src/server/api/endpoints/pages/create.ts @@ -1,5 +1,5 @@ import { Pages, DriveFiles } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { Page } from "@/models/entities/page.js"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; diff --git a/packages/backend/src/server/api/endpoints/pages/like.ts b/packages/backend/src/server/api/endpoints/pages/like.ts index ab64b9b93e..1480b47e0b 100644 --- a/packages/backend/src/server/api/endpoints/pages/like.ts +++ b/packages/backend/src/server/api/endpoints/pages/like.ts @@ -1,5 +1,5 @@ import { Pages, PageLikes } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; diff --git a/packages/backend/src/server/api/endpoints/patrons.ts b/packages/backend/src/server/api/endpoints/patrons.ts deleted file mode 100644 index 7da72eb81e..0000000000 --- a/packages/backend/src/server/api/endpoints/patrons.ts +++ /dev/null @@ -1,33 +0,0 @@ -import define from "@/server/api/define.js"; -import * as fs from "node:fs/promises"; -import { fileURLToPath } from "node:url"; -import { dirname } from "node:path"; - -const _filename = fileURLToPath(import.meta.url); -const _dirname = dirname(_filename); - -export const meta = { - tags: ["meta"], - description: "Get Firefish patrons", - - requireCredential: false, - requireCredentialPrivateMode: false, -} as const; - -export const paramDef = { - type: "object", - properties: { - forceUpdate: { type: "boolean", default: false }, - }, - required: [], -} as const; - -export default define(meta, paramDef, async (ps) => { - const patrons = JSON.parse( - await fs.readFile(`${_dirname}/../../../../../../patrons.json`, "utf-8"), - ); - return { - patrons: patrons.patrons, - sponsors: patrons.sponsors, - }; -}); diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index b327378700..65241becae 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -1,7 +1,7 @@ import { IsNull } from "typeorm"; import { Users } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import * as Acct from "@/misc/acct.js"; +import { fetchMeta } from "backend-rs"; +import { stringToAcct } from "backend-rs"; import type { User } from "@/models/entities/user.js"; import define from "@/server/api/define.js"; @@ -31,11 +31,11 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, me) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const users = await Promise.all( meta.pinnedUsers - .map((acct) => Acct.parse(acct)) + .map((acct) => stringToAcct(acct)) .map((acct) => Users.findOneBy({ usernameLower: acct.username.toLowerCase(), @@ -44,9 +44,7 @@ export default define(meta, paramDef, async (ps, me) => { ), ); - return await Users.packMany( - users.filter((x) => x !== undefined) as User[], - me, - { detail: true }, - ); + return await Users.packMany(users.filter((x) => x != null) as User[], me, { + detail: true, + }); }); diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts index 4b41467906..0509548b05 100644 --- a/packages/backend/src/server/api/endpoints/promo/read.ts +++ b/packages/backend/src/server/api/endpoints/promo/read.ts @@ -1,5 +1,5 @@ import { PromoReads } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { getNote } from "@/server/api/common/getters.js"; diff --git a/packages/backend/src/server/api/endpoints/recommended-instances.ts b/packages/backend/src/server/api/endpoints/recommended-instances.ts index b235678428..5c5e267b2e 100644 --- a/packages/backend/src/server/api/endpoints/recommended-instances.ts +++ b/packages/backend/src/server/api/endpoints/recommended-instances.ts @@ -1,5 +1,5 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import define from "@/server/api/define.js"; export const meta = { @@ -27,7 +27,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const instances = await Promise.all(meta.recommendedInstances.map((x) => x)); return instances; }); diff --git a/packages/backend/src/server/api/endpoints/renote-mute/create.ts b/packages/backend/src/server/api/endpoints/renote-mute/create.ts index afe23f38da..46535cb39d 100644 --- a/packages/backend/src/server/api/endpoints/renote-mute/create.ts +++ b/packages/backend/src/server/api/endpoints/renote-mute/create.ts @@ -1,4 +1,4 @@ -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { RenoteMutings } from "@/models/index.js"; import { RenoteMuting } from "@/models/entities/renote-muting.js"; import define from "@/server/api/define.js"; diff --git a/packages/backend/src/server/api/endpoints/reply-mute/create.ts b/packages/backend/src/server/api/endpoints/reply-mute/create.ts index defe44ac05..fc8644a7e1 100644 --- a/packages/backend/src/server/api/endpoints/reply-mute/create.ts +++ b/packages/backend/src/server/api/endpoints/reply-mute/create.ts @@ -1,4 +1,4 @@ -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { ReplyMutings } from "@/models/index.js"; import { ReplyMuting } from "@/models/entities/reply-muting.js"; import define from "@/server/api/define.js"; diff --git a/packages/backend/src/server/api/endpoints/request-reset-password.ts b/packages/backend/src/server/api/endpoints/request-reset-password.ts index 3c78058af2..9855b06513 100644 --- a/packages/backend/src/server/api/endpoints/request-reset-password.ts +++ b/packages/backend/src/server/api/endpoints/request-reset-password.ts @@ -3,7 +3,7 @@ import { IsNull } from "typeorm"; import config from "@/config/index.js"; import { Users, UserProfiles, PasswordResetRequests } from "@/models/index.js"; import { sendEmail } from "@/services/send-email.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import define from "@/server/api/define.js"; import { HOUR } from "@/const.js"; diff --git a/packages/backend/src/server/api/endpoints/reset-password.ts b/packages/backend/src/server/api/endpoints/reset-password.ts index ff5c8d987f..b69b1b17d3 100644 --- a/packages/backend/src/server/api/endpoints/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/reset-password.ts @@ -1,6 +1,6 @@ import { UserProfiles, PasswordResetRequests } from "@/models/index.js"; import define from "@/server/api/define.js"; -import { hashPassword } from "@/misc/password.js"; +import { hashPassword } from "backend-rs"; export const meta = { tags: ["reset password"], @@ -32,7 +32,7 @@ export default define(meta, paramDef, async (ps, user) => { } // Generate hash of password - const hash = await hashPassword(ps.password); + const hash = hashPassword(ps.password); await UserProfiles.update(req.userId, { password: hash, diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index d3b6a08074..1a1ecad688 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -1,7 +1,7 @@ import * as os from "node:os"; import si from "systeminformation"; import define from "@/server/api/define.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; export const meta = { requireCredential: false, @@ -30,7 +30,7 @@ export default define(meta, paramDef, async () => { } } - const instanceMeta = await fetchMeta(); + const instanceMeta = await fetchMeta(true); if (!instanceMeta.enableServerMachineStats) { return { machine: "Not specified", diff --git a/packages/backend/src/server/api/endpoints/sw/register.ts b/packages/backend/src/server/api/endpoints/sw/register.ts index ee6b3bbf45..69b3f6779b 100644 --- a/packages/backend/src/server/api/endpoints/sw/register.ts +++ b/packages/backend/src/server/api/endpoints/sw/register.ts @@ -1,5 +1,5 @@ -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { genId } from "@/misc/gen-id.js"; +import { fetchMeta } from "backend-rs"; +import { genId } from "backend-rs"; import { SwSubscriptions } from "@/models/index.js"; import define from "@/server/api/define.js"; @@ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, me) => { publickey: ps.publickey, }); - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); // if already subscribed if (subscription != null) { diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index cec7a04b3c..ab1cac2442 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -1,6 +1,6 @@ import { IsNull } from "typeorm"; import { Users, Followings, UserProfiles } from "@/models/index.js"; -import { toPunyNullable } from "@/misc/convert-host.js"; +import { toPuny } from "backend-rs"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; @@ -80,7 +80,7 @@ export default define(meta, paramDef, async (ps, me) => { ? { id: ps.userId } : { usernameLower: ps.username!.toLowerCase(), - host: toPunyNullable(ps.host) ?? IsNull(), + host: ps.host == null ? IsNull() : toPuny(ps.host), }, ); diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 68e6cb6d06..05ab3602b0 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -1,6 +1,6 @@ import { IsNull } from "typeorm"; import { Users, Followings, UserProfiles } from "@/models/index.js"; -import { toPunyNullable } from "@/misc/convert-host.js"; +import { toPuny } from "backend-rs"; import define from "@/server/api/define.js"; import { ApiError } from "@/server/api/error.js"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; @@ -79,7 +79,7 @@ export default define(meta, paramDef, async (ps, me) => { ? { id: ps.userId } : { usernameLower: ps.username!.toLowerCase(), - host: toPunyNullable(ps.host) ?? IsNull(), + host: ps.host == null ? IsNull() : toPuny(ps.host), }, ); diff --git a/packages/backend/src/server/api/endpoints/users/groups/create.ts b/packages/backend/src/server/api/endpoints/users/groups/create.ts index 1cfb223013..e6ff909343 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/create.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/create.ts @@ -1,5 +1,5 @@ import { UserGroups, UserGroupJoinings } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import type { UserGroup } from "@/models/entities/user-group.js"; import type { UserGroupJoining } from "@/models/entities/user-group-joining.js"; import define from "@/server/api/define.js"; diff --git a/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts index a483ccd184..f86f415d7a 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts @@ -1,5 +1,5 @@ import { UserGroupJoinings, UserGroupInvitations } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import type { UserGroupJoining } from "@/models/entities/user-group-joining.js"; import { ApiError } from "@/server/api/error.js"; import define from "@/server/api/define.js"; diff --git a/packages/backend/src/server/api/endpoints/users/groups/invite.ts b/packages/backend/src/server/api/endpoints/users/groups/invite.ts index 8a1e6b31ed..62e13a4458 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invite.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invite.ts @@ -3,7 +3,7 @@ import { UserGroupJoinings, UserGroupInvitations, } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import type { UserGroupInvitation } from "@/models/entities/user-group-invitation.js"; import { createNotification } from "@/services/create-notification.js"; import { getUser } from "@/server/api/common/getters.js"; diff --git a/packages/backend/src/server/api/endpoints/users/lists/create.ts b/packages/backend/src/server/api/endpoints/users/lists/create.ts index c23e8f6f53..fa10bf24ce 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create.ts @@ -1,5 +1,5 @@ import { UserLists } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import type { UserList } from "@/models/entities/user-list.js"; import define from "@/server/api/define.js"; diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index 7e9ba7238c..fda4aa0bb8 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -2,9 +2,9 @@ import * as mfm from "mfm-js"; import sanitizeHtml from "sanitize-html"; import { publishAdminStream } from "@/services/stream.js"; import { AbuseUserReports, UserProfiles, Users } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { sendEmail } from "@/services/send-email.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { getUser } from "@/server/api/common/getters.js"; import { ApiError } from "@/server/api/error.js"; import define from "@/server/api/define.js"; @@ -86,7 +86,7 @@ export default define(meta, paramDef, async (ps, me) => { ], }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); for (const moderator of moderators) { publishAdminStream(moderator.id, "newAbuseUserReport", { id: report.id, diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index 517ef615b1..fe15ae18c0 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -2,7 +2,7 @@ import { Brackets } from "typeorm"; import { Followings, Users } from "@/models/index.js"; import type { User } from "@/models/entities/user.js"; import define from "@/server/api/define.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["users"], diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index a15a0feb4b..df0701709b 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -2,7 +2,7 @@ import { Brackets } from "typeorm"; import { UserProfiles, Users } from "@/models/index.js"; import type { User } from "@/models/entities/user.js"; import define from "@/server/api/define.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["users"], diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts index 1bb8ad4939..493661b2a2 100644 --- a/packages/backend/src/server/api/index.ts +++ b/packages/backend/src/server/api/index.ts @@ -23,13 +23,8 @@ import verifyEmail from "./private/verify-email.js"; import { koaBody } from "koa-body"; import { convertAttachment } from "./mastodon/converters.js"; import { apiLogger } from "./logger.js"; - -import { convertId, IdConvertType as IdType } from "backend-rs"; import { inspect } from "node:util"; -// re-export native rust id conversion (function and enum) -export { IdType, convertId }; - // Init app const app = new Koa(); diff --git a/packages/backend/src/server/api/limiter.ts b/packages/backend/src/server/api/limiter.ts index f03f8754cf..d4a9353ade 100644 --- a/packages/backend/src/server/api/limiter.ts +++ b/packages/backend/src/server/api/limiter.ts @@ -2,7 +2,7 @@ import Limiter from "ratelimiter"; import Logger from "@/services/logger.js"; import { redisClient } from "@/db/redis.js"; import type { IEndpointMeta } from "./endpoints.js"; -import { convertMilliseconds } from "@/misc/convert-milliseconds.js"; +import { formatMilliseconds } from "backend-rs"; const logger = new Logger("limiter"); @@ -78,7 +78,7 @@ export const limiter = ( if (info.remaining === 0) { reject({ message: "RATE_LIMIT_EXCEEDED", - remainingTime: convertMilliseconds(info.resetMs - Date.now()), + remainingTime: formatMilliseconds(info.resetMs - Date.now()), }); } else { ok(); diff --git a/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts b/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts index ec3600537c..4c072b0e7b 100644 --- a/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts +++ b/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts @@ -13,7 +13,7 @@ import { convertAnnouncement, convertFilter, } from "./converters.js"; -import { convertId, IdType } from "@/server/api/index.js"; +import { fromMastodonId } from "backend-rs"; import { Users } from "@/models/index.js"; import { IsNull } from "typeorm"; import { apiLogger } from "../logger.js"; @@ -105,7 +105,7 @@ export function apiMastodonCompatible(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.dismissInstanceAnnouncement( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = data.data; } catch (e: any) { diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index 30506d9c51..b2259e6ed5 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -1,10 +1,10 @@ -import { Entity } from "megalodon"; -import { convertId, IdType } from "@/server/api/index.js"; +import type { Entity } from "megalodon"; +import { toMastodonId } from "backend-rs"; function simpleConvert(data: any) { // copy the object to bypass weird pass by reference bugs const result = Object.assign({}, data); - result.id = convertId(data.id, IdType.MastodonId); + result.id = toMastodonId(data.id); return result; } @@ -15,7 +15,19 @@ export function convertAnnouncement(announcement: Entity.Announcement) { return simpleConvert(announcement); } export function convertAttachment(attachment: Entity.Attachment) { - return simpleConvert(attachment); + const converted = simpleConvert(attachment); + // ref: https://github.com/whitescent/Mastify/pull/102 + if (converted.meta == null) return converted; + const result = { + ...converted, + meta: { + ...converted.meta, + original: { + ...converted.meta, + }, + }, + }; + return result; } export function convertFilter(filter: Entity.Filter) { return simpleConvert(filter); @@ -29,7 +41,7 @@ export function convertFeaturedTag(tag: Entity.FeaturedTag) { export function convertNotification(notification: Entity.Notification) { notification.account = convertAccount(notification.account); - notification.id = convertId(notification.id, IdType.MastodonId); + notification.id = toMastodonId(notification.id); if (notification.status) notification.status = convertStatus(notification.status); if (notification.reaction) @@ -52,20 +64,17 @@ export function convertRelationship(relationship: Entity.Relationship) { export function convertStatus(status: Entity.Status) { status.account = convertAccount(status.account); - status.id = convertId(status.id, IdType.MastodonId); + status.id = toMastodonId(status.id); if (status.in_reply_to_account_id) - status.in_reply_to_account_id = convertId( - status.in_reply_to_account_id, - IdType.MastodonId, - ); + status.in_reply_to_account_id = toMastodonId(status.in_reply_to_account_id); if (status.in_reply_to_id) - status.in_reply_to_id = convertId(status.in_reply_to_id, IdType.MastodonId); + status.in_reply_to_id = toMastodonId(status.in_reply_to_id); status.media_attachments = status.media_attachments.map((attachment) => convertAttachment(attachment), ); status.mentions = status.mentions.map((mention) => ({ ...mention, - id: convertId(mention.id, IdType.MastodonId), + id: toMastodonId(mention.id), })); if (status.poll) status.poll = convertPoll(status.poll); if (status.reblog) status.reblog = convertStatus(status.reblog); @@ -76,7 +85,7 @@ export function convertStatus(status: Entity.Status) { } export function convertConversation(conversation: Entity.Conversation) { - conversation.id = convertId(conversation.id, IdType.MastodonId); + conversation.id = toMastodonId(conversation.id); conversation.accounts = conversation.accounts.map(convertAccount); if (conversation.last_status) { conversation.last_status = convertStatus(conversation.last_status); diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index a6f953677c..2b58a1ed8c 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -1,7 +1,7 @@ import Router from "@koa/router"; import { getClient } from "../ApiMastodonCompatibleService.js"; import { argsToBools, convertTimelinesArgsId, limitToInt } from "./timeline.js"; -import { convertId, IdType } from "@/server/api/index.js"; +import { fromMastodonId, toMastodonId } from "backend-rs"; import { convertAccount, convertFeaturedTag, @@ -37,7 +37,7 @@ export function apiAccountMastodon(router: Router): void { try { const data = await client.verifyAccountCredentials(); let acct = data.data; - acct.id = convertId(acct.id, IdType.MastodonId); + acct.id = toMastodonId(acct.id); acct.display_name = acct.display_name || acct.username; acct.url = `${BASE_URL}/@${acct.url}`; acct.note = acct.note || ""; @@ -110,7 +110,7 @@ export function apiAccountMastodon(router: Router): void { let reqIds = []; for (let i = 0; i < ids.length; i++) { - reqIds.push(convertId(ids[i], IdType.FirefishId)); + reqIds.push(fromMastodonId(ids[i])); } const data = await client.getRelationships(reqIds); @@ -130,7 +130,7 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const calcId = convertId(ctx.params.id, IdType.FirefishId); + const calcId = fromMastodonId(ctx.params.id); const data = await client.getAccount(calcId); ctx.body = convertAccount(data.data); } catch (e: any) { @@ -147,7 +147,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountStatuses( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), convertTimelinesArgsId(argsToBools(limitToInt(ctx.query as any))), ); ctx.body = data.data.map((status) => convertStatus(status)); @@ -166,7 +166,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountFeaturedTags( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = data.data.map((tag) => convertFeaturedTag(tag)); } catch (e: any) { @@ -184,7 +184,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountFollowers( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), convertTimelinesArgsId(limitToInt(ctx.query as any)), ); ctx.body = data.data.map((account) => convertAccount(account)); @@ -203,7 +203,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountFollowing( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), convertTimelinesArgsId(limitToInt(ctx.query as any)), ); ctx.body = data.data.map((account) => convertAccount(account)); @@ -222,7 +222,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountLists( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = data.data.map((list) => convertList(list)); } catch (e: any) { @@ -239,9 +239,7 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.followAccount( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.followAccount(fromMastodonId(ctx.params.id)); let acct = convertRelationship(data.data); acct.following = true; ctx.body = acct; @@ -260,7 +258,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.unfollowAccount( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); let acct = convertRelationship(data.data); acct.following = false; @@ -279,9 +277,7 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.blockAccount( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.blockAccount(fromMastodonId(ctx.params.id)); ctx.body = convertRelationship(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -297,9 +293,7 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unblockAccount( - convertId(ctx.params.id, IdType.MastodonId), - ); + const data = await client.unblockAccount(toMastodonId(ctx.params.id)); ctx.body = convertRelationship(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -316,7 +310,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.muteAccount( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), (ctx.request as any).body as any, ); ctx.body = convertRelationship(data.data); @@ -334,9 +328,7 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unmuteAccount( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.unmuteAccount(fromMastodonId(ctx.params.id)); ctx.body = convertRelationship(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -454,7 +446,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.acceptFollowRequest( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = convertRelationship(data.data); } catch (e: any) { @@ -472,7 +464,7 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.rejectFollowRequest( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = convertRelationship(data.data); } catch (e: any) { diff --git a/packages/backend/src/server/api/mastodon/endpoints/filter.ts b/packages/backend/src/server/api/mastodon/endpoints/filter.ts index 30fb1e1eab..4b961bfe0b 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/filter.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/filter.ts @@ -27,9 +27,7 @@ export function apiFilterMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); const body: any = ctx.request.body; try { - const data = await client.getFilter( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.getFilter(fromMastodonId(ctx.params.id)); ctx.body = convertFilter(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -60,7 +58,7 @@ export function apiFilterMastodon(router: Router): void { const body: any = ctx.request.body; try { const data = await client.updateFilter( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), body.phrase, body.context, ); @@ -78,9 +76,7 @@ export function apiFilterMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); const body: any = ctx.request.body; try { - const data = await client.deleteFilter( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.deleteFilter(fromMastodonId(ctx.params.id)); ctx.body = data.data; } catch (e: any) { apiLogger.error(inspect(e)); diff --git a/packages/backend/src/server/api/mastodon/endpoints/meta.ts b/packages/backend/src/server/api/mastodon/endpoints/meta.ts index fbad7d5ef4..5c304929a1 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/meta.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/meta.ts @@ -1,6 +1,6 @@ import { Entity } from "megalodon"; import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Users, Notes } from "@/models/index.js"; import { IsNull } from "typeorm"; import { MAX_NOTE_TEXT_LENGTH, FILE_TYPE_BROWSERSAFE } from "@/const.js"; @@ -10,7 +10,7 @@ export async function getInstance( contact: Entity.Account, ) { const [meta, totalUsers, totalStatuses] = await Promise.all([ - fetchMeta(), + fetchMeta(true), Users.count({ where: { host: IsNull() } }), Notes.count({ where: { userHost: IsNull() } }), ]); diff --git a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts index 3df740a91e..23765d7bbb 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts @@ -1,5 +1,5 @@ import Router from "@koa/router"; -import { convertId, IdType } from "@/server/api/index.js"; +import { fromMastodonId } from "backend-rs"; import { getClient } from "../ApiMastodonCompatibleService.js"; import { convertTimelinesArgsId } from "./timeline.js"; import { convertNotification } from "../converters.js"; @@ -46,7 +46,7 @@ export function apiNotificationsMastodon(router: Router): void { const body: any = ctx.request.body; try { const dataRaw = await client.getNotification( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); const data = convertNotification(dataRaw.data); ctx.body = data; @@ -86,7 +86,7 @@ export function apiNotificationsMastodon(router: Router): void { const body: any = ctx.request.body; try { const data = await client.dismissNotification( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = data.data; } catch (e: any) { diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index 33201d9edf..6fa70717e7 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -1,17 +1,15 @@ import Router from "@koa/router"; import { getClient } from "../ApiMastodonCompatibleService.js"; -import { emojiRegexAtStartToEnd } from "@/misc/emoji-regex.js"; import querystring from "node:querystring"; import qs from "qs"; import { convertTimelinesArgsId, limitToInt } from "./timeline.js"; -import { convertId, IdType } from "@/server/api/index.js"; +import { fetchMeta, fromMastodonId, isUnicodeEmoji } from "backend-rs"; import { convertAccount, convertAttachment, convertPoll, convertStatus, } from "../converters.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; import { apiLogger } from "@/server/api/logger.js"; import { inspect } from "node:util"; @@ -28,9 +26,8 @@ export function apiStatusMastodon(router: Router): void { try { let body: any = ctx.request.body; if (body.in_reply_to_id) - body.in_reply_to_id = convertId(body.in_reply_to_id, IdType.FirefishId); - if (body.quote_id) - body.quote_id = convertId(body.quote_id, IdType.FirefishId); + body.in_reply_to_id = fromMastodonId(body.in_reply_to_id); + if (body.quote_id) body.quote_id = fromMastodonId(body.quote_id); if ( (!body.poll && body["poll[options][]"]) || (!body.media_ids && body["media_ids[]"]) @@ -39,7 +36,7 @@ export function apiStatusMastodon(router: Router): void { } const text = body.status; const removed = text.replace(/@\S+/g, "").replace(/\s|​/g, ""); - const isDefaultEmoji = emojiRegexAtStartToEnd.test(removed); + const isDefaultEmoji = isUnicodeEmoji(removed); const isCustomEmoji = /^:[a-zA-Z0-9@_]+:$/.test(removed); if ((body.in_reply_to_id && isDefaultEmoji) || isCustomEmoji) { const a = await client.createEmojiReaction( @@ -65,7 +62,7 @@ export function apiStatusMastodon(router: Router): void { if (body.media_ids && !body.media_ids.length) body.media_ids = undefined; if (body.media_ids) { body.media_ids = (body.media_ids as string[]).map((p) => - convertId(p, IdType.FirefishId), + fromMastodonId(p), ); } const { sensitive } = body; @@ -103,9 +100,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getStatus( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.getStatus(fromMastodonId(ctx.params.id)); ctx.body = convertStatus(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -118,9 +113,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.deleteStatus( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.deleteStatus(fromMastodonId(ctx.params.id)); ctx.body = data.data; } catch (e: any) { apiLogger.error(inspect(e)); @@ -141,7 +134,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const id = convertId(ctx.params.id, IdType.FirefishId); + const id = fromMastodonId(ctx.params.id); const data = await client.getStatusContext( id, convertTimelinesArgsId(limitToInt(ctx.query as any)), @@ -169,7 +162,7 @@ export function apiStatusMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getStatusHistory( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = data.data.map((account) => convertAccount(account)); } catch (e: any) { @@ -187,7 +180,7 @@ export function apiStatusMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getStatusRebloggedBy( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = data.data.map((account) => convertAccount(account)); } catch (e: any) { @@ -205,7 +198,7 @@ export function apiStatusMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getStatusFavouritedBy( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = data.data.map((account) => convertAccount(account)); } catch (e: any) { @@ -218,14 +211,14 @@ export function apiStatusMastodon(router: Router): void { router.post<{ Params: { id: string } }>( "/v1/statuses/:id/favourite", async (ctx) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); const react = meta.defaultReaction; try { const a = (await client.createEmojiReaction( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), react, )) as any; //const data = await client.favouriteStatus(ctx.params.id) as any; @@ -240,14 +233,14 @@ export function apiStatusMastodon(router: Router): void { router.post<{ Params: { id: string } }>( "/v1/statuses/:id/unfavourite", async (ctx) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); const react = meta.defaultReaction; try { const data = await client.deleteEmojiReaction( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), react, ); ctx.body = convertStatus(data.data); @@ -266,9 +259,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.reblogStatus( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.reblogStatus(fromMastodonId(ctx.params.id)); ctx.body = convertStatus(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -285,9 +276,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unreblogStatus( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.unreblogStatus(fromMastodonId(ctx.params.id)); ctx.body = convertStatus(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -304,9 +293,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.bookmarkStatus( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.bookmarkStatus(fromMastodonId(ctx.params.id)); ctx.body = convertStatus(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -324,7 +311,7 @@ export function apiStatusMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.unbookmarkStatus( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ); ctx.body = convertStatus(data.data); } catch (e: any) { @@ -342,9 +329,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.pinStatus( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.pinStatus(fromMastodonId(ctx.params.id)); ctx.body = convertStatus(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -361,9 +346,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unpinStatus( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.unpinStatus(fromMastodonId(ctx.params.id)); ctx.body = convertStatus(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -381,7 +364,7 @@ export function apiStatusMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.reactStatus( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ctx.params.name, ); ctx.body = convertStatus(data.data); @@ -401,7 +384,7 @@ export function apiStatusMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.unreactStatus( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ctx.params.name, ); ctx.body = convertStatus(data.data); @@ -418,9 +401,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getMedia( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.getMedia(fromMastodonId(ctx.params.id)); ctx.body = convertAttachment(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -434,7 +415,7 @@ export function apiStatusMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.updateMedia( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), ctx.request.body as any, ); ctx.body = convertAttachment(data.data); @@ -449,9 +430,7 @@ export function apiStatusMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getPoll( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.getPoll(fromMastodonId(ctx.params.id)); ctx.body = convertPoll(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -467,7 +446,7 @@ export function apiStatusMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.votePoll( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), (ctx.request.body as any).choices, ); ctx.body = convertPoll(data.data); diff --git a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts index 9d2caaca65..c71fc57c78 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts @@ -7,7 +7,7 @@ import { convertList, convertStatus, } from "../converters.js"; -import { convertId, IdType } from "@/server/api/index.js"; +import { fromMastodonId } from "backend-rs"; import { apiLogger } from "@/server/api/logger.js"; import { inspect } from "node:util"; @@ -47,12 +47,9 @@ export function argsToBools(q: ParsedUrlQuery) { } export function convertTimelinesArgsId(q: ParsedUrlQuery) { - if (typeof q.min_id === "string") - q.min_id = convertId(q.min_id, IdType.FirefishId); - if (typeof q.max_id === "string") - q.max_id = convertId(q.max_id, IdType.FirefishId); - if (typeof q.since_id === "string") - q.since_id = convertId(q.since_id, IdType.FirefishId); + if (typeof q.min_id === "string") q.min_id = fromMastodonId(q.min_id); + if (typeof q.max_id === "string") q.max_id = fromMastodonId(q.max_id); + if (typeof q.since_id === "string") q.since_id = fromMastodonId(q.since_id); return q; } @@ -120,7 +117,7 @@ export function apiTimelineMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getListTimeline( - convertId(ctx.params.listId, IdType.FirefishId), + fromMastodonId(ctx.params.listId), convertTimelinesArgsId(limitToInt(ctx.query)), ); ctx.body = data.data.map((status) => convertStatus(status)); @@ -168,9 +165,7 @@ export function apiTimelineMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getList( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.getList(fromMastodonId(ctx.params.id)); ctx.body = convertList(data.data); } catch (e: any) { apiLogger.error(inspect(e)); @@ -200,7 +195,7 @@ export function apiTimelineMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.updateList( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), (ctx.request.body as any).title, ); ctx.body = convertList(data.data); @@ -218,9 +213,7 @@ export function apiTimelineMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.deleteList( - convertId(ctx.params.id, IdType.FirefishId), - ); + const data = await client.deleteList(fromMastodonId(ctx.params.id)); ctx.body = data.data; } catch (e: any) { apiLogger.error(inspect(e)); @@ -237,7 +230,7 @@ export function apiTimelineMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountsInList( - convertId(ctx.params.id, IdType.FirefishId), + fromMastodonId(ctx.params.id), convertTimelinesArgsId(ctx.query as any), ); ctx.body = data.data.map((account) => convertAccount(account)); @@ -256,10 +249,8 @@ export function apiTimelineMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.addAccountsToList( - convertId(ctx.params.id, IdType.FirefishId), - (ctx.query.account_ids as string[]).map((id) => - convertId(id, IdType.FirefishId), - ), + fromMastodonId(ctx.params.id), + (ctx.query.account_ids as string[]).map((id) => fromMastodonId(id)), ); ctx.body = data.data; } catch (e: any) { @@ -277,10 +268,8 @@ export function apiTimelineMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.deleteAccountsFromList( - convertId(ctx.params.id, IdType.FirefishId), - (ctx.query.account_ids as string[]).map((id) => - convertId(id, IdType.FirefishId), - ), + fromMastodonId(ctx.params.id), + (ctx.query.account_ids as string[]).map((id) => fromMastodonId(id)), ); ctx.body = data.data; } catch (e: any) { diff --git a/packages/backend/src/server/api/private/signin.ts b/packages/backend/src/server/api/private/signin.ts index fb3596d9b1..a7eb623062 100644 --- a/packages/backend/src/server/api/private/signin.ts +++ b/packages/backend/src/server/api/private/signin.ts @@ -10,12 +10,12 @@ import { AttestationChallenges, } from "@/models/index.js"; import type { ILocalUser } from "@/models/entities/user.js"; -import { genId } from "@/misc/gen-id.js"; import { - comparePassword, + genId, hashPassword, - isOldAlgorithm, -} from "@/misc/password.js"; + isOldPasswordAlgorithm, + verifyPassword, +} from "backend-rs"; import { verifyLogin, hash } from "@/server/api/2fa.js"; import { randomBytes } from "node:crypto"; import { IsNull } from "typeorm"; @@ -91,11 +91,11 @@ export default async (ctx: Koa.Context) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(password, profile.password!); + // Compare passwords + const same = verifyPassword(password, profile.password!); - if (same && isOldAlgorithm(profile.password!)) { - profile.password = await hashPassword(password); + if (same && isOldPasswordAlgorithm(profile.password!)) { + profile.password = hashPassword(password); await UserProfiles.save(profile); } @@ -185,7 +185,7 @@ export default async (ctx: Koa.Context) => { id: body.challengeId, }); - if (new Date().getTime() - challenge.createdAt.getTime() >= 5 * 60 * 1000) { + if (Date.now() - challenge.createdAt.getTime() >= 5 * 60 * 1000) { await fail(403, { id: "2715a88a-2125-4013-932f-aa6fe72792da", }); diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts index ba6d23d28f..5af5d65b50 100644 --- a/packages/backend/src/server/api/private/signup.ts +++ b/packages/backend/src/server/api/private/signup.ts @@ -1,20 +1,17 @@ import type Koa from "koa"; import rndstr from "rndstr"; -import { fetchMeta } from "@/misc/fetch-meta.js"; import { verifyHcaptcha, verifyRecaptcha } from "@/misc/captcha.js"; import { Users, RegistrationTickets, UserPendings } from "@/models/index.js"; import { signup } from "@/server/api/common/signup.js"; import config from "@/config/index.js"; import { sendEmail } from "@/services/send-email.js"; -import { genId } from "@/misc/gen-id.js"; +import { fetchMeta, genId, hashPassword } from "backend-rs"; import { validateEmailForAccount } from "@/services/validate-email-for-account.js"; -import { hashPassword } from "@/misc/password.js"; -import { inspect } from "node:util"; export default async (ctx: Koa.Context) => { const body = ctx.request.body; - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); // Verify *Captcha // ただしテスト時はこの機構は障害となるため無効にする @@ -85,7 +82,7 @@ export default async (ctx: Koa.Context) => { const code = rndstr("a-z0-9", 16); // Generate hash of password - const hash = await hashPassword(password); + const hash = hashPassword(password); await UserPendings.insert({ id: genId(), diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index 79d2fe90ec..1760d5abf7 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -1,6 +1,5 @@ import Channel from "../channel.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { getWordHardMute } from "@/misc/check-word-mute.js"; +import { checkWordMute, fetchMeta } from "backend-rs"; import { isInstanceMuted } from "@/misc/is-instance-muted.js"; import { isUserRelated } from "@/misc/is-user-related.js"; import type { Packed } from "@/misc/schema.js"; @@ -17,7 +16,7 @@ export default class extends Channel { } public async init(params: any) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.disableGlobalTimeline) { if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) return; @@ -72,7 +71,7 @@ export default class extends Channel { if ( this.userProfile && this.user?.id !== note.userId && - (await getWordHardMute( + (await checkWordMute( note, this.userProfile.mutedWords, this.userProfile.mutedPatterns, diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 8f23946259..8103fe9b69 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -1,5 +1,5 @@ import Channel from "../channel.js"; -import { getWordHardMute } from "@/misc/check-word-mute.js"; +import { checkWordMute } from "backend-rs"; import { isUserRelated } from "@/misc/is-user-related.js"; import { isInstanceMuted } from "@/misc/is-instance-muted.js"; import type { Packed } from "@/misc/schema.js"; @@ -69,7 +69,7 @@ export default class extends Channel { if ( this.userProfile && this.user?.id !== note.userId && - (await getWordHardMute( + (await checkWordMute( note, this.userProfile.mutedWords, this.userProfile.mutedPatterns, diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 7f5c662b8c..5100a48efd 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -1,6 +1,5 @@ import Channel from "../channel.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { getWordHardMute } from "@/misc/check-word-mute.js"; +import { checkWordMute, fetchMeta } from "backend-rs"; import { isUserRelated } from "@/misc/is-user-related.js"; import { isInstanceMuted } from "@/misc/is-instance-muted.js"; import type { Packed } from "@/misc/schema.js"; @@ -17,7 +16,7 @@ export default class extends Channel { } public async init(params: any) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( meta.disableLocalTimeline && !this.user!.isAdmin && @@ -86,7 +85,7 @@ export default class extends Channel { if ( this.userProfile && this.user?.id !== note.userId && - (await getWordHardMute( + (await checkWordMute( note, this.userProfile.mutedWords, this.userProfile.mutedPatterns, diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 1df87dbfc8..2c9a38d677 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -1,6 +1,5 @@ import Channel from "../channel.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { getWordHardMute } from "@/misc/check-word-mute.js"; +import { checkWordMute, fetchMeta } from "backend-rs"; import { isUserRelated } from "@/misc/is-user-related.js"; import type { Packed } from "@/misc/schema.js"; @@ -16,7 +15,7 @@ export default class extends Channel { } public async init(params: any) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.disableLocalTimeline) { if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) return; @@ -64,7 +63,7 @@ export default class extends Channel { if ( this.userProfile && this.user?.id !== note.userId && - (await getWordHardMute( + (await checkWordMute( note, this.userProfile.mutedWords, this.userProfile.mutedPatterns, diff --git a/packages/backend/src/server/api/stream/channels/recommended-timeline.ts b/packages/backend/src/server/api/stream/channels/recommended-timeline.ts index a9da732f89..5d0d6fc602 100644 --- a/packages/backend/src/server/api/stream/channels/recommended-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/recommended-timeline.ts @@ -1,6 +1,5 @@ import Channel from "../channel.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { getWordHardMute } from "@/misc/check-word-mute.js"; +import { checkWordMute, fetchMeta } from "backend-rs"; import { isUserRelated } from "@/misc/is-user-related.js"; import { isInstanceMuted } from "@/misc/is-instance-muted.js"; import type { Packed } from "@/misc/schema.js"; @@ -17,7 +16,7 @@ export default class extends Channel { } public async init(params: any) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( meta.disableRecommendedTimeline && !this.user!.isAdmin && @@ -37,7 +36,7 @@ export default class extends Channel { // チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または // チャンネルの投稿ではなく、全体公開のローカルの投稿 または // フォローしているチャンネルの投稿 の場合だけ - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( !( note.user.host != null && @@ -84,7 +83,7 @@ export default class extends Channel { if ( this.userProfile && this.user?.id !== note.userId && - (await getWordHardMute( + (await checkWordMute( note, this.userProfile.mutedWords, this.userProfile.mutedPatterns, diff --git a/packages/backend/src/server/api/streaming.ts b/packages/backend/src/server/api/streaming.ts index a25984ec3e..12f97d8018 100644 --- a/packages/backend/src/server/api/streaming.ts +++ b/packages/backend/src/server/api/streaming.ts @@ -1,6 +1,6 @@ import type * as http from "node:http"; -import { EventEmitter } from "events"; -import type { ParsedUrlQuery } from "querystring"; +import { EventEmitter } from "node:events"; +import type { ParsedUrlQuery } from "node:querystring"; import * as websocket from "websocket"; import { subscriber as redisClient } from "@/db/redis.js"; diff --git a/packages/backend/src/server/file/byte-range-readable.ts b/packages/backend/src/server/file/byte-range-readable.ts index 96dcbc4a52..9699f95092 100644 --- a/packages/backend/src/server/file/byte-range-readable.ts +++ b/packages/backend/src/server/file/byte-range-readable.ts @@ -1,4 +1,4 @@ -import { Readable, ReadableOptions } from "node:stream"; +import { Readable, type ReadableOptions } from "node:stream"; import { Buffer } from "node:buffer"; import * as fs from "node:fs"; diff --git a/packages/backend/src/server/file/send-drive-file.ts b/packages/backend/src/server/file/send-drive-file.ts index b7f3838e3f..01ec93e448 100644 --- a/packages/backend/src/server/file/send-drive-file.ts +++ b/packages/backend/src/server/file/send-drive-file.ts @@ -54,6 +54,8 @@ export default async function (ctx: Koa.Context) { return; } + ctx.set("X-Content-Type-Options", "nosniff"); + const isThumbnail = file.thumbnailAccessKey === key; const isWebpublic = file.webpublicAccessKey === key; diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 00ad0baef9..17358a4758 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -13,15 +13,14 @@ import koaLogger from "koa-logger"; import * as slow from "koa-slow"; import { IsNull } from "typeorm"; -import config from "@/config/index.js"; +import config, { envOption } from "@/config/index.js"; import Logger from "@/services/logger.js"; import { Users } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { genIdenticon } from "@/misc/gen-identicon.js"; import { createTemp } from "@/misc/create-temp.js"; -import * as Acct from "@/misc/acct.js"; -import { envOption } from "@/env.js"; -import megalodon, { MegalodonInterface } from "megalodon"; +import { stringToAcct } from "backend-rs"; +import megalodon, { type MegalodonInterface } from "megalodon"; import activityPub from "./activitypub.js"; import nodeinfo from "./nodeinfo.js"; import wellKnown from "./well-known.js"; @@ -108,7 +107,7 @@ router.use(nodeinfo.routes()); router.use(wellKnown.routes()); router.get("/avatar/@:acct", async (ctx) => { - const { username, host } = Acct.parse(ctx.params.acct); + const { username, host } = stringToAcct(ctx.params.acct); const user = await Users.findOne({ where: { usernameLower: username.toLowerCase(), @@ -126,7 +125,7 @@ router.get("/avatar/@:acct", async (ctx) => { }); router.get("/identicon/:x", async (ctx) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.enableIdenticonGeneration) { const [temp, cleanup] = await createTemp(); await genIdenticon(ctx.params.x, fs.createWriteStream(temp)); @@ -158,7 +157,7 @@ mastoRouter.post("/oauth/token", async (ctx) => { access_token: uuid(), token_type: "Bearer", scope: "read", - created_at: Math.floor(new Date().getTime() / 1000), + created_at: Math.floor(Date.now() / 1000), }; ctx.body = ret; return; @@ -193,7 +192,7 @@ mastoRouter.post("/oauth/token", async (ctx) => { access_token: atData.accessToken, token_type: "Bearer", scope: body.scope || "read write follow push", - created_at: Math.floor(new Date().getTime() / 1000), + created_at: Math.floor(Date.now() / 1000), }; serverLogger.info("token-response", ret); ctx.body = ret; diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts index 1cb8eb1eaf..7359878b19 100644 --- a/packages/backend/src/server/nodeinfo.ts +++ b/packages/backend/src/server/nodeinfo.ts @@ -1,6 +1,6 @@ import Router from "@koa/router"; import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Users, Notes } from "@/models/index.js"; import { IsNull, MoreThan } from "typeorm"; import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js"; @@ -27,7 +27,7 @@ const nodeinfo2 = async () => { const now = Date.now(); const [meta, total, activeHalfyear, activeMonth, localPosts] = await Promise.all([ - fetchMeta(true), + fetchMeta(false), Users.count({ where: { host: IsNull() } }), Users.count({ where: { diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index e6b09b4f4f..f3b3c97c32 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -2,7 +2,16 @@ import { Feed } from "feed"; import { In, IsNull } from "typeorm"; import config from "@/config/index.js"; import type { User } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; import { Notes, DriveFiles, UserProfiles, Users } from "@/models/index.js"; +import getNoteHtml from "@/remote/activitypub/misc/get-note-html.js"; + +/** + * If there is this part in the note, it will cause CDATA to be terminated early. + */ +function escapeCDATA(str: string) { + return str.replaceAll("]]>", "]]]]>"); +} export default async function ( user: User, @@ -15,7 +24,7 @@ export default async function ( const author = { link: `${config.url}/@${user.username}`, email: `${user.username}@${config.host}`, - name: user.name || user.username, + name: escapeCDATA(user.name || user.username), }; const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -44,11 +53,13 @@ export default async function ( title: `${author.name} (@${user.username}@${config.host})`, updated: notes[0].createdAt, generator: "Firefish", - description: `${user.notesCount} Notes, ${ - profile.ffVisibility === "public" ? user.followingCount : "?" - } Following, ${ - profile.ffVisibility === "public" ? user.followersCount : "?" - } Followers${profile.description ? ` · ${profile.description}` : ""}`, + description: escapeCDATA( + `${user.notesCount} Notes, ${ + profile.ffVisibility === "public" ? user.followingCount : "?" + } Following, ${ + profile.ffVisibility === "public" ? user.followersCount : "?" + } Followers${profile.description ? ` · ${profile.description}` : ""}`, + ), link: author.link, image: await Users.getAvatarUrl(user), feedLinks: { @@ -88,19 +99,23 @@ export default async function ( } feed.addItem({ - title: title - .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "") - .substring(0, 100), + title: escapeCDATA( + title + .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "") + .substring(0, 100), + ), link: `${config.url}/notes/${note.id}`, date: note.createdAt, description: note.cw - ? note.cw.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "") + ? escapeCDATA(note.cw.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "")) : undefined, - content: contentStr.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ""), + content: escapeCDATA( + contentStr.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ""), + ), }); } - async function noteToString(note, isTheNote = false) { + async function noteToString(note: Note, isTheNote = false) { const author = isTheNote ? null : await Users.findOneBy({ id: note.userId }); @@ -135,7 +150,10 @@ export default async function ( }">${file.name}`; } } - outstr += `${note.cw ? note.cw + "
" : ""}${note.text || ""}${fileEle}`; + + outstr += `${note.cw ? note.cw + "
" : ""}${ + getNoteHtml(note) || "" + }${fileEle}`; if (isTheNote) { outstr += ` { const url = decodeURI(ctx.path); if (url === bullBoardPath || url.startsWith(`${bullBoardPath}/`)) { + if (!url.startsWith(`${bullBoardPath}/static/`)) { + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); + } + const token = ctx.cookies.get("token"); if (token == null) { ctx.status = 401; @@ -326,11 +328,11 @@ const getFeed = async ( noRenotes: string, noReplies: string, ) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.privateMode) { return; } - const { username, host } = Acct.parse(acct); + const { username, host } = stringToAcct(acct); const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), host: host ?? IsNull(), @@ -461,7 +463,7 @@ const jsonFeed: Router.Middleware = async (ctx) => { const userPage: Router.Middleware = async (ctx, next) => { const userParam = ctx.params.user; const subParam = ctx.params.sub; - const { username, host } = Acct.parse(userParam); + const { username, host } = stringToAcct(userParam); const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), @@ -475,7 +477,7 @@ const userPage: Router.Middleware = async (ctx, next) => { } const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const me = profile.fields ? profile.fields .filter((filed) => filed.value?.match(/^https?:/)) @@ -518,22 +520,22 @@ router.get("/notes/:note", async (ctx, next) => { }); try { - if (note) { - const _note = await Notes.pack(note); + if (note != null) { + const packedNote = await Notes.pack(note); const profile = await UserProfiles.findOneByOrFail({ userId: note.userId, }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("note", { ...metaToPugArgs(meta), - note: _note, + note: packedNote, profile, avatarUrl: await Users.getAvatarUrl( await Users.findOneByOrFail({ id: note.userId }), ), // TODO: Let locale changeable by instance setting - summary: getNoteSummary(_note), + summary: getNoteSummary(note), }); ctx.set("Cache-Control", "public, max-age=15"); @@ -558,7 +560,7 @@ router.get("/posts/:note", async (ctx, next) => { if (note) { const _note = await Notes.pack(note); const profile = await UserProfiles.findOneByOrFail({ userId: note.userId }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("note", { ...metaToPugArgs(meta), note: _note, @@ -580,7 +582,7 @@ router.get("/posts/:note", async (ctx, next) => { // Page router.get("/@:user/pages/:page", async (ctx, next) => { - const { username, host } = Acct.parse(ctx.params.user); + const { username, host } = stringToAcct(ctx.params.user); const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), host: host ?? IsNull(), @@ -596,7 +598,7 @@ router.get("/@:user/pages/:page", async (ctx, next) => { if (page) { const _page = await Pages.pack(page); const profile = await UserProfiles.findOneByOrFail({ userId: page.userId }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("page", { ...metaToPugArgs(meta), page: _page, @@ -628,7 +630,7 @@ router.get("/clips/:clip", async (ctx, next) => { if (clip) { const _clip = await Clips.pack(clip); const profile = await UserProfiles.findOneByOrFail({ userId: clip.userId }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("clip", { ...metaToPugArgs(meta), clip: _clip, @@ -653,7 +655,7 @@ router.get("/gallery/:post", async (ctx, next) => { if (post) { const _post = await GalleryPosts.pack(post); const profile = await UserProfiles.findOneByOrFail({ userId: post.userId }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("gallery-post", { ...metaToPugArgs(meta), post: _post, @@ -679,7 +681,7 @@ router.get("/channels/:channel", async (ctx, next) => { if (channel) { const _channel = await Channels.pack(channel); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("channel", { ...metaToPugArgs(meta), channel: _channel, @@ -732,7 +734,7 @@ router.get("/api/v1/streaming", async (ctx) => { // Render base html for all requests router.get("(.*)", async (ctx) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("base", { ...metaToPugArgs(meta), diff --git a/packages/backend/src/server/web/manifest.ts b/packages/backend/src/server/web/manifest.ts index bbcf639ffe..a4c615c7ab 100644 --- a/packages/backend/src/server/web/manifest.ts +++ b/packages/backend/src/server/web/manifest.ts @@ -1,5 +1,5 @@ import type Koa from "koa"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import config from "@/config/index.js"; import manifest from "./manifest.json" assert { type: "json" }; @@ -8,7 +8,7 @@ export const manifestHandler = async (ctx: Koa.Context) => { //const res = structuredClone(manifest); const res = JSON.parse(JSON.stringify(manifest)); - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); res.short_name = instance.name || "Firefish"; res.name = instance.name || "Firefish"; diff --git a/packages/backend/src/server/web/url-preview.ts b/packages/backend/src/server/web/url-preview.ts index 07d3bf7f2c..f59f3f357a 100644 --- a/packages/backend/src/server/web/url-preview.ts +++ b/packages/backend/src/server/web/url-preview.ts @@ -1,6 +1,6 @@ import type Koa from "koa"; import summaly from "summaly"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import Logger from "@/services/logger.js"; import config from "@/config/index.js"; import { query } from "@/prelude/url.js"; @@ -22,7 +22,7 @@ export const urlPreviewHandler = async (ctx: Koa.Context) => { return; } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); logger.info( meta.summalyProxy diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index bdbe153fbe..738d3ffc01 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -72,8 +72,8 @@ html div#splash img#splashIcon(src= splashIcon || `/static-assets/splash.svg?${ timestamp }`) span#splashText - block randomMOTD - = randomMOTD + block randomMotd + = randomMotd div#splashSpinner diff --git a/packages/backend/src/server/well-known.ts b/packages/backend/src/server/well-known.ts index 1dc0f3d0a5..fc339eaad6 100644 --- a/packages/backend/src/server/well-known.ts +++ b/packages/backend/src/server/well-known.ts @@ -1,7 +1,7 @@ import Router from "@koa/router"; import config from "@/config/index.js"; -import * as Acct from "@/misc/acct.js"; +import { type Acct, stringToAcct } from "backend-rs"; import { links } from "./nodeinfo.js"; import { escapeAttribute, escapeValue } from "@/prelude/xml.js"; import { Users } from "@/models/index.js"; @@ -74,22 +74,6 @@ router.get("/.well-known/host-meta.json", async (ctx) => { }; }); -if (config.twa != null) { - router.get("/.well-known/assetlinks.json", async (ctx) => { - ctx.set("Content-Type", "application/json"); - ctx.body = [ - { - relation: ["delegate_permission/common.handle_all_urls"], - target: { - namespace: config.twa.nameSpace, - package_name: config.twa.packageName, - sha256_cert_fingerprints: config.twa.sha256CertFingerprints, - }, - }, - ]; - }); -} - router.get("/.well-known/nodeinfo", async (ctx) => { ctx.body = { links }; }); @@ -110,7 +94,7 @@ router.get(webFingerPath, async (ctx) => { resource.startsWith(`${config.url.toLowerCase()}/users/`) ? fromId(resource.split("/").pop()!) : fromAcct( - Acct.parse( + stringToAcct( resource.startsWith(`${config.url.toLowerCase()}/@`) ? resource.split("/").pop()! : resource.startsWith("acct:") @@ -119,7 +103,7 @@ router.get(webFingerPath, async (ctx) => { ), ); - const fromAcct = (acct: Acct.Acct): FindOptionsWhere | number => + const fromAcct = (acct: Acct): FindOptionsWhere | number => !acct.host || acct.host === config.host.toLowerCase() ? { usernameLower: acct.username, diff --git a/packages/backend/src/services/add-note-to-antenna.ts b/packages/backend/src/services/add-note-to-antenna.ts index 499418000d..66bc898263 100644 --- a/packages/backend/src/services/add-note-to-antenna.ts +++ b/packages/backend/src/services/add-note-to-antenna.ts @@ -1,6 +1,6 @@ import type { Antenna } from "@/models/entities/antenna.js"; import type { Note } from "@/models/entities/note.js"; -import { getTimestamp } from "@/misc/gen-id.js"; +import { getTimestamp } from "backend-rs"; import { redisClient } from "@/db/redis.js"; import { publishAntennaStream } from "@/services/stream.js"; import type { User } from "@/models/entities/user.js"; diff --git a/packages/backend/src/services/blocking/create.ts b/packages/backend/src/services/blocking/create.ts index 144304cfb3..2e5766c45b 100644 --- a/packages/backend/src/services/blocking/create.ts +++ b/packages/backend/src/services/blocking/create.ts @@ -15,7 +15,7 @@ import { UserListJoinings, UserLists, } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { getActiveWebhooks } from "@/misc/webhook-cache.js"; import { webhookDeliver } from "@/queue/index.js"; diff --git a/packages/backend/src/services/chart/charts/active-users.ts b/packages/backend/src/services/chart/charts/active-users.ts index 3f4b7e3381..067334005e 100644 --- a/packages/backend/src/services/chart/charts/active-users.ts +++ b/packages/backend/src/services/chart/charts/active-users.ts @@ -1,4 +1,3 @@ -import type { KVs } from "../core.js"; import Chart from "../core.js"; import type { User } from "@/models/entities/user.js"; import { name, schema } from "./entities/active-users.js"; diff --git a/packages/backend/src/services/chart/core.ts b/packages/backend/src/services/chart/core.ts index 625498c10a..89e1bbf706 100644 --- a/packages/backend/src/services/chart/core.ts +++ b/packages/backend/src/services/chart/core.ts @@ -306,7 +306,7 @@ export default abstract class Chart { k.startsWith(columnPrefix), ) as (keyof Columns)[]) { kvs[ - (k as string).substr(columnPrefix.length).split(columnDot).join(".") + (k as string).substring(columnPrefix.length).split(columnDot).join(".") ] = x[k]; } return kvs as KVs; diff --git a/packages/backend/src/services/create-notification.ts b/packages/backend/src/services/create-notification.ts index 9bfd1a7bfa..a108d4f5de 100644 --- a/packages/backend/src/services/create-notification.ts +++ b/packages/backend/src/services/create-notification.ts @@ -8,7 +8,7 @@ import { Users, Followings, } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import type { User } from "@/models/entities/user.js"; import type { Notification } from "@/models/entities/notification.js"; import { sendEmailNotification } from "./send-email-notification.js"; diff --git a/packages/backend/src/services/create-system-user.ts b/packages/backend/src/services/create-system-user.ts index 0ebd1142f1..802c59b288 100644 --- a/packages/backend/src/services/create-system-user.ts +++ b/packages/backend/src/services/create-system-user.ts @@ -4,17 +4,16 @@ import { genRsaKeyPair } from "@/misc/gen-key-pair.js"; import { User } from "@/models/entities/user.js"; import { UserProfile } from "@/models/entities/user-profile.js"; import { IsNull } from "typeorm"; -import { genId } from "@/misc/gen-id.js"; +import { genId, hashPassword } from "backend-rs"; import { UserKeypair } from "@/models/entities/user-keypair.js"; import { UsedUsername } from "@/models/entities/used-username.js"; import { db } from "@/db/postgre.js"; -import { hashPassword } from "@/misc/password.js"; export async function createSystemUser(username: string) { const password = uuid(); // Generate hash of password - const hash = await hashPassword(password); + const hash = hashPassword(password); // Generate secret const secret = generateNativeUserToken(); diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index 65a51f926a..d180bbabf3 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -6,7 +6,7 @@ import type S3 from "aws-sdk/clients/s3.js"; // TODO: migrate to SDK v3 import sharp from "sharp"; import { IsNull } from "typeorm"; import { publishMainStream, publishDriveStream } from "@/services/stream.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { contentDisposition } from "@/misc/content-disposition.js"; import { getFileInfo } from "@/misc/get-file-info.js"; import { @@ -16,8 +16,9 @@ import { UserProfiles, } from "@/models/index.js"; import { DriveFile } from "@/models/entities/drive-file.js"; +import type { DriveFileUsageHint } from "@/models/entities/drive-file.js"; import type { IRemoteUser, User } from "@/models/entities/user.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; import { FILE_TYPE_BROWSERSAFE } from "@/const.js"; import { IdentifiableError } from "@/misc/identifiable-error.js"; @@ -65,6 +66,7 @@ function urlPathJoin( * @param type Content-Type for original * @param hash Hash for original * @param size Size for original + * @param usage Optional usage hint for file (f.e. "userAvatar") */ async function save( file: DriveFile, @@ -73,11 +75,12 @@ async function save( type: string, hash: string, size: number, + usage: DriveFileUsageHint = null, ): Promise { // thunbnail, webpublic を必要なら生成 const alts = await generateAlts(path, type, !file.uri); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.useObjectStorage) { //#region ObjectStorage params @@ -161,6 +164,7 @@ async function save( file.md5 = hash; file.size = size; file.storedInternal = false; + file.usageHint = usage ?? null; return await DriveFiles.insert(file).then((x) => DriveFiles.findOneByOrFail(x.identifiers[0]), @@ -204,6 +208,7 @@ async function save( file.type = type; file.md5 = hash; file.size = size; + file.usageHint = usage ?? null; return await DriveFiles.insert(file).then((x) => DriveFiles.findOneByOrFail(x.identifiers[0]), @@ -360,7 +365,7 @@ async function upload( if (type === "image/apng") type = "image/png"; if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = "application/octet-stream"; - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const params = { Bucket: meta.objectStorageBucket, @@ -450,6 +455,9 @@ type AddFileArgs = { requestIp?: string | null; requestHeaders?: Record | null; + + /** Whether this file has a known use case, like user avatar or instance icon */ + usageHint?: DriveFileUsageHint; }; /** @@ -469,6 +477,7 @@ export async function addFile({ sensitive = null, requestIp = null, requestHeaders = null, + usageHint = null, }: AddFileArgs): Promise { const info = await getFileInfo(path); logger.info(`${JSON.stringify(info)}`); @@ -495,7 +504,7 @@ export async function addFile({ const usage = await DriveFiles.calcDriveUsageOf(user); const u = await Users.findOneBy({ id: user.id }); - const instance = await fetchMeta(); + const instance = await fetchMeta(true); let driveCapacity = 1024 * 1024 * @@ -567,7 +576,7 @@ export async function addFile({ : null; const folder = await fetchFolder(); - const instance = await fetchMeta(); + const instance = await fetchMeta(true); let file = new DriveFile(); file.id = genId(); @@ -581,6 +590,7 @@ export async function addFile({ file.isLink = isLink; file.requestIp = requestIp; file.requestHeaders = requestHeaders; + file.usageHint = usageHint; file.isSensitive = user ? Users.isLocalUser(user) && (instance!.markLocalFilesNsfwByDefault || profile!.alwaysMarkNsfw) @@ -639,6 +649,7 @@ export async function addFile({ info.type.mime, info.md5, info.size, + usageHint, ); } diff --git a/packages/backend/src/services/drive/delete-file.ts b/packages/backend/src/services/drive/delete-file.ts index 16c0219e71..b4b5580a1c 100644 --- a/packages/backend/src/services/drive/delete-file.ts +++ b/packages/backend/src/services/drive/delete-file.ts @@ -2,7 +2,7 @@ import type { DriveFile } from "@/models/entities/drive-file.js"; import { InternalStorage } from "./internal-storage.js"; import { DriveFiles } from "@/models/index.js"; import { createDeleteObjectStorageFileJob } from "@/queue/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { getS3 } from "./s3.js"; import { v4 as uuid } from "uuid"; @@ -82,7 +82,7 @@ async function postProcess(file: DriveFile, isExpired = false) { } export async function deleteObjectStorageFile(key: string) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const s3 = getS3(meta); diff --git a/packages/backend/src/services/drive/upload-from-url.ts b/packages/backend/src/services/drive/upload-from-url.ts index 551d3757ca..e7b084bda1 100644 --- a/packages/backend/src/services/drive/upload-from-url.ts +++ b/packages/backend/src/services/drive/upload-from-url.ts @@ -3,7 +3,10 @@ import type { User } from "@/models/entities/user.js"; import { createTemp } from "@/misc/create-temp.js"; import { downloadUrl, isPrivateIp } from "@/misc/download-url.js"; import type { DriveFolder } from "@/models/entities/drive-folder.js"; -import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { + DriveFile, + DriveFileUsageHint, +} from "@/models/entities/drive-file.js"; import { DriveFiles } from "@/models/index.js"; import { driveLogger } from "./logger.js"; import { addFile } from "./add-file.js"; @@ -13,7 +16,11 @@ const logger = driveLogger.createSubLogger("downloader"); type Args = { url: string; - user: { id: User["id"]; host: User["host"] } | null; + user: { + id: User["id"]; + host: User["host"]; + driveCapacityOverrideMb: User["driveCapacityOverrideMb"]; + } | null; folderId?: DriveFolder["id"] | null; uri?: string | null; sensitive?: boolean; @@ -22,6 +29,7 @@ type Args = { comment?: string | null; requestIp?: string | null; requestHeaders?: Record | null; + usageHint?: DriveFileUsageHint; }; export async function uploadFromUrl({ @@ -35,6 +43,7 @@ export async function uploadFromUrl({ comment = null, requestIp = null, requestHeaders = null, + usageHint = null, }: Args): Promise { const parsedUrl = new URL(url); if ( @@ -75,9 +84,10 @@ export async function uploadFromUrl({ sensitive, requestIp, requestHeaders, + usageHint, }); logger.succ(`Got: ${driveFile.id}`); - return driveFile!; + return driveFile; } catch (e) { logger.error(`Failed to create drive file:\n${inspect(e)}`); throw e; diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index 6795db0690..18e6411e88 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -3,7 +3,10 @@ import { Window } from "happy-dom"; import fetch from "node-fetch"; import tinycolor from "tinycolor2"; import { getJson, getAgentByUrl } from "@/misc/fetch.js"; -import type { Instance } from "@/models/entities/instance.js"; +import { + type Instance, + MAX_LENGTH_INSTANCE, +} from "@/models/entities/instance.js"; import { Instances } from "@/models/index.js"; import { getFetchInstanceMetadataLock } from "@/misc/app-lock.js"; import Logger from "@/services/logger.js"; @@ -53,26 +56,52 @@ export async function fetchInstanceMetadata( } as Record; if (info) { - updates.softwareName = info.software?.name?.toLowerCase() || null; - updates.softwareVersion = info.software?.version; + updates.softwareName = + info.software?.name + ?.toLowerCase() + .substring(0, MAX_LENGTH_INSTANCE.softwareName) || null; + updates.softwareVersion = + info.software?.version?.substring( + 0, + MAX_LENGTH_INSTANCE.softwareVersion, + ) || null; updates.openRegistrations = info.openRegistrations; updates.maintainerName = info.metadata ? info.metadata.maintainer - ? info.metadata.maintainer.name || null + ? info.metadata.maintainer.name?.substring( + 0, + MAX_LENGTH_INSTANCE.maintainerName, + ) || null : null : null; updates.maintainerEmail = info.metadata ? info.metadata.maintainer - ? info.metadata.maintainer.email || null + ? info.metadata.maintainer.email?.substring( + 0, + MAX_LENGTH_INSTANCE.maintainerEmail, + ) || null : null : null; } - if (name) updates.name = name; - if (description) updates.description = description; - if (icon || favicon) updates.iconUrl = icon || favicon; - if (favicon) updates.faviconUrl = favicon; - if (themeColor) updates.themeColor = themeColor; + if (name) updates.name = name.substring(0, MAX_LENGTH_INSTANCE.name); + if (description) + updates.description = description.substring( + 0, + MAX_LENGTH_INSTANCE.description, + ); + if (icon || favicon) + updates.iconUrl = (icon || favicon)?.substring( + 0, + MAX_LENGTH_INSTANCE.iconUrl, + ); + if (favicon) + updates.faviconUrl = favicon.substring(0, MAX_LENGTH_INSTANCE.faviconUrl); + if (themeColor) + updates.themeColor = themeColor.substring( + 0, + MAX_LENGTH_INSTANCE.themeColor, + ); await Instances.update(instance.id, updates); diff --git a/packages/backend/src/services/fetch-rel-me.ts b/packages/backend/src/services/fetch-rel-me.ts index c9a37d1c88..70faa01aa7 100644 --- a/packages/backend/src/services/fetch-rel-me.ts +++ b/packages/backend/src/services/fetch-rel-me.ts @@ -1,4 +1,5 @@ import { Window } from "happy-dom"; +import type { HTMLAnchorElement, HTMLLinkElement } from "happy-dom"; import config from "@/config/index.js"; async function getRelMeLinks(url: string): Promise { diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts index 3b8f63281d..7387346d1a 100644 --- a/packages/backend/src/services/following/create.ts +++ b/packages/backend/src/services/following/create.ts @@ -17,7 +17,7 @@ import { Instances, UserProfiles, } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { createNotification } from "@/services/create-notification.js"; import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; import type { Packed } from "@/misc/schema.js"; diff --git a/packages/backend/src/services/following/requests/create.ts b/packages/backend/src/services/following/requests/create.ts index 12dfddf302..d2f2c1ca41 100644 --- a/packages/backend/src/services/following/requests/create.ts +++ b/packages/backend/src/services/following/requests/create.ts @@ -4,7 +4,7 @@ import renderFollow from "@/remote/activitypub/renderer/follow.js"; import { deliver } from "@/queue/index.js"; import type { User } from "@/models/entities/user.js"; import { Blockings, FollowRequests, Users } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { createNotification } from "@/services/create-notification.js"; import config from "@/config/index.js"; diff --git a/packages/backend/src/services/i/pin.ts b/packages/backend/src/services/i/pin.ts index 3ee4cb4a80..2d2675a535 100644 --- a/packages/backend/src/services/i/pin.ts +++ b/packages/backend/src/services/i/pin.ts @@ -7,7 +7,7 @@ import type { User } from "@/models/entities/user.js"; import type { Note } from "@/models/entities/note.js"; import { Notes, UserNotePinings, Users } from "@/models/index.js"; import type { UserNotePining } from "@/models/entities/user-note-pining.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { deliverToFollowers } from "@/remote/activitypub/deliver-manager.js"; import { deliverToRelays } from "@/services/relay.js"; diff --git a/packages/backend/src/services/insert-moderation-log.ts b/packages/backend/src/services/insert-moderation-log.ts index 8e2c5b78a1..9c76cf45ac 100644 --- a/packages/backend/src/services/insert-moderation-log.ts +++ b/packages/backend/src/services/insert-moderation-log.ts @@ -1,5 +1,5 @@ import { ModerationLogs } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import type { User } from "@/models/entities/user.js"; export async function insertModerationLog( diff --git a/packages/backend/src/services/logger.ts b/packages/backend/src/services/logger.ts index 63eb3d00b9..f4b4454ef8 100644 --- a/packages/backend/src/services/logger.ts +++ b/packages/backend/src/services/logger.ts @@ -2,8 +2,7 @@ import cluster from "node:cluster"; import chalk from "chalk"; import { default as convertColor } from "color-convert"; import { format as dateFormat } from "date-fns"; -import { envOption } from "@/env.js"; -import config from "@/config/index.js"; +import config, { envOption } from "@/config/index.js"; import * as SyslogPro from "syslog-pro"; @@ -29,9 +28,9 @@ export default class Logger { if (config.syslog) { this.syslogClient = new SyslogPro.RFC5424({ - applacationName: "Firefish", + applicationName: "Firefish", timestamp: true, - encludeStructuredData: true, + includeStructuredData: true, color: true, extendedColor: true, server: { @@ -56,7 +55,6 @@ export default class Logger { subDomains: Domain[] = [], store = true, ): void { - if (envOption.quiet) return; if ( !(typeof config.logLevel === "undefined") && !config.logLevel.includes(level) @@ -146,12 +144,12 @@ export default class Logger { } } + // Used when the process can't continue (fatal error) public error( x: string | Error, data?: Record | null, important = false, ): void { - // 実行を継続できない状況で使う if (x instanceof Error) { data = data || {}; data.e = x; @@ -168,30 +166,30 @@ export default class Logger { } } + // Used when the process can continue but some action should be taken public warn( message: string, data?: Record | null, important = false, ): void { - // 実行を継続できるが改善すべき状況で使う this.log("warning", message, data, important); } + // Used when something is successful public succ( message: string, data?: Record | null, important = false, ): void { - // 何かに成功した状況で使う this.log("success", message, data, important); } + // Used for debugging (information necessary for developers but unnecessary for users) public debug( message: string, data?: Record | null, important = false, ): void { - // Used for debugging (information necessary for developers but unnecessary for users) // Fixed if statement is ignored when logLevel includes debug if ( config.logLevel?.includes("debug") || @@ -202,12 +200,12 @@ export default class Logger { } } + // Other generic logs public info( message: string, data?: Record | null, important = false, ): void { - // それ以外 this.log("info", message, data, important); } } diff --git a/packages/backend/src/services/messages/create.ts b/packages/backend/src/services/messages/create.ts index 0b3f8eded9..257a132e6b 100644 --- a/packages/backend/src/services/messages/create.ts +++ b/packages/backend/src/services/messages/create.ts @@ -7,7 +7,7 @@ import { Mutings, Users, } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId, toPuny } from "backend-rs"; import type { MessagingMessage } from "@/models/entities/messaging-message.js"; import { publishMessagingStream, @@ -22,7 +22,6 @@ import renderNote from "@/remote/activitypub/renderer/note.js"; import renderCreate from "@/remote/activitypub/renderer/create.js"; import { renderActivity } from "@/remote/activitypub/renderer/index.js"; import { deliver } from "@/queue/index.js"; -import { toPuny } from "@/misc/convert-host.js"; import { Instances } from "@/models/index.js"; export async function createMessage( diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index 2bd7442211..0a4ddc517f 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -37,14 +37,14 @@ import type { DriveFile } from "@/models/entities/drive-file.js"; import type { App } from "@/models/entities/app.js"; import { Not, In } from "typeorm"; import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { activeUsersChart } from "@/services/chart/index.js"; import type { IPoll } from "@/models/entities/poll.js"; import { Poll } from "@/models/entities/poll.js"; import { createNotification } from "@/services/create-notification.js"; import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; import { checkHitAntenna } from "@/misc/check-hit-antenna.js"; -import { getWordHardMute } from "@/misc/check-word-mute.js"; +import { checkWordMute } from "backend-rs"; import { addNoteToAntenna } from "@/services/add-note-to-antenna.js"; import { countSameRenotes } from "@/misc/count-same-renotes.js"; import { deliverToRelays, getCachedRelays } from "../relay.js"; @@ -380,7 +380,7 @@ export default async ( .then((us) => { for (const u of us) { if (u.userId === user.id) return; - getWordHardMute(note, u.mutedWords, u.mutedPatterns).then( + checkWordMute(note, u.mutedWords, u.mutedPatterns).then( (shouldMute: boolean) => { if (shouldMute) { MutedNotes.insert({ diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index ac3515cfae..be3bf1e8b2 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -38,7 +38,6 @@ async function recalculateNotesCountOfLocalUser(user: { export default async function ( user: { id: User["id"]; uri: User["uri"]; host: User["host"] }, note: Note, - quiet = false, deleteFromDb = true, ) { const deletedAt = new Date(); @@ -67,87 +66,80 @@ export default async function ( } const instanceNotesCountDecreasement: Record = {}; - if (!quiet) { - // Only broadcast "deleted" to local if the note is deleted from db + // Only broadcast "deleted" to local if the note is deleted from db + if (deleteFromDb) { + publishNoteStream(note.id, "deleted", { + deletedAt: deletedAt, + }); + } + + //#region ローカルの投稿なら削除アクティビティを配送 + if (Users.isLocalUser(user) && !note.localOnly) { + let renote: Note | null = null; + + // if deletd note is renote + if ( + note.renoteId && + note.text == null && + !note.hasPoll && + (note.fileIds == null || note.fileIds.length === 0) + ) { + renote = await Notes.findOneBy({ + id: note.renoteId, + }); + } + + const content = renderActivity( + renote + ? renderUndo( + renderAnnounce( + renote.uri || `${config.url}/notes/${renote.id}`, + note, + ), + user, + ) + : renderDelete(renderTombstone(`${config.url}/notes/${note.id}`), user), + ); + + deliverToConcerned(user, note, content); + } + + // also deliever delete activity to cascaded notes + for (const cascadingNote of cascadingNotes) { if (deleteFromDb) { - publishNoteStream(note.id, "deleted", { + // For other notes, publishNoteStream is also required. + publishNoteStream(cascadingNote.id, "deleted", { deletedAt: deletedAt, }); } - //#region ローカルの投稿なら削除アクティビティを配送 - if (Users.isLocalUser(user) && !note.localOnly) { - let renote: Note | null = null; - - // if deletd note is renote - if ( - note.renoteId && - note.text == null && - !note.hasPoll && - (note.fileIds == null || note.fileIds.length === 0) - ) { - renote = await Notes.findOneBy({ - id: note.renoteId, - }); - } - - const content = renderActivity( - renote - ? renderUndo( - renderAnnounce( - renote.uri || `${config.url}/notes/${renote.id}`, - note, - ), - user, - ) - : renderDelete( - renderTombstone(`${config.url}/notes/${note.id}`), - user, - ), - ); - - deliverToConcerned(user, note, content); + if (!cascadingNote.user) continue; + if (!Users.isLocalUser(cascadingNote.user)) { + if (!Users.isRemoteUser(cascadingNote.user)) continue; + instanceNotesCountDecreasement[cascadingNote.user.host] ??= 0; + instanceNotesCountDecreasement[cascadingNote.user.host]++; + continue; // filter out remote users } + affectedLocalUsers[cascadingNote.user.id] ??= cascadingNote.user; + if (cascadingNote.localOnly) continue; // filter out local-only notes + const content = renderActivity( + renderDelete( + renderTombstone(`${config.url}/notes/${cascadingNote.id}`), + cascadingNote.user, + ), + ); + deliverToConcerned(cascadingNote.user, cascadingNote, content); + } + //#endregion - // also deliever delete activity to cascaded notes - for (const cascadingNote of cascadingNotes) { - if (deleteFromDb) { - // For other notes, publishNoteStream is also required. - publishNoteStream(cascadingNote.id, "deleted", { - deletedAt: deletedAt, - }); - } - - if (!cascadingNote.user) continue; - if (!Users.isLocalUser(cascadingNote.user)) { - if (!Users.isRemoteUser(cascadingNote.user)) continue; - instanceNotesCountDecreasement[cascadingNote.user.host] ??= 0; - instanceNotesCountDecreasement[cascadingNote.user.host]++; - continue; // filter out remote users - } - affectedLocalUsers[cascadingNote.user.id] ??= cascadingNote.user; - if (cascadingNote.localOnly) continue; // filter out local-only notes - const content = renderActivity( - renderDelete( - renderTombstone(`${config.url}/notes/${cascadingNote.id}`), - cascadingNote.user, - ), - ); - deliverToConcerned(cascadingNote.user, cascadingNote, content); - } - //#endregion - - if (Users.isRemoteUser(user)) { - instanceNotesCountDecreasement[user.host] ??= 0; - instanceNotesCountDecreasement[user.host]++; - } - for (const [host, count] of Object.entries( - instanceNotesCountDecreasement, - )) { - registerOrFetchInstanceDoc(host).then((i) => { - Instances.decrement({ id: i.id }, "notesCount", count); - }); - } + if (Users.isRemoteUser(user)) { + instanceNotesCountDecreasement[user.host] ??= 0; + instanceNotesCountDecreasement[user.host]++; + } + for (const [host, count] of Object.entries(instanceNotesCountDecreasement)) { + registerOrFetchInstanceDoc(host).then((i) => { + Instances.decrement({ id: i.id }, "notesCount", count); + }); } if (deleteFromDb) { diff --git a/packages/backend/src/services/note/polls/vote.ts b/packages/backend/src/services/note/polls/vote.ts index 6ade899726..32213ddcc8 100644 --- a/packages/backend/src/services/note/polls/vote.ts +++ b/packages/backend/src/services/note/polls/vote.ts @@ -3,7 +3,7 @@ import type { CacheableUser } from "@/models/entities/user.js"; import type { Note } from "@/models/entities/note.js"; import { PollVotes, NoteWatchings, Polls, Blockings } from "@/models/index.js"; import { Not } from "typeorm"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { createNotification } from "@/services/create-notification.js"; export default async function ( diff --git a/packages/backend/src/services/note/reaction/create.ts b/packages/backend/src/services/note/reaction/create.ts index d9f45cc50a..3b8b97cefd 100644 --- a/packages/backend/src/services/note/reaction/create.ts +++ b/packages/backend/src/services/note/reaction/create.ts @@ -2,7 +2,6 @@ import { publishNoteStream } from "@/services/stream.js"; import { renderLike } from "@/remote/activitypub/renderer/like.js"; import DeliverManager from "@/remote/activitypub/deliver-manager.js"; import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import { toDbReaction, decodeReaction } from "@/misc/reaction-lib.js"; import type { User, IRemoteUser } from "@/models/entities/user.js"; import type { Note } from "@/models/entities/note.js"; import { @@ -14,7 +13,7 @@ import { Blockings, } from "@/models/index.js"; import { IsNull, Not } from "typeorm"; -import { genId } from "@/misc/gen-id.js"; +import { decodeReaction, genId, toDbReaction } from "backend-rs"; import { createNotification } from "@/services/create-notification.js"; import deleteReaction from "./delete.js"; import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; @@ -95,7 +94,7 @@ export default async ( const emoji = await Emojis.findOne({ where: { - name: decodedReaction.name, + name: decodedReaction.name ?? undefined, host: decodedReaction.host ?? IsNull(), }, select: ["name", "host", "originalUrl", "publicUrl"], diff --git a/packages/backend/src/services/note/reaction/delete.ts b/packages/backend/src/services/note/reaction/delete.ts index 49879a0c02..e5416a78a8 100644 --- a/packages/backend/src/services/note/reaction/delete.ts +++ b/packages/backend/src/services/note/reaction/delete.ts @@ -7,7 +7,7 @@ import { IdentifiableError } from "@/misc/identifiable-error.js"; import type { User, IRemoteUser } from "@/models/entities/user.js"; import type { Note } from "@/models/entities/note.js"; import { NoteReactions, Users, Notes } from "@/models/index.js"; -import { decodeReaction } from "@/misc/reaction-lib.js"; +import { decodeReaction } from "backend-rs"; export default async ( user: { id: User["id"]; host: User["host"] }, diff --git a/packages/backend/src/services/note/read.ts b/packages/backend/src/services/note/read.ts index 3c49501416..d7fda27a85 100644 --- a/packages/backend/src/services/note/read.ts +++ b/packages/backend/src/services/note/read.ts @@ -1,12 +1,7 @@ import { publishMainStream } from "@/services/stream.js"; import type { Note } from "@/models/entities/note.js"; import type { User } from "@/models/entities/user.js"; -import { - NoteUnreads, - Users, - Followings, - ChannelFollowings, -} from "@/models/index.js"; +import { NoteUnreads, Followings, ChannelFollowings } from "@/models/index.js"; import { Not, IsNull, In } from "typeorm"; import type { Channel } from "@/models/entities/channel.js"; import { readNotificationByQuery } from "@/server/api/common/read-notification.js"; @@ -120,34 +115,4 @@ export default async function ( ]), }); } - - // if (readAntennaNotes.length > 0) { - // await AntennaNotes.update( - // { - // antennaId: In(myAntennas.map((a) => a.id)), - // noteId: In(readAntennaNotes.map((n) => n.id)), - // }, - // { - // read: true, - // }, - // ); - - // // TODO: まとめてクエリしたい - // for (const antenna of myAntennas) { - // const count = await AntennaNotes.countBy({ - // antennaId: antenna.id, - // read: false, - // }); - - // if (count === 0) { - // publishMainStream(userId, "readAntenna", antenna); - // } - // } - - // Users.getHasUnreadAntenna(userId).then((unread) => { - // if (!unread) { - // publishMainStream(userId, "readAllAntennas"); - // } - // }); - // } } diff --git a/packages/backend/src/services/note/unread.ts b/packages/backend/src/services/note/unread.ts index cb87abe0e6..e00dcd07ac 100644 --- a/packages/backend/src/services/note/unread.ts +++ b/packages/backend/src/services/note/unread.ts @@ -2,7 +2,7 @@ import type { Note } from "@/models/entities/note.js"; import { publishMainStream } from "@/services/stream.js"; import type { User } from "@/models/entities/user.js"; import { Mutings, NoteThreadMutings, NoteUnreads } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; export async function insertNoteUnread( userId: User["id"], diff --git a/packages/backend/src/services/note/watch.ts b/packages/backend/src/services/note/watch.ts index 2a99dd6949..682b0822cc 100644 --- a/packages/backend/src/services/note/watch.ts +++ b/packages/backend/src/services/note/watch.ts @@ -1,7 +1,7 @@ import type { User } from "@/models/entities/user.js"; import type { Note } from "@/models/entities/note.js"; import { NoteWatchings } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import type { NoteWatching } from "@/models/entities/note-watching.js"; export default async (me: User["id"], note: Note) => { diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index a207fae391..3f1f2cfb1a 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -1,9 +1,8 @@ import push from "web-push"; import config from "@/config/index.js"; import { SwSubscriptions } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta, getNoteSummary } from "backend-rs"; import type { Packed } from "@/misc/schema.js"; -import { getNoteSummary } from "@/misc/get-note-summary.js"; // Defined also packages/sw/types.ts#L14-L21 type pushNotificationsTypes = { @@ -17,15 +16,15 @@ type pushNotificationsTypes = { // プッシュメッセージサーバーには文字数制限があるため、内容を削減します function truncateNotification(notification: Packed<"Notification">): any { - if (notification.note) { + if (notification.note != null) { return { ...notification, note: { ...notification.note, - // textをgetNoteSummaryしたものに置き換える + // replace the text with summary text: getNoteSummary( - notification.type === "renote" - ? (notification.note.renote as Packed<"Note">) + notification.type === "renote" && notification.note.renote != null + ? notification.note.renote : notification.note, ), @@ -45,7 +44,7 @@ export async function pushNotification( type: T, body: pushNotificationsTypes[T], ) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( !meta.enableServiceWorker || @@ -92,7 +91,7 @@ export async function pushNotification( ? truncateNotification(body as Packed<"Notification">) : body, userId, - dateTime: new Date().getTime(), + dateTime: Date.now(), }), { proxy: config.proxy, diff --git a/packages/backend/src/services/register-or-fetch-instance-doc.ts b/packages/backend/src/services/register-or-fetch-instance-doc.ts index c0ead08190..bb044db287 100644 --- a/packages/backend/src/services/register-or-fetch-instance-doc.ts +++ b/packages/backend/src/services/register-or-fetch-instance-doc.ts @@ -1,9 +1,14 @@ -import type { Instance } from "@/models/entities/instance.js"; +import { + type Instance, + MAX_LENGTH_INSTANCE, +} from "@/models/entities/instance.js"; import { Instances } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { genId } from "backend-rs"; +import { toPuny } from "backend-rs"; import { Cache } from "@/misc/cache.js"; +import Logger from "@/services/logger.js"; +const logger = new Logger("register-or-fetch-instance"); const cache = new Cache("registerOrFetchInstanceDoc", 60 * 60); export async function registerOrFetchInstanceDoc( @@ -11,6 +16,14 @@ export async function registerOrFetchInstanceDoc( ): Promise { const _host = toPuny(host); + if (_host.length > MAX_LENGTH_INSTANCE.host) { + logger.error( + `Instance host name must not be longer than ${MAX_LENGTH_INSTANCE.host} characters`, + ); + logger.error(`hostname: ${_host}`); + throw new Error("Instance host name is too long"); + } + const cached = await cache.get(_host); if (cached) return cached; diff --git a/packages/backend/src/services/relay.ts b/packages/backend/src/services/relay.ts index fdc42616ea..bd632ab1c1 100644 --- a/packages/backend/src/services/relay.ts +++ b/packages/backend/src/services/relay.ts @@ -8,7 +8,7 @@ import renderUndo from "@/remote/activitypub/renderer/undo.js"; import { deliver } from "@/queue/index.js"; import type { ILocalUser, User } from "@/models/entities/user.js"; import { Users, Relays } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { Cache } from "@/misc/cache.js"; import type { Relay } from "@/models/entities/relay.js"; import { createSystemUser } from "@/services/create-system-user.js"; diff --git a/packages/backend/src/services/send-email-notification.ts b/packages/backend/src/services/send-email-notification.ts index aa8fa35ffe..8eed0a4e69 100644 --- a/packages/backend/src/services/send-email-notification.ts +++ b/packages/backend/src/services/send-email-notification.ts @@ -2,7 +2,7 @@ import type { User } from "@/models/entities/user.js"; // import { sendEmail } from "./send-email.js"; // import { I18n } from "@/misc/i18n.js"; -// import * as Acct from "@/misc/acct.js"; +// import { acctToString } from "backend-rs"; // TODO //const locales = await import('../../../../locales/index.js'); @@ -15,7 +15,7 @@ async function follow(userId: User["id"], follower: User) { const locale = locales['en-US']; const i18n = new I18n(locale); // TODO: render user information html - sendEmail(userProfile.email, i18n.t('_email._follow.title'), `${follower.name} (@${Acct.toString(follower)})`, `${follower.name} (@${Acct.toString(follower)})`); + sendEmail(userProfile.email, i18n.t('_email._follow.title'), `${follower.name} (@${acctToString(follower)})`, `${follower.name} (@${acctToString(follower)})`); */ } @@ -26,7 +26,7 @@ async function receiveFollowRequest(userId: User["id"], follower: User) { const locale = locales['en-US']; const i18n = new I18n(locale); // TODO: render user information html - sendEmail(userProfile.email, i18n.t('_email._receiveFollowRequest.title'), `${follower.name} (@${Acct.toString(follower)})`, `${follower.name} (@${Acct.toString(follower)})`); + sendEmail(userProfile.email, i18n.t('_email._receiveFollowRequest.title'), `${follower.name} (@${acctToString(follower)})`, `${follower.name} (@${acctToString(follower)})`); */ } diff --git a/packages/backend/src/services/send-email.ts b/packages/backend/src/services/send-email.ts index aa96cfc014..11a899d267 100644 --- a/packages/backend/src/services/send-email.ts +++ b/packages/backend/src/services/send-email.ts @@ -1,5 +1,5 @@ import * as nodemailer from "nodemailer"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import Logger from "@/services/logger.js"; import config from "@/config/index.js"; import { inspect } from "node:util"; @@ -12,7 +12,7 @@ export async function sendEmail( html: string, text: string, ) { - const meta = await fetchMeta(true); + const meta = await fetchMeta(false); const iconUrl = `${config.url}/static-assets/mi-white.png`; const emailSettingUrl = `${config.url}/settings/email`; diff --git a/packages/backend/src/services/update-hashtag.ts b/packages/backend/src/services/update-hashtag.ts index a2b61664b4..05a899db6c 100644 --- a/packages/backend/src/services/update-hashtag.ts +++ b/packages/backend/src/services/update-hashtag.ts @@ -1,6 +1,6 @@ import type { User } from "@/models/entities/user.js"; import { Hashtags, Users } from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import type { Hashtag } from "@/models/entities/hashtag.js"; import { normalizeForSearch } from "@/misc/normalize-for-search.js"; diff --git a/packages/backend/src/services/user-list/push.ts b/packages/backend/src/services/user-list/push.ts index db01b0a900..141584e294 100644 --- a/packages/backend/src/services/user-list/push.ts +++ b/packages/backend/src/services/user-list/push.ts @@ -3,7 +3,7 @@ import type { User } from "@/models/entities/user.js"; import type { UserList } from "@/models/entities/user-list.js"; import { UserListJoinings, Users } from "@/models/index.js"; import type { UserListJoining } from "@/models/entities/user-list-joining.js"; -import { genId } from "@/misc/gen-id.js"; +import { genId } from "backend-rs"; import { fetchProxyAccount } from "@/misc/fetch-proxy-account.js"; import createFollowing from "@/services/following/create.js"; diff --git a/packages/backend/src/services/validate-email-for-account.ts b/packages/backend/src/services/validate-email-for-account.ts index 4d05afcc6d..5aa091a5ac 100644 --- a/packages/backend/src/services/validate-email-for-account.ts +++ b/packages/backend/src/services/validate-email-for-account.ts @@ -1,12 +1,12 @@ import { validate as validateEmail } from "deep-email-validator"; import { UserProfiles } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; export async function validateEmailForAccount(emailAddress: string): Promise<{ available: boolean; reason: null | "used" | "format" | "disposable" | "mx" | "smtp"; }> { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const exist = await UserProfiles.countBy({ emailVerified: true, diff --git a/packages/client/.eslintrc.json b/packages/client/.eslintrc.json index 1afa80de9f..37d80f6588 100644 --- a/packages/client/.eslintrc.json +++ b/packages/client/.eslintrc.json @@ -4,16 +4,17 @@ "ignorePatterns": ["**/*.json5"], "rules": { "file-progress/activate": 1, - "prettier/prettier": 0, - "one-var": ["error", "never"], + "prettier/prettier": "off", + "one-var": ["warn", "never"], "@typescript-eslint/no-unused-vars": [ - "error", + "warn", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_", "destructuredArrayIgnorePattern": "^_" } - ] + ], + "vue/no-setup-props-destructure": "off" } } diff --git a/packages/client/@types/global.d.ts b/packages/client/@types/global.d.ts index c757482900..3ac4f09b0c 100644 --- a/packages/client/@types/global.d.ts +++ b/packages/client/@types/global.d.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/suspicious/noExplicitAny: type FIXME = any; declare const _LANGS_: string[][]; diff --git a/packages/client/@types/window.d.ts b/packages/client/@types/window.d.ts new file mode 100644 index 0000000000..1ae20c0d20 --- /dev/null +++ b/packages/client/@types/window.d.ts @@ -0,0 +1,6 @@ +declare global { + interface Window { + __misskey_input_ref__?: HTMLInputElement | null; + } +} +export type {}; diff --git a/packages/client/assets/tagcanvas.min.js b/packages/client/assets/tagcanvas.min.js index 526dec528d..60f5306807 100644 --- a/packages/client/assets/tagcanvas.min.js +++ b/packages/client/assets/tagcanvas.min.js @@ -968,8 +968,8 @@ a = c.documentElement, d = c.body, e = window, - h = e.pageXOffset || a.scrollLeft, - i = e.pageYOffset || a.scrollTop, + h = e.scrollX || a.scrollLeft, + i = e.scrollY || a.scrollTop, j = a.clientLeft || d.clientLeft, k = a.clientTop || d.clientTop; return { x: b.left + h - j, y: b.top + i - k }; diff --git a/packages/client/package.json b/packages/client/package.json index 8585bd1834..97a5f83ef7 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -8,12 +8,13 @@ "build:debug": "pnpm run build", "lint": "pnpm biome check **/*.ts --apply ; pnpm run lint:vue", "lint:vue": "pnpm eslint src --fix '**/*.vue' --cache ; pnpm run format", + "types:check": "pnpm vue-tsc --noEmit", "format": "pnpm biome format * --write" }, "devDependencies": { "@eslint-sets/eslint-config-vue3": "^5.12.0", "@eslint-sets/eslint-config-vue3-ts": "^3.3.0", - "@phosphor-icons/web": "^2.0.3", + "@phosphor-icons/web": "^2.1.1", "@rollup/plugin-alias": "5.1.0", "@rollup/plugin-json": "6.1.0", "@rollup/pluginutils": "^5.1.0", @@ -47,7 +48,7 @@ "compare-versions": "6.1.0", "cropperjs": "2.0.0-beta.4", "date-fns": "3.6.0", - "emojilib": "^3.0.11", + "emojilib": "^3.0.12", "eslint-plugin-file-progress": "^1.3.0", "eventemitter3": "5.0.1", "fast-blurhash": "^1.1.2", @@ -66,26 +67,27 @@ "photoswipe": "5.4.3", "prismjs": "1.29.0", "punycode": "2.3.1", - "rollup": "4.13.0", + "rollup": "4.14.2", "s-age": "1.1.2", - "sass": "1.72.0", + "sass": "1.75.0", "seedrandom": "3.0.5", "stringz": "2.1.0", - "swiper": "11.0.7", + "swiper": "11.1.1", "syuilo-password-strength": "0.0.1", "textarea-caret": "3.1.0", - "three": "0.162.0", + "three": "0.163.0", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tinyld": "^1.3.4", - "typescript": "5.4.3", + "typescript": "5.4.5", "unicode-emoji-json": "^0.6.0", "uuid": "9.0.1", - "vite": "5.2.6", + "vite": "5.2.8", "vite-plugin-compression": "^0.5.1", "vue": "3.4.21", - "vue-draggable-plus": "^0.3.5", + "vue-draggable-plus": "^0.4.0", "vue-plyr": "^7.0.0", - "vue-prism-editor": "2.0.0-alpha.2" + "vue-prism-editor": "2.0.0-alpha.2", + "vue-tsc": "2.0.13" } } diff --git a/packages/client/src/account.ts b/packages/client/src/account.ts index 4fd201fa49..cf6fb54915 100644 --- a/packages/client/src/account.ts +++ b/packages/client/src/account.ts @@ -4,6 +4,7 @@ import { i18n } from "./i18n"; import { apiUrl } from "@/config"; import { me } from "@/me"; import { alert, api, popup, popupMenu, waiting } from "@/os"; +import icon from "@/scripts/icon"; import { del, get, set } from "@/scripts/idb-proxy"; import { reloadChannel, unisonReload } from "@/scripts/unison-reload"; @@ -234,7 +235,7 @@ export async function openAccountMenu( ? [ { type: "parent", - icon: "ph-plus ph-bold ph-lg", + icon: `${icon("ph-plus")}`, text: i18n.ts.addAccount, children: [ { @@ -276,7 +277,7 @@ export async function openAccountMenu( : [ { type: "parent", - icon: "ph-plus ph-bold ph-lg", + icon: `${icon("ph-plus")}`, text: i18n.ts.addAccount, children: [ { diff --git a/packages/client/src/components/MkAbuseReport.vue b/packages/client/src/components/MkAbuseReport.vue index 5536523948..b190652052 100644 --- a/packages/client/src/components/MkAbuseReport.vue +++ b/packages/client/src/components/MkAbuseReport.vue @@ -67,6 +67,7 @@ {{ emoji.emoji }} ({{ emoji.aliasOf }}) import { onMounted, ref } from "vue"; +import type { entities } from "firefish-js"; import * as os from "@/os"; const props = defineProps<{ userIds: string[]; }>(); -const users = ref([]); +const users = ref([]); onMounted(async () => { users.value = await os.api("users/show", { diff --git a/packages/client/src/components/MkButton.vue b/packages/client/src/components/MkButton.vue index 48864be62a..ab62fd166c 100644 --- a/packages/client/src/components/MkButton.vue +++ b/packages/client/src/components/MkButton.vue @@ -16,7 +16,7 @@ v-else class="bghgjjyj _button" :class="{ inline, primary, gradate, danger, rounded, full, mini }" - :to="to" + :to="to!" @mousedown="onMousedown" >
@@ -36,6 +36,7 @@ const props = defineProps<{ gradate?: boolean; rounded?: boolean; inline?: boolean; + // FIXME: if `link`, `to` is necessary link?: boolean; to?: string; autofocus?: boolean; @@ -47,7 +48,7 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: "click", payload: MouseEvent): void; + click: [payload: MouseEvent]; }>(); const el = ref(null); @@ -61,11 +62,19 @@ onMounted(() => { } }); -function distance(p, q): number { +function distance( + p: { x: number; y: number }, + q: { x: number; y: number }, +): number { return Math.hypot(p.x - q.x, p.y - q.y); } -function calcCircleScale(boxW, boxH, circleCenterX, circleCenterY): number { +function calcCircleScale( + boxW: number, + boxH: number, + circleCenterX: number, + circleCenterY: number, +): number { const origin = { x: circleCenterX, y: circleCenterY }; const dist1 = distance({ x: 0, y: 0 }, origin); const dist2 = distance({ x: boxW, y: 0 }, origin); @@ -79,8 +88,8 @@ function onMousedown(evt: MouseEvent): void { const rect = target.getBoundingClientRect(); const ripple = document.createElement("div"); - ripple.style.top = (evt.clientY - rect.top - 1).toString() + "px"; - ripple.style.left = (evt.clientX - rect.left - 1).toString() + "px"; + ripple.style.top = `${(evt.clientY - rect.top - 1).toString()}px`; + ripple.style.left = `${(evt.clientX - rect.left - 1).toString()}px`; ripples.value!.appendChild(ripple); @@ -97,7 +106,7 @@ function onMousedown(evt: MouseEvent): void { vibrate(10); window.setTimeout(() => { - ripple.style.transform = "scale(" + scale / 2 + ")"; + ripple.style.transform = `scale(${scale / 2})`; }, 1); window.setTimeout(() => { ripple.style.transition = "all 1s ease"; diff --git a/packages/client/src/components/MkCaptcha.vue b/packages/client/src/components/MkCaptcha.vue index 146c512fb8..135eee8e90 100644 --- a/packages/client/src/components/MkCaptcha.vue +++ b/packages/client/src/components/MkCaptcha.vue @@ -50,7 +50,7 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: "update:modelValue", v: string | null): void; + "update:modelValue": [v: string | null]; }>(); const available = ref(false); @@ -93,7 +93,9 @@ if (loaded) { src: src.value, }), ) - ).addEventListener("load", () => (available.value = true)); + ) + // biome-ignore lint/suspicious/noAssignInExpressions: assign it intentially + .addEventListener("load", () => (available.value = true)); } function reset() { diff --git a/packages/client/src/components/MkChannelFollowButton.vue b/packages/client/src/components/MkChannelFollowButton.vue index c1910bc595..3ff907b25b 100644 --- a/packages/client/src/components/MkChannelFollowButton.vue +++ b/packages/client/src/components/MkChannelFollowButton.vue @@ -24,13 +24,14 @@ diff --git a/packages/client/src/components/MkChannelPreview.vue b/packages/client/src/components/MkChannelPreview.vue index f824a1b2f5..b7462f5504 100644 --- a/packages/client/src/components/MkChannelPreview.vue +++ b/packages/client/src/components/MkChannelPreview.vue @@ -52,11 +52,12 @@ diff --git a/packages/client/src/components/MkCode.core.vue b/packages/client/src/components/MkCode.core.vue index 11720b4f62..7e3cdac562 100644 --- a/packages/client/src/components/MkCode.core.vue +++ b/packages/client/src/components/MkCode.core.vue @@ -29,6 +29,7 @@ if (props.lang != null && !(props.lang in Prism.languages)) { const { lang } = props; loadLanguage(props.lang).then( // onLoaded + // biome-ignore lint/suspicious/noAssignInExpressions: assign intentionally () => (prismLang.value = lang), // onError () => {}, diff --git a/packages/client/src/components/MkContainer.vue b/packages/client/src/components/MkContainer.vue index 404f984415..6f7f19dbf0 100644 --- a/packages/client/src/components/MkContainer.vue +++ b/packages/client/src/components/MkContainer.vue @@ -1,5 +1,6 @@ diff --git a/packages/client/src/pages/channel-editor.vue b/packages/client/src/pages/channel-editor.vue index 60bcfe990e..e776de30e3 100644 --- a/packages/client/src/pages/channel-editor.vue +++ b/packages/client/src/pages/channel-editor.vue @@ -41,6 +41,7 @@ diff --git a/packages/client/src/pages/clip.vue b/packages/client/src/pages/clip.vue index ffe00beeec..8507721519 100644 --- a/packages/client/src/pages/clip.vue +++ b/packages/client/src/pages/clip.vue @@ -75,29 +75,29 @@ const headerActions = computed(() => icon: `${icon("ph-pencil")}`, text: i18n.ts.toEdit, handler: async (): Promise => { - const { canceled, result } = await os.form(clip.value.name, { + const { canceled, result } = await os.form(clip.value!.name, { name: { type: "string", label: i18n.ts.name, - default: clip.value.name, + default: clip.value!.name, }, description: { type: "string", required: false, multiline: true, label: i18n.ts.description, - default: clip.value.description, + default: clip.value!.description, }, isPublic: { type: "boolean", label: i18n.ts.public, - default: clip.value.isPublic, + default: clip.value!.isPublic, }, }); if (canceled) return; os.apiWithDialog("clips/update", { - clipId: clip.value.id, + clipId: clip.value!.id, ...result, }); }, diff --git a/packages/client/src/pages/favorites.vue b/packages/client/src/pages/favorites.vue index f9fb36f296..09e857449b 100644 --- a/packages/client/src/pages/favorites.vue +++ b/packages/client/src/pages/favorites.vue @@ -37,6 +37,7 @@ + + diff --git a/packages/client/src/pages/page-editor/els/page-editor.el.image.vue b/packages/client/src/pages/page-editor/els/page-editor.el.image.vue index 859f0f1112..3820b140df 100644 --- a/packages/client/src/pages/page-editor/els/page-editor.el.image.vue +++ b/packages/client/src/pages/page-editor/els/page-editor.el.image.vue @@ -44,9 +44,9 @@ const props = withDefaults( const file = ref(null); async function choose() { - os.selectDriveFile(false).then((fileResponse: any) => { + os.selectDriveFile(false).then((fileResponse) => { file.value = fileResponse; - props.value.fileId = fileResponse.id; + props.value.fileId = fileResponse?.id; }); } diff --git a/packages/client/src/pages/page-editor/page-editor.script-block.vue b/packages/client/src/pages/page-editor/page-editor.script-block.vue index d9403a4d52..54065d4049 100644 --- a/packages/client/src/pages/page-editor/page-editor.script-block.vue +++ b/packages/client/src/pages/page-editor/page-editor.script-block.vue @@ -17,7 +17,7 @@ > @@ -104,7 +104,7 @@ x.type === "fn"); if (userFns.length > 0) { list.unshift({ - label: i18n.t("_pages.script.categories.fn"), + label: i18n.ts._pages.script.categories.fn, items: userFns.map((v) => ({ value: "fn:" + v.name, text: v.name, diff --git a/packages/client/src/pages/page.vue b/packages/client/src/pages/page.vue index 46730b05d1..9ccfed4271 100644 --- a/packages/client/src/pages/page.vue +++ b/packages/client/src/pages/page.vue @@ -47,7 +47,6 @@ v-tooltip="i18n.ts._pages.viewSource" :to="`/@${username}/pages/${pageName}/view-source`" class="menu _button" - style="transform: translateY(2px)" > diff --git a/packages/client/src/pages/user/home.vue b/packages/client/src/pages/user/home.vue index 13846e42d4..463e5cb4a2 100644 --- a/packages/client/src/pages/user/home.vue +++ b/packages/client/src/pages/user/home.vue @@ -101,18 +101,6 @@ v-tooltip.noDelay="i18n.ts.isBot" >
- @@ -188,18 +176,6 @@ v-tooltip.noDelay="i18n.ts.isBot" > -