Merge branch 'develop' into feat/alt_warning

This commit is contained in:
naskya 2024-04-22 06:59:58 +09:00
commit 23ec206aee
No known key found for this signature in database
GPG key ID: 712D413B3A9FED5C
910 changed files with 11730 additions and 6581 deletions

View file

@ -178,19 +178,13 @@ logLevel: [
# Media Proxy # Media Proxy
#mediaProxy: https://example.com/proxy #mediaProxy: https://example.com/proxy
# Proxy remote files (default: false) # Proxy remote files (default: true)
#proxyRemoteFiles: true #proxyRemoteFiles: true
#allowedPrivateNetworks: [ #allowedPrivateNetworks: [
# '127.0.0.1/32' # '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) # Upload or download file size limits (bytes)
#maxFileSize: 262144000 #maxFileSize: 262144000

View file

@ -10,7 +10,7 @@ node_modules
report.*.json report.*.json
# Rust # Rust
packages/backend-rs/target /target
# Coverage # Coverage
coverage coverage

3
.gitignore vendored
View file

@ -14,6 +14,9 @@ packages/backend/.idea/vcs.xml
node_modules node_modules
report.*.json report.*.json
# Cargo
/target
# Cypress # Cypress
cypress/screenshots cypress/screenshots
cypress/videos cypress/videos

View file

@ -3,27 +3,47 @@
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md) 🔒 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) --> 🤝 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? <!-- Please give us a brief description of 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? <!-- Please give us a brief description of what you expected 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 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 browser are you using? (Client-side issues only)**
**What operating system are you using? (Client-side issues only)** ## 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. -->
**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)** <details>
**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 <!-- What instance of firefish are you using? -->
**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 <!-- Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. -->
</details>
## Contribution Guidelines
By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) 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 agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar issues, and this is not a duplicate. - [ ] 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.

View file

@ -3,15 +3,22 @@
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md) 🔒 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) --> 🤝 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? <!-- Please give us a brief description of what you'd like. -->
**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? <!-- Please give us a brief description of why your feature is important. -->
**Instance** _(What instance of firefish are you using?)_
**Contribution Guidelines** ## 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. -->
## Instance <!-- What instance of firefish are you using? -->
## Contribution Guidelines
By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) 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 agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar requests, and this is not a duplicate. - [ ] 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.

View file

@ -1,9 +1,11 @@
<!-- Thanks for taking the time to make Firefish better! It's not required, but please consider using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) when making your commits. If you use VSCode, please use the [Conventional Commits extension](https://marketplace.visualstudio.com/items?itemName=vivaxy.vscode-conventional-commits). --> <!-- Thanks for taking the time to make Firefish better! It's not required, but please consider using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) when making your commits. If you use VSCode, please use the [Conventional Commits extension](https://marketplace.visualstudio.com/items?itemName=vivaxy.vscode-conventional-commits). -->
**What does this PR do?** _(Please give us a brief description of what this PR does.)_ ## What does this PR do? <!-- Please give us a brief description of what this PR does. -->
**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) 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 agree to follow this project's Contribution Guidelines
- [ ] I have made sure to test this pull request - [ ] I have made sure to test this pull request
- [ ] I have made sure to run `pnpm run format` before submitting 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 - [ ] I updated the document / This merge request doesn't include API changes
<!-- Uncomment if your merge request has multiple authors --> <!-- Uncomment if your merge request has multiple authors -->
<!-- Co-authored-by: Name <email@email.com> --> <!-- Co-authored-by: Name <email@example.com> -->

View file

@ -10,6 +10,7 @@ I have updated...
- [ ] `docs/changelog.md` - [ ] `docs/changelog.md`
- [ ] `docs/notice-for-admins.md` - [ ] `docs/notice-for-admins.md`
- [ ] `docs/api-change.md` - [ ] `docs/api-change.md`
- [ ] `packages/backend-rs/index.js`
- [ ] OCI container image - [ ] OCI container image
<!-- TODO: Add automated tests (task runners are currently down) --> <!-- TODO: Add automated tests (task runners are currently down) -->

View file

@ -12,6 +12,7 @@
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"redhat.vscode-yaml", "redhat.vscode-yaml",
"yoavbls.pretty-ts-errors", "yoavbls.pretty-ts-errors",
"biomejs.biome" "biomejs.biome",
"rust-lang.rust-analyzer"
] ]
} }

View file

@ -1,5 +0,0 @@
{
"rust-analyzer.linkedProjects": [
"packages/backend-rs/Cargo.toml"
]
}

View file

@ -1,6 +1,7 @@
Unless specified otherwise, the entirety of this repository is subject to the following: Unless specified otherwise, the entirety of this repository is subject to the following:
Copyright © 2014-2023 syuilo and contributors Copyright © 2014-2023 syuilo and contributors
Copyright © 2022-2023 Kainoa Kanter 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. 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 and their contents are
Copyright © 2022-2023 Kainoa Kanter and contributors 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. 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.

View file

@ -59,9 +59,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.16" version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]] [[package]]
name = "android-tzdata" name = "android-tzdata"
@ -128,9 +128,21 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "arrayvec" name = "arrayvec"
@ -157,18 +169,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.79" version = "0.1.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -190,12 +202,17 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
name = "backend-rs" name = "backend-rs"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"argon2",
"async-trait", "async-trait",
"basen", "basen",
"bcrypt",
"cfg-if", "cfg-if",
"chrono", "chrono",
"cuid2", "cuid2",
"emojis",
"idna",
"jsonschema", "jsonschema",
"macro_rs",
"napi", "napi",
"napi-build", "napi-build",
"napi-derive", "napi-derive",
@ -203,12 +220,16 @@ dependencies = [
"parse-display", "parse-display",
"pretty_assertions", "pretty_assertions",
"rand", "rand",
"regex",
"schemars", "schemars",
"sea-orm", "sea-orm",
"serde", "serde",
"serde_json", "serde_json",
"serde_yaml",
"thiserror", "thiserror",
"tokio", "tokio",
"url",
"urlencoding",
] ]
[[package]] [[package]]
@ -232,6 +253,12 @@ version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.6.0" version = "1.6.0"
@ -244,6 +271,19 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dbe4bb73fd931c4d1aaf53b35d1286c8a948ad00ec92c8e3c856f15fd027f43" 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]] [[package]]
name = "bigdecimal" name = "bigdecimal"
version = "0.3.1" version = "0.3.1"
@ -297,6 +337,15 @@ dependencies = [
"wyz", "wyz",
] ]
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.4" version = "0.10.4"
@ -307,10 +356,20 @@ dependencies = [
] ]
[[package]] [[package]]
name = "borsh" name = "blowfish"
version = "1.3.1" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" 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 = [ dependencies = [
"borsh-derive", "borsh-derive",
"cfg_aliases", "cfg_aliases",
@ -318,23 +377,23 @@ dependencies = [
[[package]] [[package]]
name = "borsh-derive" name = "borsh-derive"
version = "1.3.1" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
"syn_derive", "syn_derive",
] ]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.15.4" version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]] [[package]]
name = "bytecheck" name = "bytecheck"
@ -378,9 +437,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.90" version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -396,9 +455,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.35" version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
dependencies = [ dependencies = [
"android-tzdata", "android-tzdata",
"iana-time-zone", "iana-time-zone",
@ -406,7 +465,17 @@ dependencies = [
"num-traits", "num-traits",
"serde", "serde",
"wasm-bindgen", "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]] [[package]]
@ -440,7 +509,7 @@ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -497,9 +566,9 @@ dependencies = [
[[package]] [[package]]
name = "crc" name = "crc"
version = "3.0.1" version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
dependencies = [ dependencies = [
"crc-catalog", "crc-catalog",
] ]
@ -542,7 +611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c" checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -565,9 +634,9 @@ dependencies = [
[[package]] [[package]]
name = "der" name = "der"
version = "0.7.8" version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
dependencies = [ dependencies = [
"const-oid", "const-oid",
"pem-rfc7468", "pem-rfc7468",
@ -627,18 +696,27 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]] [[package]]
name = "either" name = "either"
version = "1.10.0" version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "encoding_rs" name = "emojis"
version = "0.8.33" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" 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 = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -839,9 +917,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.12" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@ -858,9 +936,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.3.25" version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@ -1066,7 +1144,16 @@ checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "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]] [[package]]
@ -1116,7 +1203,7 @@ checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978"
dependencies = [ dependencies = [
"ahash 0.8.11", "ahash 0.8.11",
"anyhow", "anyhow",
"base64", "base64 0.21.7",
"bytecount", "bytecount",
"clap", "clap",
"fancy-regex", "fancy-regex",
@ -1169,7 +1256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"windows-targets 0.52.4", "windows-targets 0.52.5",
] ]
[[package]] [[package]]
@ -1211,6 +1298,18 @@ version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "macro_rs"
version = "0.0.0"
dependencies = [
"convert_case",
"napi",
"proc-macro2",
"quote",
"syn 2.0.58",
"thiserror",
]
[[package]] [[package]]
name = "md-5" name = "md-5"
version = "0.10.6" version = "0.10.6"
@ -1223,9 +1322,9 @@ dependencies = [
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.1" version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]] [[package]]
name = "mime" name = "mime"
@ -1261,43 +1360,46 @@ dependencies = [
[[package]] [[package]]
name = "napi" name = "napi"
version = "2.16.1" version = "2.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4ca998356d8ff9fba7a070dae4508a2298439c98c9f3bc9c07669538b999e8f" checksum = "70d04890ef4ec001fad791be785b8b920e2a3f5a6b1188e7a81dfa6197c0dee4"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.5.0",
"chrono",
"ctor", "ctor",
"napi-derive", "napi-derive",
"napi-sys", "napi-sys",
"once_cell", "once_cell",
"serde",
"serde_json",
"tokio", "tokio",
] ]
[[package]] [[package]]
name = "napi-build" name = "napi-build"
version = "2.1.2" version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f9130fccc5f763cf2069b34a089a18f0d0883c66aceb81f2fad541a3d823c43" checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a"
[[package]] [[package]]
name = "napi-derive" name = "napi-derive"
version = "2.16.1" version = "2.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b138cecf1141ae0ff5d62f4aa0e2f269aec339f66070f346ba6fb4279f1fc178" checksum = "aff4a63f26a7aa9fa25df6ea36675890115972b207ae516e86bd0c47e31eba39"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"convert_case", "convert_case",
"napi-derive-backend", "napi-derive-backend",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
name = "napi-derive-backend" name = "napi-derive-backend"
version = "1.0.63" version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce5126b64f6ad9e28e30e6d15213dd378626b38f556454afebc42f7f02a90902" checksum = "e5e76afe642e2424ebe465406e328e4316d82af1f79256231d4b0f184c67550a"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"once_cell", "once_cell",
@ -1305,14 +1407,14 @@ dependencies = [
"quote", "quote",
"regex", "regex",
"semver", "semver",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
name = "napi-sys" name = "napi-sys"
version = "2.3.0" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2503fa6af34dc83fb74888df8b22afe933b58d37daf7d80424b1c60c68196b8b" checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3"
dependencies = [ dependencies = [
"libloading", "libloading",
] ]
@ -1329,9 +1431,9 @@ dependencies = [
[[package]] [[package]]
name = "num" name = "num"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-complex", "num-complex",
@ -1487,7 +1589,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -1515,28 +1617,38 @@ dependencies = [
[[package]] [[package]]
name = "parse-display" name = "parse-display"
version = "0.8.2" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6509d08722b53e8dafe97f2027b22ccbe3a5db83cb352931e9716b0aa44bc5c" checksum = "06af5f9333eb47bd9ba8462d612e37a8328a5cb80b13f0af4de4c3b89f52dee5"
dependencies = [ dependencies = [
"once_cell",
"parse-display-derive", "parse-display-derive",
"regex", "regex",
"regex-syntax",
] ]
[[package]] [[package]]
name = "parse-display-derive" name = "parse-display-derive"
version = "0.8.2" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68517892c8daf78da08c0db777fcc17e07f2f63ef70041718f8a7630ad84f341" checksum = "dc9252f259500ee570c75adcc4e317fa6f57a1e47747d622e0bf838002a7b790"
dependencies = [ dependencies = [
"once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"regex", "regex",
"regex-syntax 0.7.5", "regex-syntax",
"structmeta", "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]] [[package]]
@ -1561,10 +1673,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "pin-project-lite" name = "phf"
version = "0.2.13" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "pin-utils" name = "pin-utils"
@ -1685,9 +1815,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.35" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -1746,7 +1876,7 @@ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata", "regex-automata",
"regex-syntax 0.8.2", "regex-syntax",
] ]
[[package]] [[package]]
@ -1757,20 +1887,14 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax 0.8.2", "regex-syntax",
] ]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.7.5" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]] [[package]]
name = "rend" name = "rend"
@ -1787,7 +1911,7 @@ version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [ dependencies = [
"base64", "base64 0.21.7",
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
@ -1883,9 +2007,9 @@ dependencies = [
[[package]] [[package]]
name = "rust_decimal" name = "rust_decimal"
version = "1.34.3" version = "1.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39449a79f45e8da28c57c341891b69a183044b29518bb8f86dbac9df60bb7df" checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"borsh", "borsh",
@ -1933,7 +2057,7 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
dependencies = [ dependencies = [
"base64", "base64 0.21.7",
] ]
[[package]] [[package]]
@ -2003,7 +2127,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -2044,7 +2168,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"sea-bae", "sea-bae",
"syn 2.0.55", "syn 2.0.58",
"unicode-ident", "unicode-ident",
] ]
@ -2110,7 +2234,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -2147,6 +2271,19 @@ dependencies = [
"serde", "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]] [[package]]
name = "sha1" name = "sha1"
version = "0.10.6" version = "0.10.6"
@ -2204,6 +2341,12 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.9" version = "0.4.9"
@ -2371,7 +2514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
dependencies = [ dependencies = [
"atoi", "atoi",
"base64", "base64 0.21.7",
"bigdecimal", "bigdecimal",
"bitflags 2.5.0", "bitflags 2.5.0",
"byteorder", "byteorder",
@ -2418,7 +2561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
dependencies = [ dependencies = [
"atoi", "atoi",
"base64", "base64 0.21.7",
"bigdecimal", "bigdecimal",
"bitflags 2.5.0", "bitflags 2.5.0",
"byteorder", "byteorder",
@ -2500,31 +2643,31 @@ dependencies = [
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.0" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "structmeta" name = "structmeta"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ad9e09554f0456d67a69c1584c9798ba733a5b50349a6c0d0948710523922d" checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive", "structmeta-derive",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
name = "structmeta-derive" name = "structmeta-derive"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -2552,9 +2695,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.55" version = "2.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2570,7 +2713,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -2635,14 +2778,14 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.34" version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa", "itoa",
@ -2661,9 +2804,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.17" version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [ dependencies = [
"num-conv", "num-conv",
"time-core", "time-core",
@ -2686,9 +2829,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.36.0" version = "1.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@ -2711,7 +2854,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -2782,7 +2925,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]
@ -2839,6 +2982,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.9.0" version = "0.9.0"
@ -2931,7 +3080,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -2965,7 +3114,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -3008,7 +3157,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [ dependencies = [
"windows-targets 0.52.4", "windows-targets 0.52.5",
] ]
[[package]] [[package]]
@ -3026,7 +3175,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets 0.52.4", "windows-targets 0.52.5",
] ]
[[package]] [[package]]
@ -3046,17 +3195,18 @@ dependencies = [
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.4" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm 0.52.4", "windows_aarch64_gnullvm 0.52.5",
"windows_aarch64_msvc 0.52.4", "windows_aarch64_msvc 0.52.5",
"windows_i686_gnu 0.52.4", "windows_i686_gnu 0.52.5",
"windows_i686_msvc 0.52.4", "windows_i686_gnullvm",
"windows_x86_64_gnu 0.52.4", "windows_i686_msvc 0.52.5",
"windows_x86_64_gnullvm 0.52.4", "windows_x86_64_gnu 0.52.5",
"windows_x86_64_msvc 0.52.4", "windows_x86_64_gnullvm 0.52.5",
"windows_x86_64_msvc 0.52.5",
] ]
[[package]] [[package]]
@ -3067,9 +3217,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.4" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
@ -3079,9 +3229,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.4" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
@ -3091,9 +3241,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.4" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
@ -3103,9 +3259,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.4" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
@ -3115,9 +3271,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.4" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
@ -3127,9 +3283,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.4" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
@ -3139,9 +3295,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.4" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]] [[package]]
name = "winnow" name = "winnow"
@ -3194,7 +3350,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.58",
] ]
[[package]] [[package]]

42
Cargo.toml Normal file
View file

@ -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

View file

@ -8,9 +8,12 @@ RUN curl --proto '=https' --tlsv1.2 --silent --show-error --fail https://sh.rust
ENV PATH="/root/.cargo/bin:${PATH}" ENV PATH="/root/.cargo/bin:${PATH}"
# Copy only the cargo dependency-related files first, to cache efficiently # 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.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/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 # Install cargo dependencies
RUN cargo fetch --locked --manifest-path /firefish/packages/backend-rs/Cargo.toml RUN cargo fetch --locked --manifest-path /firefish/packages/backend-rs/Cargo.toml

View file

@ -3,7 +3,7 @@ export
.PHONY: pre-commit .PHONY: pre-commit
pre-commit: format entities update-index-js pre-commit: format entities napi-index
.PHONY: format .PHONY: format
format: format:
@ -14,9 +14,9 @@ entities:
pnpm run migrate pnpm run migrate
$(MAKE) -C ./packages/backend-rs regenerate-entities $(MAKE) -C ./packages/backend-rs regenerate-entities
.PHONY: update-index-js .PHONY: napi-index
update-index-js: napi-index:
$(MAKE) -C ./packages/backend-rs index.js $(MAKE) -C ./packages/backend-rs update-index
.PHONY: build .PHONY: build
@ -27,13 +27,13 @@ build:
pnpm run migrate pnpm run migrate
.PHONY: db.init db.up db.down .PHONY: db.up db.down db.init
db.init:
$(MAKE) -C ./dev/db-container init
db.up: db.up:
$(MAKE) -C ./dev/db-container up $(MAKE) -C ./dev/db-container up
db.down: db.down:
$(MAKE) -C ./dev/db-container down $(MAKE) -C ./dev/db-container down
db.init:
$(MAKE) -C ./dev/db-container init
.PHONY: psql redis-cli .PHONY: psql redis-cli
psql: psql:

View file

@ -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": { "organizeImports": {
"enabled": true "enabled": false
}, },
"linter": { "linter": {
"enabled": true, "enabled": true,
"rules": { "rules": {
"recommended": true "recommended": true,
"style": {
"noUselessElse": "off"
}
} }
} },
"overrides": [
{
"include": ["*.vue"],
"linter": {
"rules": {
"style": {
"useImportType": "warn",
"useShorthandFunctionType": "warn",
"useTemplate": "warn",
"noNonNullAssertion": "off",
"useNodejsImportProtocol": "off"
}
}
}
}
]
} }

View file

@ -1,9 +1,11 @@
.PHONY: init up down .PHONY: up down init
init: down up
up: up:
$(COMPOSE) up --detach $(COMPOSE) up --detach
down: down:
$(COMPOSE) down $(COMPOSE) down
init:
$(COMPOSE) down --volumes
$(COMPOSE) up --detach
.PHONY: psql redis-cli .PHONY: psql redis-cli
psql: psql:

View file

@ -5,6 +5,8 @@ services:
image: docker.io/redis:7-alpine image: docker.io/redis:7-alpine
ports: ports:
- "26379:6379" - "26379:6379"
volumes:
- "redis-data:/data"
db: db:
image: docker.io/groonga/pgroonga:3.1.8-alpine-12 image: docker.io/groonga/pgroonga:3.1.8-alpine-12
env_file: env_file:
@ -13,3 +15,10 @@ services:
- "25432:5432" - "25432:5432"
volumes: volumes:
- "./install.sql:/docker-entrypoint-initdb.d/install.sql:ro" - "./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

View file

@ -42,6 +42,8 @@ cargo --version
### PostgreSQL and PGroonga ### 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/). PostgreSQL install instructions can be found at [this page](https://www.postgresql.org/download/).
```sh ```sh

View file

@ -17,6 +17,7 @@ services:
# - web # - web
environment: environment:
NODE_ENV: production NODE_ENV: production
NODE_OPTIONS: --max-old-space-size=3072
volumes: volumes:
- ./custom:/firefish/custom:ro - ./custom:/firefish/custom:ro
- ./files:/firefish/files - ./files:/firefish/files

View file

@ -2,6 +2,18 @@
Breaking changes are indicated by the :warning: icon. 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 ## v20240319
- :warning: `followingCount` and `followersCount` in `users/show` will be `null` (instead of 0) if these values are unavailable. - :warning: `followingCount` and `followersCount` in `users/show` will be `null` (instead of 0) if these values are unavailable.

View file

@ -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. - 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. - 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) ## :warning: [v20240330](https://firefish.dev/firefish/firefish/-/merge_requests/10719/commits)
- Fix bugs (including a critical security issue) - Fix bugs (including a critical security issue)

View file

@ -1,6 +1,11 @@
BEGIN; BEGIN;
DELETE FROM "migrations" WHERE name IN ( DELETE FROM "migrations" WHERE name IN (
'AddDriveFileUsage1713451569342',
'ConvertCwVarcharToText1713225866247',
'FixChatFileConstraint1712855579316',
'DropTimeZone1712425488543',
'ExpandNoteEdit1711936358554',
'markLocalFilesNsfwByDefault1709305200000', 'markLocalFilesNsfwByDefault1709305200000',
'FixMutingIndices1710690239308', 'FixMutingIndices1710690239308',
'NoteFile1710304584214', 'NoteFile1710304584214',
@ -19,6 +24,99 @@ DELETE FROM "migrations" WHERE name IN (
'RemoveNativeUtilsMigration1705877093218' '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 -- markLocalFilesNsfwByDefault
ALTER TABLE "meta" DROP COLUMN "markLocalFilesNsfwByDefault"; ALTER TABLE "meta" DROP COLUMN "markLocalFilesNsfwByDefault";

View file

@ -1,9 +1,36 @@
# Install Firefish # 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 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. Make sure that you can use the `sudo` command before proceeding.
## 1. Install dependencies ## 1. Install dependencies
@ -154,7 +181,7 @@ sudo apt install ffmpeg
1. Build 1. Build
```sh ```sh
pnpm install --frozen-lockfile 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 1. Execute database migrations
```sh ```sh
@ -242,6 +269,7 @@ In this instruction, we use [Caddy](https://caddyserver.com/) to make the Firefi
WorkingDirectory=/home/firefish/firefish WorkingDirectory=/home/firefish/firefish
Environment="NODE_ENV=production" Environment="NODE_ENV=production"
Environment="npm_config_cache=/tmp" 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) # 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" # Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
StandardOutput=journal StandardOutput=journal

View file

@ -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). 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 ## v20240326
### For Docker/Podman users ### For Docker/Podman users
@ -31,11 +58,11 @@ psql (PostgreSQL) 16.1
In this case, your PostgreSQL major version is `16`. In this case, your PostgreSQL major version is `16`.
There are official installation instructions for many operating systems on <https://pgroonga.github.io/install>, 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 <https://pgroonga.github.io/install>, 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 ```sh
sudo apt install -y software-properties-common sudo apt install -y software-properties-common
sudo add-apt-repository -y universe sudo add-apt-repository -y universe
@ -43,14 +70,35 @@ There are official installation instructions for many operating systems on <http
sudo apt install -y wget lsb-release sudo apt install -y wget lsb-release
wget https://packages.groonga.org/ubuntu/groonga-apt-source-latest-$(lsb_release --codename --short).deb wget https://packages.groonga.org/ubuntu/groonga-apt-source-latest-$(lsb_release --codename --short).deb
sudo apt install -y -V ./groonga-apt-source-latest-$(lsb_release --codename --short).deb sudo apt install -y -V ./groonga-apt-source-latest-$(lsb_release --codename --short).deb
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release --codename --short)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt update
``` ```
2. Install PGroonga 2. Install PGroonga (replace `16` with your PostgreSQL version)
```sh ```sh
# Please replace "16" with your PostgreSQL major version
sudo apt install postgresql-16-pgdg-pgroonga sudo apt install postgresql-16-pgdg-pgroonga
# Depending on your PostgreSQL installation method,
# the above command may fail and you need to run
# the following instead:
# sudo apt install postgresql-16-pgroonga
```
##### Debian
1. Install subdependencies
```sh
sudo apt install -y -V ca-certificates lsb-release wget
wget https://apache.jfrog.io/artifactory/arrow/$(lsb_release --id --short | tr 'A-Z' 'a-z')/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb
sudo apt install -y -V ./apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb
wget https://packages.groonga.org/debian/groonga-apt-source-latest-$(lsb_release --codename --short).deb
sudo apt install -y -V ./groonga-apt-source-latest-$(lsb_release --codename --short).deb
```
2. Install PGroonga (replace `16` with your PostgreSQL version)
```sh
sudo apt install postgresql-16-pgdg-pgroonga
# Depending on your PostgreSQL installation method,
# the above command may fail and you need to run
# the following instead:
# sudo apt install postgresql-16-pgroonga
``` ```
##### Arch Linux ##### Arch Linux

View file

@ -822,7 +822,6 @@ auto: "تلقائي"
themeColor: "لون السمة" themeColor: "لون السمة"
size: "الحجم" size: "الحجم"
numberOfColumn: "عدد الأعمدة" numberOfColumn: "عدد الأعمدة"
searchByGoogle: "غوغل"
mutePeriod: "مدة الكتم" mutePeriod: "مدة الكتم"
indefinitely: "أبدًا" indefinitely: "أبدًا"
tenMinutes: "10 دقائق" tenMinutes: "10 دقائق"
@ -894,9 +893,6 @@ _aboutFirefish:
source: "الشفرة المصدرية" source: "الشفرة المصدرية"
translation: "ترجم ميسكي" translation: "ترجم ميسكي"
donate: "تبرع لميسكي" donate: "تبرع لميسكي"
morePatrons: "نحن نقدر الدعم الذي قدمه العديد من الأشخاص الذين لم نذكرهم. شكرًا
لكم 🥰"
patrons: "الداعمون"
_nsfw: _nsfw:
respect: "اخف الوسائط ذات المحتوى الحساس" respect: "اخف الوسائط ذات المحتوى الحساس"
ignore: "اعرض الوسائط ذات المحتوى الحساس" ignore: "اعرض الوسائط ذات المحتوى الحساس"

View file

@ -21,8 +21,8 @@ searchUser: Търсене на потребител
reply: Отговор reply: Отговор
showMore: Покажи още showMore: Покажи още
loadMore: Зареди още loadMore: Зареди още
followRequestAccepted: Заявка за последване приета followRequestAccepted: Заявката за последване е приета
importAndExport: Импорт/Експорт на Данни importAndExport: Импорт/експорт на данни
import: Импортиране import: Импортиране
download: Изтегляне download: Изтегляне
export: Експортиране export: Експортиране
@ -34,7 +34,6 @@ searchWith: 'Търсене: {q}'
smtpUser: Потребителско име smtpUser: Потребителско име
notificationType: Тип известие notificationType: Тип известие
searchResult: Резултати от търсенето searchResult: Резултати от търсенето
searchByGoogle: Търсене
markAsReadAllNotifications: Маркиране на всички известия като прочетени markAsReadAllNotifications: Маркиране на всички известия като прочетени
settingGuide: Препоръчителни настройки settingGuide: Препоръчителни настройки
smtpPass: Парола smtpPass: Парола
@ -47,7 +46,7 @@ groups: Групи
incorrectPassword: Грешна парола. incorrectPassword: Грешна парола.
leaveGroup: Напускане на групата leaveGroup: Напускане на групата
numberOfColumn: Брой колони numberOfColumn: Брой колони
passwordLessLogin: Вход без парола passwordLessLogin: Влизане без парола
newPasswordRetype: Повтори новата парола newPasswordRetype: Повтори новата парола
saveAs: Запазване като... saveAs: Запазване като...
resetPassword: Нулиране на паролата resetPassword: Нулиране на паролата
@ -101,6 +100,8 @@ _profile:
metadataLabel: Етикет metadataLabel: Етикет
metadataEdit: Редактиране на допълнителната информация metadataEdit: Редактиране на допълнителната информация
changeAvatar: Промяна на профилната снимка changeAvatar: Промяна на профилната снимка
youCanIncludeHashtags: Можеш също да включиш хаштагове в биографията си.
changeBanner: Промяна на банера
addAccount: Добавяне на акаунт addAccount: Добавяне на акаунт
followRequestPending: Заявка за последване в изчакване followRequestPending: Заявка за последване в изчакване
signinHistory: История на вписванията signinHistory: История на вписванията
@ -237,6 +238,7 @@ _theme:
installedThemes: Инсталирани теми installedThemes: Инсталирани теми
constant: Константа constant: Константа
addConstant: Добавяне на константа addConstant: Добавяне на константа
make: Направа на тема
_pages: _pages:
script: script:
blocks: blocks:
@ -369,8 +371,8 @@ enterUsername: Въведи потребителско име
renotedBy: Подсилено от {user} renotedBy: Подсилено от {user}
noNotifications: Няма известия noNotifications: Няма известия
instance: Сървър instance: Сървър
basicSettings: Основни Настройки basicSettings: Основни настройки
otherSettings: Други Настройки otherSettings: Други настройки
openInWindow: Отваряне в прозорец openInWindow: Отваряне в прозорец
profile: Профил profile: Профил
timeline: Инфопоток timeline: Инфопоток
@ -638,7 +640,7 @@ _preferencesBackups:
updatedAt: 'Обновено на: {date} {time}' updatedAt: 'Обновено на: {date} {time}'
editWidgetsExit: Готово editWidgetsExit: Готово
done: Готово done: Готово
emailRequiredForSignup: Изискване на адрес на ел. поща за регистриране emailRequiredForSignup: Изискване на адрес за ел. поща за регистриране
preview: Преглед preview: Преглед
privacy: Поверителност privacy: Поверителност
about: Относно about: Относно
@ -785,6 +787,9 @@ _menuDisplay:
hide: Скриване hide: Скриване
_exportOrImport: _exportOrImport:
allNotes: Всички публикации allNotes: Всички публикации
followingList: Следвани потребители
blockingList: Блокирани потребители
muteList: Заглушени потребители
exploreFediverse: Разглеждане на Федивселената exploreFediverse: Разглеждане на Федивселената
recentlyUpdatedUsers: Последно активни потребители recentlyUpdatedUsers: Последно активни потребители
uiLanguage: Език на потребителския интерфейс uiLanguage: Език на потребителския интерфейс
@ -793,7 +798,7 @@ tags: Тагове
youHaveNoGroups: Нямаш групи youHaveNoGroups: Нямаш групи
accessibility: Достъпност accessibility: Достъпност
email: Ел. поща email: Ел. поща
emailAddress: Адрес на ел. поща emailAddress: Адрес за ел. поща
addItem: Добавяне на елемент addItem: Добавяне на елемент
visibility: Видимост visibility: Видимост
description: Описание description: Описание
@ -890,3 +895,40 @@ updatedAt: Обновено на
privateDescription: Видима само за теб privateDescription: Видима само за теб
enableTimelineStreaming: Автоматично обновяване на инфопотоците enableTimelineStreaming: Автоматично обновяване на инфопотоците
toEdit: Редактиране toEdit: Редактиране
showEmojisInReactionNotifications: Показване на емоджита в известията за реакции
rememberNoteVisibility: Запомняне на настройките за видимост на публикациите
drive: Диск
banner: Банер
public: Общодостъпна
makeExplorable: Акаунтът да е видим в "Разглеждане"
hideOnlineStatus: Скриване на онлайн състоянието
customCss: Персонализиран CSS
keepCw: Запазване на предупрежденията за съдържание
makeReactionsPublic: Историята на реакциите да е общодостъпна
noEmailServerWarning: Сървърът за ел. поща не е конфигуриран.
languageForTranslation: Език за превеждане на публикации
private: Частна
replies: Отговори
wordMute: Заглушаване на думи и езици
instanceMute: Заглушаване на сървъри
notificationSettingDesc: Избиране на какви известия да се показват.
preventAiLearning: Предотвратяване на ИИ scraping
indexable: Индексируем
showPreviewByDefault: Показване на преглед при публикуване по подразбиране
showNoAltTextWarning: Показване на предупреждение при опит за публикуване на файлове
без описание
makeFollowManuallyApprove: Заявките за последване да изискват одобряване
enableEmojiReactions: Включване на реакциите с емоджи
autoAcceptFollowed: Автоматично одобряване на заявките за последване от последвани
потребители
expandOnNoteClick: Отваряне на публикацията при кликване
enableInfiniteScroll: Автоматично зареждане на повече
noCrawle: Предотвратяване на индексирането от търсачки
misskeyUpdated: Firefish бе обновен!
emailNotConfiguredWarning: Адресът за ел. поща не е зададен.
notificationSetting: Настройки за известията
emailNotification: Известия по ел. поща
clientSettings: Настройки за устройството
behavior: Поведение
detectPostLanguage: Автоматично откриване на езика и показване на бутон за превеждане
за публикации на чужди езици

View file

@ -894,7 +894,6 @@ auto: "স্বয়ংক্রিয়"
themeColor: "থিমের রং" themeColor: "থিমের রং"
size: "আকার" size: "আকার"
numberOfColumn: "কলামের সংখ্যা" numberOfColumn: "কলামের সংখ্যা"
searchByGoogle: "গুগল"
instanceDefaultLightTheme: "ইন্সট্যান্সের ডিফল্ট লাইট থিম" instanceDefaultLightTheme: "ইন্সট্যান্সের ডিফল্ট লাইট থিম"
instanceDefaultDarkTheme: "ইন্সট্যান্সের ডিফল্ট ডার্ক থিম" instanceDefaultDarkTheme: "ইন্সট্যান্সের ডিফল্ট ডার্ক থিম"
instanceDefaultThemeDescription: "অবজেক্ট ফরম্যাটে থিম কোড লিখুন" instanceDefaultThemeDescription: "অবজেক্ট ফরম্যাটে থিম কোড লিখুন"
@ -976,8 +975,6 @@ _aboutFirefish:
source: "সোর্স কোড" source: "সোর্স কোড"
translation: "Firefish অনুবাদ করুন" translation: "Firefish অনুবাদ করুন"
donate: "Firefish তে দান করুন" donate: "Firefish তে দান করুন"
morePatrons: "আরও অনেকে আমাদের সাহায্য করছেন। তাদের সবাইকে ধন্যবাদ 🥰"
patrons: "সমর্থনকারী"
_nsfw: _nsfw:
respect: "স্পর্শকাতর মিডিয়া লুকান" respect: "স্পর্শকাতর মিডিয়া লুকান"
ignore: "স্পর্শকাতর মিডিয়া লুকাবেন না" ignore: "স্পর্শকাতর মিডিয়া লুকাবেন না"

View file

@ -135,7 +135,6 @@ userList: "Llistes"
smtpUser: "Nom d'usuari" smtpUser: "Nom d'usuari"
smtpPass: "Contrasenya" smtpPass: "Contrasenya"
user: "Usuari" user: "Usuari"
searchByGoogle: "Cerca"
file: "Fitxer" file: "Fitxer"
_email: _email:
_follow: _follow:
@ -856,7 +855,7 @@ more: Més!
featured: Destacat featured: Destacat
usernameOrUserId: Nom o ID d'usuari usernameOrUserId: Nom o ID d'usuari
noSuchUser: No s'ha trobat l'usuari noSuchUser: No s'ha trobat l'usuari
lookup: Cerca lookup: Ves a
attachFile: Afegeix fitxers attachFile: Afegeix fitxers
currentPassword: Contrasenya actual currentPassword: Contrasenya actual
newPassword: Nova contrasenya newPassword: Nova contrasenya
@ -877,7 +876,7 @@ fromDrive: Des del Disc
uploadFromUrl: Puja des d'una adreça URL uploadFromUrl: Puja des d'una adreça URL
uploadFromUrlDescription: Adreça URL del fitxer que vols pujar uploadFromUrlDescription: Adreça URL del fitxer que vols pujar
uploadFromUrlRequested: Pujada demanada uploadFromUrlRequested: Pujada demanada
noMoreHistory: No hi ha res més a l'historial noMoreHistory: No hi ha més historial
tos: Condicions d'ús tos: Condicions d'ús
start: Comença start: Comença
startMessaging: Comença una conversa startMessaging: Comença una conversa
@ -1577,7 +1576,7 @@ cannotUploadBecauseInappropriate: Aquest fitxer no s'ha pogut carregar perquè s
cannotUploadBecauseNoFreeSpace: La pujada ha fallat a causa de la manca d'espai al cannotUploadBecauseNoFreeSpace: La pujada ha fallat a causa de la manca d'espai al
Disc. Disc.
enableAutoSensitive: Marcatge automàtic NSFW enableAutoSensitive: Marcatge automàtic NSFW
moveTo: Mou el compte actual al compte nou moveTo: Mou aquest compte a un compte nou
customKaTeXMacro: Macros KaTeX personalitzats customKaTeXMacro: Macros KaTeX personalitzats
_aboutFirefish: _aboutFirefish:
contributors: Col·laboradors principals contributors: Col·laboradors principals
@ -1587,18 +1586,12 @@ _aboutFirefish:
translation: Tradueix Firefish translation: Tradueix Firefish
about: Firefish és una bifurcació de Misskey feta per ThatOneCalculator, que està about: Firefish és una bifurcació de Misskey feta per ThatOneCalculator, que està
en desenvolupament des del 2022. en desenvolupament des del 2022.
morePatrons: També agraïm el suport de molts altres ajudants que no figuren aquí.
Gràcies! 🥰
patrons: Mecenes de Firefish
patronsList: Llistats cronològicament, no per la quantitat donada. Fes una donació
amb l'enllaç de dalt per veure el teu nom aquí!
donateTitle: T'agrada Firefish? donateTitle: T'agrada Firefish?
pleaseDonateToFirefish: Penseu en fer una donació a Firefish per donar suport al pleaseDonateToFirefish: Penseu en fer una donació a Firefish per donar suport al
seu desenvolupament. seu desenvolupament.
pleaseDonateToHost: Penseu també en fer una donació a la vostre instància, {host}, pleaseDonateToHost: Penseu també en fer una donació a la vostre instància, {host},
per ajudar-lo a suportar els costos de funcionament. per ajudar-lo a suportar els costos de funcionament.
donateHost: Fes una donació a {host} donateHost: Fes una donació a {host}
sponsors: Patrocinadors de Calckey
misskeyContributors: Col·laboradors de Misskey misskeyContributors: Col·laboradors de Misskey
unknown: Desconegut unknown: Desconegut
pageLikesCount: Nombre de pàgines amb M'agrada pageLikesCount: Nombre de pàgines amb M'agrada
@ -1724,7 +1717,7 @@ deleteConfirm: De veritat ho vols esborrar?
receiveAnnouncementFromInstance: Rep notificacions d'aquest servidor receiveAnnouncementFromInstance: Rep notificacions d'aquest servidor
emailNotification: Notificacions per correu electrònic emailNotification: Notificacions per correu electrònic
publish: Publicar publish: Publicar
inChannelSearch: Buscar al canal inChannelSearch: Cerca al canal
useReactionPickerForContextMenu: Obrir el selector de reaccions al fer click esquerra useReactionPickerForContextMenu: Obrir el selector de reaccions al fer click esquerra
typingUsers: L'{users} està escrivint typingUsers: L'{users} està escrivint
oneDay: Un dia oneDay: Un dia
@ -1762,7 +1755,7 @@ customSplashIconsDescription: Les URLS de les icones personalitzades a la pantal
de benvinguda separades per salts de línia. Es mostraran aleatòriament cada vegada de benvinguda separades per salts de línia. Es mostraran aleatòriament cada vegada
que un usuari carrega/recarrega la pàgina. Si us plau, assegureu-vos que les imatges que un usuari carrega/recarrega la pàgina. Si us plau, assegureu-vos que les imatges
estiguin en una URL estàtica, preferiblement amb imatges amb la de 192 x 192. estiguin en una URL estàtica, preferiblement amb imatges amb la de 192 x 192.
moveFrom: Mou a aquest compte des d'un compte anterior moveFrom: Mou-te a aquest compte des d'un compte anterior
moveFromLabel: 'Compte des del qual us moveu:' moveFromLabel: 'Compte des del qual us moveu:'
migrationConfirm: "Esteu absolutament segur que voleu migrar el vostre compte a {account}? migrationConfirm: "Esteu absolutament segur que voleu migrar el vostre compte a {account}?
Un cop ho feu, no podreu revertir-ho i no podreu tornar a utilitzar el vostre compte Un cop ho feu, no podreu revertir-ho i no podreu tornar a utilitzar el vostre compte
@ -2085,9 +2078,9 @@ _experiments:
release: Publicà release: Publicà
title: Experiments title: Experiments
enablePostImports: Activar l'importació de publicacions enablePostImports: Activar l'importació de publicacions
postImportsCaption: Permet els usuaris importar publicacions desde comptes a Firefish, postImportsCaption: Permet als usuaris importar publicacions des de comptes de Firefish,
Misskey, Mastodon, Akkoma i Pleroma. Pot fer que el servidor vagi més lent durant Misskey, Mastodon, Akkoma i Pleroma. Pot fer que el servidor vagi més lent durant
la càrrega si tens un coll d'ampolla a la cua. la importació si la teva cua de feina és saturada.
noGraze: Si us plau, desactiva l'extensió del navegador "Graze for Mastodon", ja que noGraze: Si us plau, desactiva l'extensió del navegador "Graze for Mastodon", ja que
interfereix amb Firefish. interfereix amb Firefish.
accessibility: Accessibilitat accessibility: Accessibilitat
@ -2210,8 +2203,8 @@ squareCatAvatars: Mostrar avatars quadrats per a comptes de gats
replaceChatButtonWithAccountButton: Canviar el botó de xats amb el botó de canvi de replaceChatButtonWithAccountButton: Canviar el botó de xats amb el botó de canvi de
compte compte
replaceWidgetsButtonWithReloadButton: Canviar el botó de ginys amb el botó de recarregar replaceWidgetsButtonWithReloadButton: Canviar el botó de ginys amb el botó de recarregar
searchEngine: Motor de cerca fet servir anla barra MFM searchEngine: Motor de cerca fet servir a la barra MFM
postSearch: Posar els resultats en aquest servidor postSearch: Publicar els resultats en aquest servidor
showBigPostButton: Mostrar un botó gegant al formulari de publicació showBigPostButton: Mostrar un botó gegant al formulari de publicació
_emojiModPerm: _emojiModPerm:
unauthorized: Res unauthorized: Res
@ -2238,7 +2231,7 @@ enableTimelineStreaming: Actualitza les línies de temps automàticament
enablePullToRefresh: Activa "Baixa per actualitzar" enablePullToRefresh: Activa "Baixa per actualitzar"
pullDownToReload: Baixa per actualitzar pullDownToReload: Baixa per actualitzar
pullToRefreshThreshold: Distancia de baixada per actualitzar pullToRefreshThreshold: Distancia de baixada per actualitzar
searchWords: Paraules / ID o adreça a URL a buscar searchWords: Paraules / ID o adreça URL que vols cercar
noSentFollowRequests: No tens cap sol·licitud de seguiment enviada noSentFollowRequests: No tens cap sol·licitud de seguiment enviada
sentFollowRequests: Enviar sol·licituds de seguiment sentFollowRequests: Enviar sol·licituds de seguiment
replyMute: Silencia les respostes a les línies de temps replyMute: Silencia les respostes a les línies de temps
@ -2251,12 +2244,12 @@ searchWordsDescription: "Per cercar publicacions, escriu el terme a buscar. Sepa
Si vols cercar per una seqüencia de paraules (per exemple una frase) has d'escriure-les Si vols cercar per una seqüencia de paraules (per exemple una frase) has d'escriure-les
entre cometes dobles, per no fer una cerca amb condicionant AND: \"Avui he aprés\"\ entre cometes dobles, per no fer una cerca amb condicionant AND: \"Avui he aprés\"\
\n \nSi vols anar a una pàgina d'usuari o publicació en concret, escriu la adreça \n \nSi vols anar a una pàgina d'usuari o publicació en concret, escriu la adreça
URL o la ID en aquest camp i fes clic al botó 'Trobar'. Fent clic a 'Cercar' trobarà URL o la ID en aquest camp i fes clic al botó 'Ves a'. Fent clic a 'Cerca' trobarà
publicacions que, literalment , continguin la ID/adreça URL." publicacions que, literalment , continguin la ID/adreça URL."
searchPostsWithFiles: Només publicacions amb fitxers searchPostsWithFiles: Només publicacions amb fitxers
searchCwAndAlt: Inclou avisos de contingut i arxius amb descripcions searchCwAndAlt: Inclou avisos de contingut i arxius amb descripcions
searchUsers: Publicat per (opcional) searchUsers: Publicat per (opcional)
searchRange: Publicat dintre de (opcional) searchRange: Publicat entre les dates (opcional)
publishTimelines: Publica línies de temps per visitants publishTimelines: Publica línies de temps per visitants
toPost: Publicar toPost: Publicar
publishTimelinesDescription: Si està activat, les línies de temps Global i Local es publishTimelinesDescription: Si està activat, les línies de temps Global i Local es
@ -2294,3 +2287,5 @@ markLocalFilesNsfwByDefaultDescription: Independentment d'aquest ajust, els usua
afectats. afectats.
autocorrectNoteLanguage: Mostra un avís si l'idioma de la publicació no coincideix autocorrectNoteLanguage: Mostra un avís si l'idioma de la publicació no coincideix
amb el resultat de l'idioma detectat automàticament amb el resultat de l'idioma detectat automàticament
noteEditHistory: Historial d'edicions
media: Multimèdia

View file

@ -600,7 +600,6 @@ tablet: "Tablet"
auto: "Auto" auto: "Auto"
size: "Velikost" size: "Velikost"
numberOfColumn: "Počet sloupců" numberOfColumn: "Počet sloupců"
searchByGoogle: "Vyhledávání"
indefinitely: "Navždy" indefinitely: "Navždy"
tenMinutes: "10 minut" tenMinutes: "10 minut"
oneHour: "1 hodina" oneHour: "1 hodina"

View file

@ -923,7 +923,6 @@ auto: "Automatisch"
themeColor: "Farbe der Ticker-Laufschrift" themeColor: "Farbe der Ticker-Laufschrift"
size: "Größe" size: "Größe"
numberOfColumn: "Spaltenanzahl" numberOfColumn: "Spaltenanzahl"
searchByGoogle: "Suchen"
instanceDefaultLightTheme: "Standard-Farbkombination auf diesem Server: \"Hell\"" instanceDefaultLightTheme: "Standard-Farbkombination auf diesem Server: \"Hell\""
instanceDefaultDarkTheme: "Standard-Farbkombination auf diesem Server: \"Dunkel\"" instanceDefaultDarkTheme: "Standard-Farbkombination auf diesem Server: \"Dunkel\""
instanceDefaultThemeDescription: "Gib den Farbschemencode im Objektformat ein." instanceDefaultThemeDescription: "Gib den Farbschemencode im Objektformat ein."
@ -1093,17 +1092,11 @@ _aboutFirefish:
source: "Quellcode" source: "Quellcode"
translation: "Firefish übersetzen" translation: "Firefish übersetzen"
donate: "An Firefish spenden" donate: "An Firefish spenden"
morePatrons: "Wir schätzen ebenso die Unterstützung vieler anderer hier nicht gelisteter
Personen sehr. Danke! 🥰"
patrons: "UnterstützerInnen"
patronsList: Auflistung chonologisch, nicht nach Spenden-Größe. Spende über den
Link oben, um hier aufgeführt zu werden!
donateTitle: Gefällt dir Firefish? donateTitle: Gefällt dir Firefish?
pleaseDonateToFirefish: Bitte erwäge eine Spende an Firefish, um dessen Entwicklung pleaseDonateToFirefish: Bitte erwäge eine Spende an Firefish, um dessen Entwicklung
zu unterstützen. zu unterstützen.
pleaseDonateToHost: Bitte erwäge auch, an deinen Heimatserver {host} zu spenden, pleaseDonateToHost: Bitte erwäge auch, an deinen Heimatserver {host} zu spenden,
um bei der Deckung der Betriebskosten zu helfen. um bei der Deckung der Betriebskosten zu helfen.
sponsors: Firefish-Sponsoren
donateHost: Spende an {host} donateHost: Spende an {host}
misskeyContributors: Misskey-Mitwirkende misskeyContributors: Misskey-Mitwirkende
_nsfw: _nsfw:

View file

@ -295,7 +295,6 @@ searchResult: "Αποτελέσματα αναζήτησης"
learnMore: "Μάθετε περισσότερα" learnMore: "Μάθετε περισσότερα"
controlPanel: "Πίνακας ελέγχου" controlPanel: "Πίνακας ελέγχου"
manageAccounts: "Διαχείριση Λογαριασμών" manageAccounts: "Διαχείριση Λογαριασμών"
searchByGoogle: "Αναζήτηση"
file: "Αρχεία" file: "Αρχεία"
recommended: "Προτεινόμενα" recommended: "Προτεινόμενα"
cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω ανεπαρκούς Αποθηκευτικού cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω ανεπαρκούς Αποθηκευτικού

View file

@ -394,6 +394,7 @@ enableRegistration: "Enable new user registration"
invite: "Invite" invite: "Invite"
driveCapacityPerLocalAccount: "Drive capacity per local user" driveCapacityPerLocalAccount: "Drive capacity per local user"
driveCapacityPerRemoteAccount: "Drive capacity per remote user" driveCapacityPerRemoteAccount: "Drive capacity per remote user"
antennaLimit: "The maximum number of antennas that each user can create"
inMb: "In megabytes" inMb: "In megabytes"
iconUrl: "Icon URL" iconUrl: "Icon URL"
bannerUrl: "Banner image URL" bannerUrl: "Banner image URL"
@ -708,6 +709,7 @@ display: "Display"
copy: "Copy" copy: "Copy"
metrics: "Metrics" metrics: "Metrics"
overview: "Overview" overview: "Overview"
media: "Media"
logs: "Logs" logs: "Logs"
delayed: "Delayed" delayed: "Delayed"
database: "Database" database: "Database"
@ -977,7 +979,6 @@ auto: "Auto"
themeColor: "Server Ticker Color" themeColor: "Server Ticker Color"
size: "Size" size: "Size"
numberOfColumn: "Number of columns" numberOfColumn: "Number of columns"
searchByGoogle: "Search"
instanceDefaultLightTheme: "Server-wide default light theme" instanceDefaultLightTheme: "Server-wide default light theme"
instanceDefaultDarkTheme: "Server-wide default dark theme" instanceDefaultDarkTheme: "Server-wide default dark theme"
instanceDefaultThemeDescription: "Enter the theme code in object format." instanceDefaultThemeDescription: "Enter the theme code in object format."
@ -1338,12 +1339,6 @@ _aboutFirefish:
pleaseDonateToHost: "Please also consider donating to your home server, {host}, pleaseDonateToHost: "Please also consider donating to your home server, {host},
to help support its operation costs." to help support its operation costs."
donateHost: "Donate to {host}" donateHost: "Donate to {host}"
morePatrons: "We also appreciate the support of many other helpers not listed here.
Thank you! 🥰"
sponsors: "Firefish sponsors"
patrons: "Firefish patrons"
patronsList: "Listed chronologically, not by donation size. Donate with the link
above to get your name on here!"
_nsfw: _nsfw:
respect: "Hide NSFW media" respect: "Hide NSFW media"
ignore: "Don't hide NSFW media" ignore: "Don't hide NSFW media"
@ -2236,3 +2231,4 @@ autocorrectNoteLanguage: "Show a warning if the post language does not match the
result" result"
incorrectLanguageWarning: "It looks like your post is in {detected}, but you selected incorrectLanguageWarning: "It looks like your post is in {detected}, but you selected
{current}.\nWould you like to set the language to {detected} instead?" {current}.\nWould you like to set the language to {detected} instead?"
noteEditHistory: "Post edit history"

View file

@ -907,7 +907,6 @@ auto: "Automático"
themeColor: "Color de la marquesina del servidor" themeColor: "Color de la marquesina del servidor"
size: "Tamaño" size: "Tamaño"
numberOfColumn: "Cantidad de columnas" numberOfColumn: "Cantidad de columnas"
searchByGoogle: "Buscar"
instanceDefaultLightTheme: "Tema claro por defecto del servidor" instanceDefaultLightTheme: "Tema claro por defecto del servidor"
instanceDefaultDarkTheme: "Tema oscuro por defecto del servidor" instanceDefaultDarkTheme: "Tema oscuro por defecto del servidor"
instanceDefaultThemeDescription: "Ingrese el código del tema en formato objeto" instanceDefaultThemeDescription: "Ingrese el código del tema en formato objeto"
@ -1074,17 +1073,11 @@ _aboutFirefish:
source: "Código fuente" source: "Código fuente"
translation: "Traducir Firefish" translation: "Traducir Firefish"
donate: "Donar a Firefish" donate: "Donar a Firefish"
morePatrons: "También apreciamos el apoyo de muchos más que no están enlistados
aquí. ¡Gracias! 🥰"
patrons: "Mecenas de Firefish"
pleaseDonateToFirefish: Por favor considera donar a Firefish para apollar su desarrollo. pleaseDonateToFirefish: Por favor considera donar a Firefish para apollar su desarrollo.
donateHost: Dona a {host} donateHost: Dona a {host}
patronsList: Listados cronológicamente no por monto de la donación. ¡Dona con el
vínculo de arriba para que tu nombre aparezca aquí!
donateTitle: ¿Te gusta Firefish? donateTitle: ¿Te gusta Firefish?
pleaseDonateToHost: También considera donar a tu propio servidor , {host}, para pleaseDonateToHost: También considera donar a tu propio servidor , {host}, para
ayudar con los costos de operación. ayudar con los costos de operación.
sponsors: Patrocinadores de Firefish
misskeyContributors: Contribuidores de Misskey misskeyContributors: Contribuidores de Misskey
_nsfw: _nsfw:
respect: "Ocultar medios NSFW" respect: "Ocultar medios NSFW"

View file

@ -948,7 +948,6 @@ clickToFinishEmailVerification: Klikkaa [{ok}] viimeistelläksesi sähköpostiva
overridedDeviceKind: Laitetyyppi overridedDeviceKind: Laitetyyppi
tablet: Tabletti tablet: Tabletti
numberOfColumn: Sarakkeiden määrä numberOfColumn: Sarakkeiden määrä
searchByGoogle: Etsi
mutePeriod: Vaiennuksen kesto mutePeriod: Vaiennuksen kesto
indefinitely: Pysyvästi indefinitely: Pysyvästi
tenMinutes: 10 minuuttia tenMinutes: 10 minuuttia

View file

@ -910,7 +910,6 @@ auto: "Automatique"
themeColor: "Couleur du bandeau d'information du serveur" themeColor: "Couleur du bandeau d'information du serveur"
size: "Taille" size: "Taille"
numberOfColumn: "Nombre de colonnes" numberOfColumn: "Nombre de colonnes"
searchByGoogle: "Google"
instanceDefaultLightTheme: "Thème clair par défaut sur tout le serveur" instanceDefaultLightTheme: "Thème clair par défaut sur tout le serveur"
instanceDefaultDarkTheme: "Thème sombre par défaut sur tout le serveur" instanceDefaultDarkTheme: "Thème sombre par défaut sur tout le serveur"
instanceDefaultThemeDescription: "Saisissez le code du thème en format objet." instanceDefaultThemeDescription: "Saisissez le code du thème en format objet."
@ -997,18 +996,12 @@ _aboutFirefish:
source: "Code source" source: "Code source"
translation: "Traduire Firefish" translation: "Traduire Firefish"
donate: "Soutenir Firefish" donate: "Soutenir Firefish"
morePatrons: "Nous apprécions vraiment le soutien de nombreuses autres personnes
non mentionnées ici. Merci à toutes et à tous ! 🥰"
patrons: "Contributeurs"
pleaseDonateToFirefish: Merci de considérer de faire un don pour soutenir le développement pleaseDonateToFirefish: Merci de considérer de faire un don pour soutenir le développement
de Firefish. de Firefish.
sponsors: Sponsors Firefish
donateTitle: Firefish vous plaît? donateTitle: Firefish vous plaît?
pleaseDonateToHost: Également, veuillez envisager de faire un don à votre serveur pleaseDonateToHost: Également, veuillez envisager de faire un don à votre serveur
d'accueil, {host}, pour contribuer à couvrir ses frais de fonctionnement. d'accueil, {host}, pour contribuer à couvrir ses frais de fonctionnement.
donateHost: Faire un don à {host} donateHost: Faire un don à {host}
patronsList: Listé chronologiquement, pas par taille de donation. Faite un don avec
le lien ci-dessus pour avoir votre nom affiché ici !
misskeyContributors: Contributeurs Misskey misskeyContributors: Contributeurs Misskey
_nsfw: _nsfw:
respect: "Cacher les médias marqués comme contenu sensible (NSFW)" respect: "Cacher les médias marqués comme contenu sensible (NSFW)"
@ -2324,3 +2317,5 @@ markLocalFilesNsfwByDefault: Marquer tous les nouveaux fichiers locaux comme sen
markLocalFilesNsfwByDefaultDescription: Indépendamment de ce réglage, les utilisateurs markLocalFilesNsfwByDefaultDescription: Indépendamment de ce réglage, les utilisateurs
peuvent supprimer le drapeau « sensible » (NSFW) eux-mêmes. Les fichiers existants peuvent supprimer le drapeau « sensible » (NSFW) eux-mêmes. Les fichiers existants
ne sont pas affectés. ne sont pas affectés.
noteEditHistory: Historique des publications
media: Multimédia

View file

@ -901,7 +901,6 @@ auto: "Otomatis"
themeColor: "Warna Jam Server" themeColor: "Warna Jam Server"
size: "Ukuran" size: "Ukuran"
numberOfColumn: "Jumlah per kolom" numberOfColumn: "Jumlah per kolom"
searchByGoogle: "Penelusuran"
instanceDefaultLightTheme: "Tema terang bawaan ranah server" instanceDefaultLightTheme: "Tema terang bawaan ranah server"
instanceDefaultDarkTheme: "Tema gelap bawaan ranah server" instanceDefaultDarkTheme: "Tema gelap bawaan ranah server"
instanceDefaultThemeDescription: "Masukkan kode tema di format obyek." instanceDefaultThemeDescription: "Masukkan kode tema di format obyek."
@ -986,12 +985,6 @@ _aboutFirefish:
source: "Sumber kode" source: "Sumber kode"
translation: "Terjemahkan Firefish" translation: "Terjemahkan Firefish"
donate: "Donasi ke Firefish" donate: "Donasi ke Firefish"
morePatrons: "Kami sangat mengapresiasi dukungan dari banyak penolong lain yang
tidak tercantum disini. Terima kasih! 🥰"
patrons: "Pendukung"
patronsList: Diurutkan secara kronologis, bukan berdasarkan jumlah donasi. Berdonasilah
dengan tautan di atas supaya nama kamu ada di sini!
sponsors: Sponsor Firefish
donateTitle: Suka Firefish? donateTitle: Suka Firefish?
pleaseDonateToFirefish: Silakan pertimbangkan berdonasi ke Firefish untuk mendukung pleaseDonateToFirefish: Silakan pertimbangkan berdonasi ke Firefish untuk mendukung
pengembangannya. pengembangannya.
@ -2272,3 +2265,5 @@ autocorrectNoteLanguage: Tampilkan peringatan jika bahasa kiriman tidak cocok de
markLocalFilesNsfwByDefault: Tandai semua berkas lokal baru sensitif secara bawaan markLocalFilesNsfwByDefault: Tandai semua berkas lokal baru sensitif secara bawaan
markLocalFilesNsfwByDefaultDescription: Terlepas dari pengaturan ini, pengguna dapat markLocalFilesNsfwByDefaultDescription: Terlepas dari pengaturan ini, pengguna dapat
menghapus sendiri tanda NSFW. Berkas yang ada tidak berpengaruh. menghapus sendiri tanda NSFW. Berkas yang ada tidak berpengaruh.
noteEditHistory: Riwayat penyuntingan kiriman
media: Media

View file

@ -859,7 +859,6 @@ useDrawerReactionPickerForMobile: "Mostra sul drawer da dispositivo mobile"
welcomeBackWithName: "Ciao {name}" welcomeBackWithName: "Ciao {name}"
clickToFinishEmailVerification: "Fai click su [{ok}] per completare la verifica dell'indirizzo clickToFinishEmailVerification: "Fai click su [{ok}] per completare la verifica dell'indirizzo
email." email."
searchByGoogle: "Cerca"
indefinitely: "Senza scadenza" indefinitely: "Senza scadenza"
tenMinutes: "10 minuti" tenMinutes: "10 minuti"
oneHour: "1 ora" oneHour: "1 ora"
@ -935,18 +934,12 @@ _aboutFirefish:
source: "Codice sorgente" source: "Codice sorgente"
translation: "Traduzione di Firefish" translation: "Traduzione di Firefish"
donate: "Sostieni Firefish" donate: "Sostieni Firefish"
morePatrons: "Apprezziamo sinceramente l'aiuto di tante altre persone non elencate
qui. Grazie mille! 🥰"
patrons: "Sostenitori"
sponsors: Gli sponsor di Firefish
misskeyContributors: Contributori di Misskey misskeyContributors: Contributori di Misskey
donateTitle: Ti piace Firefish? donateTitle: Ti piace Firefish?
pleaseDonateToFirefish: Con una donazione puoi supportare lo sviluppo di Firefish. pleaseDonateToFirefish: Con una donazione puoi supportare lo sviluppo di Firefish.
pleaseDonateToHost: Considera anche una donazione al server che ti ospita, {host}, pleaseDonateToHost: Considera anche una donazione al server che ti ospita, {host},
per contribuire ai costi che sostiene. per contribuire ai costi che sostiene.
donateHost: Dona a {host} donateHost: Dona a {host}
patronsList: Elencati in ordine cronologico, non per importo. Dona con il link sopra
per apparire in questa lista!
_nsfw: _nsfw:
respect: "Nascondi i media sensibli (NSFW)" respect: "Nascondi i media sensibli (NSFW)"
ignore: "Mostra i media sensibili (NSFW)" ignore: "Mostra i media sensibili (NSFW)"

View file

@ -638,6 +638,7 @@ display: "表示"
copy: "コピー" copy: "コピー"
metrics: "メトリクス" metrics: "メトリクス"
overview: "概要" overview: "概要"
media: "メディア"
logs: "ログ" logs: "ログ"
delayed: "遅延" delayed: "遅延"
database: "データベース" database: "データベース"
@ -885,7 +886,6 @@ socialTimeline: "ソーシャルタイムライン"
themeColor: "テーマカラー" themeColor: "テーマカラー"
size: "サイズ" size: "サイズ"
numberOfColumn: "列の数" numberOfColumn: "列の数"
searchByGoogle: "検索"
instanceDefaultLightTheme: "サーバーの標準ライトテーマ" instanceDefaultLightTheme: "サーバーの標準ライトテーマ"
instanceDefaultDarkTheme: "サーバーの標準ダークテーマ" instanceDefaultDarkTheme: "サーバーの標準ダークテーマ"
instanceDefaultThemeDescription: "オブジェクト形式のテーマコードを記入します。" instanceDefaultThemeDescription: "オブジェクト形式のテーマコードを記入します。"
@ -1011,11 +1011,11 @@ searchWordsDescription: "投稿を検索するには、ここに検索語句を
「(朝 OR 夜) 眠い」のように、AND検索とOR検索を同時に行うこともできます。\n空白を含む文字列をAND検索ではなくそのまま検索したい場合、\"明日 買うもの\"\ 「(朝 OR 夜) 眠い」のように、AND検索とOR検索を同時に行うこともできます。\n空白を含む文字列をAND検索ではなくそのまま検索したい場合、\"明日 買うもの\"\
\ のように二重引用符 (\") で囲む必要があります。\n\n特定のユーザーや投稿のページに飛びたい場合には、この欄にID (@user@example.com) \ のように二重引用符 (\") で囲む必要があります。\n\n特定のユーザーや投稿のページに飛びたい場合には、この欄にID (@user@example.com)
や投稿のURLを入力し「照会」を押してください。「検索」を押すとそのIDやURLが文字通り含まれる投稿を検索します。" や投稿のURLを入力し「照会」を押してください。「検索」を押すとそのIDやURLが文字通り含まれる投稿を検索します。"
searchUsers: "投稿元(オプション" searchUsers: "投稿元(省略可"
searchUsersDescription: "投稿検索で投稿者を絞りたい場合、@user@example.comローカルユーザーなら @userの形式で投稿者のIDを入力してください。ユーザーIDではなくドメイン名 searchUsersDescription: "投稿検索で投稿者を絞りたい場合、@user@example.comローカルユーザーなら @userの形式で投稿者のIDを入力してください。ユーザーIDではなくドメイン名
(example.com) を指定すると、そのサーバーの投稿を検索します。\n\nme とだけ入力すると、自分の投稿を検索します。この検索結果には未収載・フォロワー限定・ダイレクト・秘密を含む全ての投稿が含まれます。\n (example.com) を指定すると、そのサーバーの投稿を検索します。\n\nme とだけ入力すると、自分の投稿を検索します。この検索結果には未収載・フォロワー限定・ダイレクト・秘密を含む全ての投稿が含まれます。\n
\nlocal とだけ入力すると、ローカルサーバーの投稿を検索します。" \nlocal とだけ入力すると、ローカルサーバーの投稿を検索します。"
searchRange: "投稿期間(オプション" searchRange: "投稿期間(省略可"
searchRangeDescription: "投稿検索で投稿期間を絞りたい場合、20220615-20231031 のような形式で投稿期間を入力してください。今年の日付を指定する場合には年の指定を省略できます0105-0106 searchRangeDescription: "投稿検索で投稿期間を絞りたい場合、20220615-20231031 のような形式で投稿期間を入力してください。今年の日付を指定する場合には年の指定を省略できます0105-0106
や 20231105-0110 のように)。\n\n開始日と終了日のどちらか一方は省略可能です。例えば -0102 とすると今年1月2日までの投稿のみを、20231026- や 20231105-0110 のように)。\n\n開始日と終了日のどちらか一方は省略可能です。例えば -0102 とすると今年1月2日までの投稿のみを、20231026-
とすると2023年10月26日以降の投稿のみを検索します。" とすると2023年10月26日以降の投稿のみを検索します。"
@ -1109,14 +1109,10 @@ _aboutFirefish:
source: "ソースコード" source: "ソースコード"
translation: "Firefishを翻訳" translation: "Firefishを翻訳"
donate: "Firefishに寄付" donate: "Firefishに寄付"
morePatrons: "他にも多くの方が支援してくれています。ありがとうございます! 🥰"
patrons: "支援者"
patronsList: 寄付額ではなく時系列順に並んでいます。上記のリンクから寄付を行ってここにあなたのIDを載せましょう
pleaseDonateToFirefish: Firefish開発への寄付をご検討ください。 pleaseDonateToFirefish: Firefish開発への寄付をご検討ください。
pleaseDonateToHost: また、このサーバー {host} の運営者への寄付もご検討ください。 pleaseDonateToHost: また、このサーバー {host} の運営者への寄付もご検討ください。
donateHost: '{host} に寄付する' donateHost: '{host} に寄付する'
donateTitle: Firefishを気に入りましたか donateTitle: Firefishを気に入りましたか
sponsors: Firefish の支援者
_nsfw: _nsfw:
respect: "閲覧注意のメディアは隠す" respect: "閲覧注意のメディアは隠す"
ignore: "閲覧注意のメディアを隠さない" ignore: "閲覧注意のメディアを隠さない"
@ -2060,3 +2056,4 @@ autocorrectNoteLanguage: 設定した投稿言語が自動検出されたもの
incorrectLanguageWarning: "この投稿は{detected}で書かれていると判定されました。\n投稿言語を{current}ではなく{detected}にしますか?" incorrectLanguageWarning: "この投稿は{detected}で書かれていると判定されました。\n投稿言語を{current}ではなく{detected}にしますか?"
markLocalFilesNsfwByDefault: このサーバーの全てのファイルをデフォルトでNSFWに設定する markLocalFilesNsfwByDefault: このサーバーの全てのファイルをデフォルトでNSFWに設定する
markLocalFilesNsfwByDefaultDescription: この設定が有効でも、ユーザーは自分でNSFWのフラグを外すことができます。また、この設定は既存のファイルには影響しません。 markLocalFilesNsfwByDefaultDescription: この設定が有効でも、ユーザーは自分でNSFWのフラグを外すことができます。また、この設定は既存のファイルには影響しません。
noteEditHistory: 編集履歴

View file

@ -803,7 +803,6 @@ unresolved: "まだ解決してないで"
breakFollow: "フォロワーを解除するで" breakFollow: "フォロワーを解除するで"
itsOn: "オンになっとるよ" itsOn: "オンになっとるよ"
hide: "隠す" hide: "隠す"
searchByGoogle: "探す"
indefinitely: "無期限" indefinitely: "無期限"
file: "ファイル" file: "ファイル"
requireAdminForView: "これを見るには管理者アカウントでログインしとらなあかんで。" requireAdminForView: "これを見るには管理者アカウントでログインしとらなあかんで。"
@ -875,8 +874,6 @@ _aboutFirefish:
source: "ソースコード" source: "ソースコード"
translation: "Firefishを翻訳" translation: "Firefishを翻訳"
donate: "Firefishに寄付" donate: "Firefishに寄付"
morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
patrons: "支援者"
misskeyContributors: フォーク元のMisskeyを作らはった人ら misskeyContributors: フォーク元のMisskeyを作らはった人ら
_mfm: _mfm:
cheatSheet: "MFMチートシート" cheatSheet: "MFMチートシート"

View file

@ -54,7 +54,6 @@ accountInfo: "Talɣut n umiḍan"
emailNotification: "Ilɣa imayl" emailNotification: "Ilɣa imayl"
selectAccount: "Fren amiḍan" selectAccount: "Fren amiḍan"
accounts: "Imiḍan" accounts: "Imiḍan"
searchByGoogle: "Nadi"
file: "Ifuyla" file: "Ifuyla"
account: "Imiḍan" account: "Imiḍan"
_email: _email:

View file

@ -59,7 +59,6 @@ remove: "ಅಳಿಸು"
smtpUser: "ಬಳಕೆಹೆಸರು" smtpUser: "ಬಳಕೆಹೆಸರು"
smtpPass: "ಗುಪ್ತಪದ" smtpPass: "ಗುಪ್ತಪದ"
user: "ಬಳಕೆದಾರ" user: "ಬಳಕೆದಾರ"
searchByGoogle: "ಹುಡುಕು"
file: "ಕಡತಗಳು" file: "ಕಡತಗಳು"
_email: _email:
_follow: _follow:

View file

@ -851,7 +851,6 @@ auto: "자동"
themeColor: "테마 컬러" themeColor: "테마 컬러"
size: "크기" size: "크기"
numberOfColumn: "한 줄에 보일 리액션의 수" numberOfColumn: "한 줄에 보일 리액션의 수"
searchByGoogle: "검색"
instanceDefaultLightTheme: "서버 기본 라이트 테마" instanceDefaultLightTheme: "서버 기본 라이트 테마"
instanceDefaultDarkTheme: "서버 기본 다크 테마" instanceDefaultDarkTheme: "서버 기본 다크 테마"
instanceDefaultThemeDescription: "객체 형식의 테마 코드를 입력해 주세요." instanceDefaultThemeDescription: "객체 형식의 테마 코드를 입력해 주세요."
@ -993,10 +992,6 @@ _aboutFirefish:
source: "소스 코드" source: "소스 코드"
translation: "Firefish를 번역하기" translation: "Firefish를 번역하기"
donate: "Firefish에 기부하기" donate: "Firefish에 기부하기"
morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰"
patrons: "후원자"
patronsList: 기부 금액이 아닌 시간 순서로 정렬합니다. 위 링크를 통해 후원하여 당신의 이름을 새겨 보세요!
sponsors: Firefish 스폰서
pleaseDonateToHost: 또한, 이 서버 {host} 의 운영자에게 기부하는 것도 검토하여 주십시오. pleaseDonateToHost: 또한, 이 서버 {host} 의 운영자에게 기부하는 것도 검토하여 주십시오.
pleaseDonateToFirefish: Firefish의 개발에 후원하는 것을 검토하여 주십시오. pleaseDonateToFirefish: Firefish의 개발에 후원하는 것을 검토하여 주십시오.
donateHost: '{host} 에게 기부하기' donateHost: '{host} 에게 기부하기'

View file

@ -326,7 +326,6 @@ user: "Gebruikers"
muteThread: "Discussies dempen " muteThread: "Discussies dempen "
unmuteThread: "Dempen van discussie ongedaan maken" unmuteThread: "Dempen van discussie ongedaan maken"
hide: "Verbergen" hide: "Verbergen"
searchByGoogle: "Zoeken"
cropImage: "Afbeelding bijsnijden" cropImage: "Afbeelding bijsnijden"
cropImageAsk: "Bijsnijdengevraagd" cropImageAsk: "Bijsnijdengevraagd"
file: "Bestanden" file: "Bestanden"

View file

@ -902,7 +902,6 @@ swipeOnDesktop: Tillat mobil-lignende sveiping på skrivebords-PC
migration: Migrering migration: Migrering
useDrawerReactionPickerForMobile: Vis reaksjosnvelger som en skuff på mobil useDrawerReactionPickerForMobile: Vis reaksjosnvelger som en skuff på mobil
numberOfColumn: Antall kolonner numberOfColumn: Antall kolonner
searchByGoogle: Søk
oneWeek: En uke oneWeek: En uke
file: Fil file: Fil
recentNHours: Siste {n} timer recentNHours: Siste {n} timer
@ -988,8 +987,6 @@ _aboutFirefish:
pleaseDonateToFirefish: Du kan vurdere å donere en slant til Firefish for å støtte pleaseDonateToFirefish: Du kan vurdere å donere en slant til Firefish for å støtte
videre utvikling og feilretting. videre utvikling og feilretting.
donateHost: Donér til {host} donateHost: Donér til {host}
morePatrons: Vi er også takknemlige for bidragene fra mange andre som ikke er listet
her. Takk til dere alle! 🥰
contributors: Hovedutviklere contributors: Hovedutviklere
source: Kildekode source: Kildekode
allContributors: Alle bidragsytere allContributors: Alle bidragsytere
@ -997,10 +994,6 @@ _aboutFirefish:
pleaseDonateToHost: Du kan også vurdere å donere til hjemme-tjeneren din, {host}, pleaseDonateToHost: Du kan også vurdere å donere til hjemme-tjeneren din, {host},
for å hjelpe dem med driftskostnadene for tjenesten. for å hjelpe dem med driftskostnadene for tjenesten.
about: Firefish ble opprettet av ThatOneCalculator i 2022, basert på Misskey. about: Firefish ble opprettet av ThatOneCalculator i 2022, basert på Misskey.
sponsors: Firefishs sponsorer
patrons: Firefishs patroner
patronsList: Listen er kronologisk, ikke etter donert beløp. Doner med lenken over
for å få navnet ditt her!
isBot: Denne kontoen er en bot isBot: Denne kontoen er en bot
_nsfw: _nsfw:
respect: Skjul NSFW-merket media respect: Skjul NSFW-merket media

View file

@ -867,7 +867,6 @@ tablet: "Tablet"
auto: "Automatycznie" auto: "Automatycznie"
size: "Rozmiar" size: "Rozmiar"
numberOfColumn: "Liczba kolumn" numberOfColumn: "Liczba kolumn"
searchByGoogle: "Szukaj"
indefinitely: "Dożywotnio" indefinitely: "Dożywotnio"
file: "Pliki" file: "Pliki"
logoutConfirm: "Czy na pewno chcesz się wylogować?" logoutConfirm: "Czy na pewno chcesz się wylogować?"
@ -991,9 +990,6 @@ _aboutFirefish:
source: "Kod źródłowy" source: "Kod źródłowy"
translation: "Tłumacz Firefish" translation: "Tłumacz Firefish"
donate: "Przekaż darowiznę na Firefish" donate: "Przekaż darowiznę na Firefish"
morePatrons: "Naprawdę doceniam wsparcie ze strony wielu niewymienionych tu osób.
Dziękuję! 🥰"
patrons: "Wspierający"
_nsfw: _nsfw:
respect: "Ukrywaj media NSFW" respect: "Ukrywaj media NSFW"
ignore: "Nie ukrywaj mediów NSFW" ignore: "Nie ukrywaj mediów NSFW"

View file

@ -497,7 +497,6 @@ smtpPass: "Senha"
clearCache: "Limpar memória transitória" clearCache: "Limpar memória transitória"
info: "Informações" info: "Informações"
user: "Usuários" user: "Usuários"
searchByGoogle: "Buscar"
file: "Ficheiros" file: "Ficheiros"
_email: _email:
_follow: _follow:

View file

@ -692,7 +692,6 @@ user: "Utilizatori"
administration: "Gestionare" administration: "Gestionare"
middle: "Mediu" middle: "Mediu"
sent: "Trimite" sent: "Trimite"
searchByGoogle: "Caută"
file: "Fișiere" file: "Fișiere"
_email: _email:
_follow: _follow:

View file

@ -894,7 +894,6 @@ auto: "Автоматически"
themeColor: "Цвет темы сервера" themeColor: "Цвет темы сервера"
size: "Размер" size: "Размер"
numberOfColumn: "Количество столбцов" numberOfColumn: "Количество столбцов"
searchByGoogle: "Поиск"
instanceDefaultLightTheme: "Светлая тема по умолчанию для всего сервера" instanceDefaultLightTheme: "Светлая тема по умолчанию для всего сервера"
instanceDefaultDarkTheme: "Темная тема по умолчанию для всего сервера" instanceDefaultDarkTheme: "Темная тема по умолчанию для всего сервера"
indefinitely: "вечно" indefinitely: "вечно"
@ -987,12 +986,6 @@ _aboutFirefish:
source: "Исходный код" source: "Исходный код"
translation: "Перевод Firefish" translation: "Перевод Firefish"
donate: "Пожертвование на Firefish" donate: "Пожертвование на Firefish"
morePatrons: "Большое спасибо и многим другим, кто принял участие в этом проекте!
🥰"
patrons: "Материальная поддержка"
patronsList: Перечислены в хронологическом порядке, а не по размеру пожертвования.
Сделайте взнос по ссылке выше, чтобы ваше имя было здесь!
sponsors: Спонсоры Firefish
donateTitle: Понравился Firefish? donateTitle: Понравился Firefish?
pleaseDonateToFirefish: Пожалуйста, поддержите разработку Firefish. pleaseDonateToFirefish: Пожалуйста, поддержите разработку Firefish.
pleaseDonateToHost: Также не забудьте поддержать ваш домашний сервер {host}, чтобы pleaseDonateToHost: Также не забудьте поддержать ваш домашний сервер {host}, чтобы

View file

@ -886,7 +886,6 @@ auto: "Automaticky"
themeColor: "Farba témy" themeColor: "Farba témy"
size: "Veľkosť" size: "Veľkosť"
numberOfColumn: "Počet stĺpcov" numberOfColumn: "Počet stĺpcov"
searchByGoogle: "Hľadať cez Google"
instanceDefaultLightTheme: "Predvolená svetlá téma" instanceDefaultLightTheme: "Predvolená svetlá téma"
instanceDefaultDarkTheme: "Predvolená tmavá téma" instanceDefaultDarkTheme: "Predvolená tmavá téma"
instanceDefaultThemeDescription: "Vložte kód témy v objektovom formáte" instanceDefaultThemeDescription: "Vložte kód témy v objektovom formáte"
@ -1037,9 +1036,6 @@ _aboutFirefish:
source: "Zdrojový kód" source: "Zdrojový kód"
translation: "Preložiť Firefish" translation: "Preložiť Firefish"
donate: "Podporiť Firefish" donate: "Podporiť Firefish"
morePatrons: "Takisto oceňujeme podporu mnoých ďalších, ktorí tu nie sú uvedení.
Ďakujeme! 🥰"
patrons: "Prispievatelia"
_nsfw: _nsfw:
respect: "Skryť NSFW médiá" respect: "Skryť NSFW médiá"
ignore: "Neskrývať NSFW médiá" ignore: "Neskrývať NSFW médiá"

View file

@ -268,7 +268,6 @@ smtpUser: "Användarnamn"
smtpPass: "Lösenord" smtpPass: "Lösenord"
clearCache: "Rensa cache" clearCache: "Rensa cache"
user: "Användare" user: "Användare"
searchByGoogle: "Sök"
file: "Filer" file: "Filer"
_email: _email:
_follow: _follow:

View file

@ -873,7 +873,6 @@ auto: "อัตโนมัติ"
themeColor: "สีข้อความเลื่อนของเซิร์ฟเวอร์" themeColor: "สีข้อความเลื่อนของเซิร์ฟเวอร์"
size: "ขนาด" size: "ขนาด"
numberOfColumn: "จำนวนคอลัมน์" numberOfColumn: "จำนวนคอลัมน์"
searchByGoogle: "ค้นหา"
instanceDefaultLightTheme: "ธีมสว่างค่าเริ่มต้นของเซิร์ฟเวอร์" instanceDefaultLightTheme: "ธีมสว่างค่าเริ่มต้นของเซิร์ฟเวอร์"
instanceDefaultDarkTheme: "ธีมมืดค่าเริ่มต้นของเซิร์ฟเวอร์" instanceDefaultDarkTheme: "ธีมมืดค่าเริ่มต้นของเซิร์ฟเวอร์"
instanceDefaultThemeDescription: "ป้อนรหัสธีมในรูปแบบออบเจ็กต์" instanceDefaultThemeDescription: "ป้อนรหัสธีมในรูปแบบออบเจ็กต์"
@ -1023,9 +1022,6 @@ _aboutFirefish:
source: "ซอร์สโค้ด" source: "ซอร์สโค้ด"
translation: "รับแปลภาษา Firefish" translation: "รับแปลภาษา Firefish"
donate: "บริจาคให้กับ Firefish" donate: "บริจาคให้กับ Firefish"
morePatrons: "เราขอขอบคุณสำหรับความช่วยเหลือจากผู้ช่วยอื่นๆ ที่ไม่ได้ระบุไว้ที่นี่นะ
ขอขอบคุณ! 🥰"
patrons: "สมาชิกพันธมิตร"
_nsfw: _nsfw:
respect: "ซ่อนสื่อ NSFW" respect: "ซ่อนสื่อ NSFW"
ignore: "อย่าซ่อนสื่อ NSFW" ignore: "อย่าซ่อนสื่อ NSFW"

View file

@ -48,7 +48,6 @@ remove: "Sil"
smtpUser: "Kullanıcı Adı" smtpUser: "Kullanıcı Adı"
smtpPass: "Şifre" smtpPass: "Şifre"
user: "Kullanıcı" user: "Kullanıcı"
searchByGoogle: "Arama"
_mfm: _mfm:
search: "Arama" search: "Arama"
play: MFM'i çal play: MFM'i çal
@ -1911,14 +1910,9 @@ _preferencesBackups:
updatedAt: 'Güncelleme tarihi: {date} {time}' updatedAt: 'Güncelleme tarihi: {date} {time}'
cannotLoad: Yüklenemedi cannotLoad: Yüklenemedi
_aboutFirefish: _aboutFirefish:
patronsList: Bağış büyüklüğüne göre değil, kronolojik olarak listelenmiştir. Adınızı
buraya almak için yukarıdaki bağlantıyla bağış yapın!
about: Firefish, 2022'den beri geliştirilmekte olan ThatOneCalculator tarafından about: Firefish, 2022'den beri geliştirilmekte olan ThatOneCalculator tarafından
yapılan bir Misskey çatalıdır. yapılan bir Misskey çatalıdır.
allContributors: Tüm katkıda bulunanlar allContributors: Tüm katkıda bulunanlar
patrons: Firefish patronları
morePatrons: Burada listelenmeyen diğer birçok yardımcının desteğini de takdir ediyoruz.
Teşekkür ederim! 🥰
donate: Firefish'e bağışta bulunun donate: Firefish'e bağışta bulunun
contributors: Ana katkıda bulunanlar contributors: Ana katkıda bulunanlar
source: Kaynak Kodu source: Kaynak Kodu
@ -1929,7 +1923,6 @@ _aboutFirefish:
pleaseDonateToHost: İşletme maliyetlerini desteklemek için lütfen ev sunucunuz {host}'a pleaseDonateToHost: İşletme maliyetlerini desteklemek için lütfen ev sunucunuz {host}'a
bağış yapmayı da düşünün. bağış yapmayı da düşünün.
donateHost: '{ev sahibi} için bağış yapın' donateHost: '{ev sahibi} için bağış yapın'
sponsors: Firefish sponsorları
misskeyContributors: Misskey'e katkıda bulunanlar misskeyContributors: Misskey'e katkıda bulunanlar
_weekday: _weekday:
saturday: Cumartesi saturday: Cumartesi

View file

@ -1,6 +1,5 @@
--- ---
_lang_: "ياپونچە" _lang_: "ياپونچە"
search: "ئىزدەش" search: "ئىزدەش"
searchByGoogle: "ئىزدەش"
_mfm: _mfm:
search: "ئىزدەش" search: "ئىزدەش"

View file

@ -788,7 +788,6 @@ global: "Глобальна"
sent: "Відправлене" sent: "Відправлене"
hashtags: "Хештеґ" hashtags: "Хештеґ"
hide: "Сховати" hide: "Сховати"
searchByGoogle: "Пошук"
indefinitely: "Ніколи" indefinitely: "Ніколи"
file: "Файли" file: "Файли"
reverse: "Переворот" reverse: "Переворот"
@ -826,17 +825,11 @@ _aboutFirefish:
source: "Вихідний код" source: "Вихідний код"
translation: "Перекладати Firefish" translation: "Перекладати Firefish"
donate: "Пожертвувати Firefish" donate: "Пожертвувати Firefish"
morePatrons: "Ми дуже цінуємо підтримку багатьох інших помічників, не перелічених
тут. Дякуємо! 🥰"
patrons: "Підтримали"
patronsList: Перераховані в хронологічному порядку, а не за розміром пожертви. Зробіть
внесок за посиланням вище, щоб ваше ім'я було тут!
donateTitle: Сподобався Firefish? donateTitle: Сподобався Firefish?
pleaseDonateToFirefish: Будь ласка, підтримайте розробку Firefish. pleaseDonateToFirefish: Будь ласка, підтримайте розробку Firefish.
pleaseDonateToHost: Також не забудьте підтримати ваш домашній сервер {host}, щоб pleaseDonateToHost: Також не забудьте підтримати ваш домашній сервер {host}, щоб
допомогти з його операційними витратами. допомогти з його операційними витратами.
donateHost: Зробити внесок на рахунок {host} donateHost: Зробити внесок на рахунок {host}
sponsors: Спонсори Firefish
misskeyContributors: Контрибутори Misskey misskeyContributors: Контрибутори Misskey
_nsfw: _nsfw:
respect: "Приховувати NSFW медіа" respect: "Приховувати NSFW медіа"

View file

@ -892,7 +892,6 @@ auto: "Tự động"
themeColor: "Màu theme" themeColor: "Màu theme"
size: "Kích thước" size: "Kích thước"
numberOfColumn: "Số lượng cột" numberOfColumn: "Số lượng cột"
searchByGoogle: "Google"
instanceDefaultLightTheme: "Theme máy chủ Sáng-Rộng" instanceDefaultLightTheme: "Theme máy chủ Sáng-Rộng"
instanceDefaultDarkTheme: "Theme máy chủ Tối-Rộng" instanceDefaultDarkTheme: "Theme máy chủ Tối-Rộng"
instanceDefaultThemeDescription: "Nhập mã theme trong định dạng đối tượng." instanceDefaultThemeDescription: "Nhập mã theme trong định dạng đối tượng."
@ -1051,15 +1050,10 @@ _aboutFirefish:
source: "Mã nguồn" source: "Mã nguồn"
translation: "Dịch Firefish" translation: "Dịch Firefish"
donate: "Ủng hộ Firefish" donate: "Ủng hộ Firefish"
morePatrons: "Chúng tôi cũng trân trọng sự hỗ trợ của nhiều người đóng góp khác
không được liệt kê ở đây. Cảm ơn! 🥰"
patrons: "Người ủng hộ"
patronsList: Liệt kê theo thứ tự, không theo số tiền ủng hộ. Hãy để tên bạn ở đây!
donateTitle: Thích Firefish? donateTitle: Thích Firefish?
pleaseDonateToFirefish: Hãy cân nhắc ủng hộ Firefish phát triển. pleaseDonateToFirefish: Hãy cân nhắc ủng hộ Firefish phát triển.
donateHost: Ủng hộ {host} donateHost: Ủng hộ {host}
pleaseDonateToHost: Cũng như ủng hộ chi phí vận hành máy chủ {host} của bạn. pleaseDonateToHost: Cũng như ủng hộ chi phí vận hành máy chủ {host} của bạn.
sponsors: Nhà tài trợ Firefish
misskeyContributors: Người đóng góp Misskey misskeyContributors: Người đóng góp Misskey
_nsfw: _nsfw:
respect: "Ẩn nội dung NSFW" respect: "Ẩn nội dung NSFW"

View file

@ -269,7 +269,7 @@ agreeTo: "我同意 {0}"
tos: "服务条款" tos: "服务条款"
start: "开始" start: "开始"
home: "首页" home: "首页"
remoteUserCaution: "由于此用户来自其它服务器,显示信息不完整。" remoteUserCaution: "此用户来自其它服务器,显示信息不完整。"
activity: "活动" activity: "活动"
images: "图片" images: "图片"
birthday: "生日" birthday: "生日"
@ -340,6 +340,7 @@ invite: "邀请"
driveCapacityPerLocalAccount: "每个本地用户的网盘容量" driveCapacityPerLocalAccount: "每个本地用户的网盘容量"
driveCapacityPerRemoteAccount: "每个远程用户的网盘容量" driveCapacityPerRemoteAccount: "每个远程用户的网盘容量"
inMb: "以兆字节 (MegaByte) 为单位" inMb: "以兆字节 (MegaByte) 为单位"
antennaLimit: "每个用户最多可以创建的天线数量"
iconUrl: "图标 URL" iconUrl: "图标 URL"
bannerUrl: "横幅图 URL" bannerUrl: "横幅图 URL"
backgroundImageUrl: "背景图 URL" backgroundImageUrl: "背景图 URL"
@ -851,7 +852,6 @@ auto: "自动"
themeColor: "服务器滚动条颜色" themeColor: "服务器滚动条颜色"
size: "大小" size: "大小"
numberOfColumn: "列数" numberOfColumn: "列数"
searchByGoogle: "搜索"
instanceDefaultLightTheme: "服务器默认浅色主题" instanceDefaultLightTheme: "服务器默认浅色主题"
instanceDefaultDarkTheme: "服务器默认深色主题" instanceDefaultDarkTheme: "服务器默认深色主题"
instanceDefaultThemeDescription: "以对象格式键入主题代码。" instanceDefaultThemeDescription: "以对象格式键入主题代码。"
@ -996,10 +996,6 @@ _aboutFirefish:
source: "源代码" source: "源代码"
translation: "翻译 Firefish" translation: "翻译 Firefish"
donate: "赞助 Firefish" donate: "赞助 Firefish"
morePatrons: "还有很多其它的人也在支持我们,非常感谢🥰"
patrons: "Firefish 赞助者"
patronsList: 按时间顺序而不是捐赠金额排列。通过上面的链接捐款,让您的名字出现在这里!
sponsors: Firefish 赞助者们
donateTitle: 喜欢 Firefish 吗? donateTitle: 喜欢 Firefish 吗?
pleaseDonateToFirefish: 请考虑赞助 Firefish 以支持其开发。 pleaseDonateToFirefish: 请考虑赞助 Firefish 以支持其开发。
pleaseDonateToHost: 也请考虑赞助您的主服务器 {host},以帮助支持其运营成本。 pleaseDonateToHost: 也请考虑赞助您的主服务器 {host},以帮助支持其运营成本。
@ -2061,3 +2057,5 @@ showNoAltTextWarning: 当您尝试发布没有描述的帖子附件时显示警
showAddFileDescriptionAtFirstPost: 当您首次尝试发布没有描述的帖子附件时自动弹出添加描述页面 showAddFileDescriptionAtFirstPost: 当您首次尝试发布没有描述的帖子附件时自动弹出添加描述页面
autocorrectNoteLanguage: 当帖子语言不符合自动检测的结果的时候显示警告 autocorrectNoteLanguage: 当帖子语言不符合自动检测的结果的时候显示警告
incorrectLanguageWarning: "看上去您帖子使用的语言是{detected},但您选择的语言是{current}。\n要改为以{detected}发帖吗?" incorrectLanguageWarning: "看上去您帖子使用的语言是{detected},但您选择的语言是{current}。\n要改为以{detected}发帖吗?"
noteEditHistory: "帖子编辑历史"
media: 媒体

View file

@ -847,7 +847,6 @@ auto: "自動"
themeColor: "主題顏色" themeColor: "主題顏色"
size: "大小" size: "大小"
numberOfColumn: "列數" numberOfColumn: "列數"
searchByGoogle: "搜尋"
instanceDefaultLightTheme: "伺服器預設的淺色主題" instanceDefaultLightTheme: "伺服器預設的淺色主題"
instanceDefaultDarkTheme: "伺服器預設的深色主題" instanceDefaultDarkTheme: "伺服器預設的深色主題"
instanceDefaultThemeDescription: "輸入物件形式的主題代碼。" instanceDefaultThemeDescription: "輸入物件形式的主題代碼。"
@ -992,10 +991,6 @@ _aboutFirefish:
source: "原始碼" source: "原始碼"
translation: "翻譯Firefish" translation: "翻譯Firefish"
donate: "贊助Firefish" donate: "贊助Firefish"
morePatrons: "還有許許多多幫助我們的其他人,非常感謝你們。 🥰"
patrons: "贊助者"
patronsList: 按時間順序列出,而不是按贊助規模列出。使用上面的連結贊助,在這裡獲得顯示您名字的機會!
sponsors: Firefish 贊助者們
donateTitle: 覺得 Firefish 棒嗎? donateTitle: 覺得 Firefish 棒嗎?
pleaseDonateToFirefish: 請考慮向 Firefish 贊助以支持其發展。 pleaseDonateToFirefish: 請考慮向 Firefish 贊助以支持其發展。
pleaseDonateToHost: 還請考慮捐贈給您在使用的伺服器 {host},以支援龐大的運營成本。 pleaseDonateToHost: 還請考慮捐贈給您在使用的伺服器 {host},以支援龐大的運營成本。

View file

@ -1,11 +1,11 @@
{ {
"name": "firefish", "name": "firefish",
"version": "20240330", "version": "20240421",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://firefish.dev/firefish/firefish.git" "url": "https://firefish.dev/firefish/firefish.git"
}, },
"packageManager": "pnpm@8.15.5", "packageManager": "pnpm@8.15.7",
"private": true, "private": true,
"scripts": { "scripts": {
"rebuild": "pnpm run clean && pnpm run build", "rebuild": "pnpm run clean && pnpm run build",
@ -20,33 +20,39 @@
"watch": "pnpm run dev", "watch": "pnpm run dev",
"dev": "pnpm node ./scripts/dev.mjs", "dev": "pnpm node ./scripts/dev.mjs",
"dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start", "dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start",
"lint": "pnpm --filter !megalodon --filter !firefish-js -r --parallel run lint", "lint": "pnpm run lint:ts; pnpm run lint:rs",
"lint:ts": "pnpm --filter !firefish-js -r --parallel run lint",
"lint:rs": "cargo clippy --fix --allow-dirty --allow-staged && cargo fmt --all --",
"debug": "pnpm run build:debug && pnpm run start", "debug": "pnpm run build:debug && pnpm run start",
"build:debug": "pnpm run clean && pnpm node ./scripts/dev-build.mjs && pnpm run gulp", "build:debug": "pnpm run clean && pnpm node ./scripts/dev-build.mjs && pnpm run gulp",
"mocha": "pnpm --filter backend run mocha", "mocha": "pnpm --filter backend run mocha",
"test": "pnpm run mocha", "test": "pnpm run test:ts && pnpm run test:rs",
"format": "pnpm -r --parallel run format", "test:ts": "pnpm run mocha",
"test:rs": "cargo test",
"format": "pnpm run format:ts; pnpm run format:rs",
"format:ts": "pnpm -r --parallel run format",
"format:rs": "cargo fmt --all --",
"clean": "pnpm node ./scripts/clean-built.mjs", "clean": "pnpm node ./scripts/clean-built.mjs",
"clean-npm": "pnpm node ./scripts/clean-npm.mjs", "clean-npm": "pnpm node ./scripts/clean-npm.mjs",
"clean-cargo": "pnpm node ./scripts/clean-cargo.mjs", "clean-cargo": "cargo clean",
"clean-all": "pnpm run clean && pnpm run clean-cargo && pnpm run clean-npm" "clean-all": "pnpm run clean && pnpm run clean-cargo && pnpm run clean-npm"
}, },
"dependencies": { "dependencies": {
"js-yaml": "4.1.0",
"gulp": "4.0.2", "gulp": "4.0.2",
"gulp-cssnano": "2.1.3", "gulp-cssnano": "2.1.3",
"gulp-replace": "1.1.4", "gulp-replace": "1.1.4",
"gulp-terser": "2.1.0" "gulp-terser": "2.1.0",
"js-yaml": "4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.6.3", "@biomejs/biome": "1.6.4",
"@biomejs/cli-darwin-arm64": "^1.6.3", "@biomejs/cli-darwin-arm64": "^1.6.4",
"@biomejs/cli-darwin-x64": "^1.6.3", "@biomejs/cli-darwin-x64": "^1.6.4",
"@biomejs/cli-linux-arm64": "^1.6.3", "@biomejs/cli-linux-arm64": "^1.6.4",
"@biomejs/cli-linux-x64": "^1.6.3", "@biomejs/cli-linux-x64": "^1.6.4",
"@types/node": "20.11.30", "@types/node": "20.12.7",
"execa": "8.0.1", "execa": "8.0.1",
"pnpm": "8.15.5", "pnpm": "8.15.7",
"typescript": "5.4.3" "typescript": "5.4.5"
} }
} }

View file

@ -4,6 +4,7 @@ This directory contains all of the packages Firefish uses.
- `backend`: Main backend code written in TypeScript for NodeJS - `backend`: Main backend code written in TypeScript for NodeJS
- `backend-rs`: Backend code written in Rust, bound to NodeJS by [NAPI-RS](https://napi.rs/) - `backend-rs`: Backend code written in Rust, bound to NodeJS by [NAPI-RS](https://napi.rs/)
- `macro-rs`: Procedural macros for backend-rs
- `client`: Web interface written in Vue3 and TypeScript - `client`: Web interface written in Vue3 and TypeScript
- `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript - `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript
- `firefish-js`: TypeScript SDK for both backend and client - `firefish-js`: TypeScript SDK for both backend and client

View file

@ -12,31 +12,37 @@ napi = ["dep:napi", "dep:napi-derive"]
crate-type = ["cdylib", "lib"] crate-type = ["cdylib", "lib"]
[dependencies] [dependencies]
async-trait = "0.1.79" macro_rs = { workspace = true }
cfg-if = "1.0.0"
chrono = "0.4.35"
cuid2 = "0.1.2"
jsonschema = "0.17.1"
once_cell = "1.19.0"
parse-display = "0.8.2"
rand = "0.8.5"
schemars = { version = "0.8.16", features = ["chrono"] }
sea-orm = { version = "0.12.15", features = ["sqlx-postgres", "runtime-tokio-rustls"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"
thiserror = "1.0.58"
tokio = { version = "1.36.0", features = ["full"] }
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix napi = { workspace = true, optional = true, default-features = false, features = ["napi9", "tokio_rt", "chrono_date", "serde-json"] }
napi = { version = "2.16.1", default-features = false, features = ["napi9", "tokio_rt"], optional = true } napi-derive = { workspace = true, optional = true }
napi-derive = { version = "2.16.1", optional = true }
basen = "0.1.0" argon2 = { workspace = true, features = ["std"] }
async-trait = { workspace = true }
basen = { workspace = true }
bcrypt = { workspace = true }
cfg-if = { workspace = true }
chrono = { workspace = true }
cuid2 = { workspace = true }
emojis = { workspace = true }
idna = { workspace = true }
jsonschema = { workspace = true }
once_cell = { workspace = true }
parse-display = { workspace = true }
rand = { workspace = true }
regex = { workspace = true }
schemars = { workspace = true, features = ["chrono"] }
sea-orm = { workspace = true, features = ["sqlx-postgres", "runtime-tokio-rustls"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["full"] }
url = { workspace = true }
urlencoding = { workspace = true }
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1.4.0" pretty_assertions = { workspace = true }
[build-dependencies] [build-dependencies]
napi-build = "2.1.2" napi-build = { workspace = true }
[profile.release]
lto = true

View file

@ -1,11 +1,33 @@
recursive_wildcard = $(foreach d, $(wildcard $(1:=/*)), $(call recursive_wildcard, $d, $2) $(filter $(subst *, %, $2), $d))
SRC := Cargo.toml
SRC += $(call recursive_wildcard, src, *)
.PHONY: regenerate-entities .PHONY: regenerate-entities
regenerate-entities: regenerate-entities:
sea-orm-cli generate entity \ sea-orm-cli generate entity \
--output-dir='src/model/entity' \ --output-dir='src/model/entity' \
--database-url='postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@localhost:25432/$(POSTGRES_DB)' --database-url='postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@localhost:25432/$(POSTGRES_DB)' \
--date-time-crate='chrono' \
--model-extra-attributes='NAPI_EXTRA_ATTR_PLACEHOLDER' && \
for file in src/model/entity/*; do \
base=$$(basename -- "$${file}"); \
jsname=$$(printf '%s\n' "$${base%.*}" | perl -pe 's/(^|_)./uc($$&)/ge;s/_//g'); \
attribute=$$(printf 'cfg_attr(feature = "napi", napi_derive::napi(object, js_name = "%s", use_nullable = true))' "$${jsname}"); \
sed -i "s/NAPI_EXTRA_ATTR_PLACEHOLDER/$${attribute}/" "$${file}"; \
done
sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]\n#[cfg_attr(not(feature = "napi"), derive(Clone))]\n#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]/' \
src/model/entity/sea_orm_active_enums.rs
cargo fmt --all --
index.js: .PHONY: update-index
update-index: index.js index.d.ts
index.js index.d.ts: $(SRC)
NODE_OPTIONS='--max_old_space_size=3072' pnpm run build:debug NODE_OPTIONS='--max_old_space_size=3072' pnpm run build:debug
[ -f built/index.js ] [ -f built/index.js ] && [ -f built/index.d.ts ]
rm --force index.js rm --force index.js index.d.ts
cp built/index.js index.js cp built/index.js index.js
cp built/index.d.ts index.d.ts
sed -i 's/^ \*r"/ */g' index.d.ts

1054
packages/backend-rs/index.d.ts vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -224,17 +224,32 @@ switch (platform) {
} }
break break
case 'arm': case 'arm':
localFileExisted = existsSync( if (isMusl()) {
join(__dirname, 'backend-rs.linux-arm-gnueabihf.node') localFileExisted = existsSync(
) join(__dirname, 'backend-rs.linux-arm-musleabihf.node')
try { )
if (localFileExisted) { try {
nativeBinding = require('./backend-rs.linux-arm-gnueabihf.node') if (localFileExisted) {
} else { nativeBinding = require('./backend-rs.linux-arm-musleabihf.node')
nativeBinding = require('backend-rs-linux-arm-gnueabihf') } 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 break
case 'riscv64': case 'riscv64':
@ -295,11 +310,46 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`) 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.readEnvironmentConfig = readEnvironmentConfig
module.exports.IdConvertType = IdConvertType module.exports.readServerConfig = readServerConfig
module.exports.convertId = convertId module.exports.stringToAcct = stringToAcct
module.exports.nativeGetTimestamp = nativeGetTimestamp module.exports.acctToString = acctToString
module.exports.nativeCreateId = nativeCreateId module.exports.checkWordMute = checkWordMute
module.exports.nativeInitIdGenerator = nativeInitIdGenerator 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

View file

@ -22,7 +22,7 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@napi-rs/cli": "2.18.0", "@napi-rs/cli": "2.18.1",
"ava": "6.1.2" "ava": "6.1.2"
}, },
"ava": { "ava": {
@ -33,14 +33,12 @@
}, },
"scripts": { "scripts": {
"artifacts": "napi artifacts", "artifacts": "napi artifacts",
"build": "napi build --features napi --platform --release ./built/", "build": "napi build --features napi --no-const-enum --platform --release ./built/",
"build:debug": "napi build --features napi --platform ./built/", "build:debug": "napi build --features napi --no-const-enum --platform ./built/",
"prepublishOnly": "napi prepublish -t npm", "prepublishOnly": "napi prepublish -t npm",
"test": "pnpm run cargo:test && pnpm run build:debug && ava", "test": "pnpm run cargo:test && pnpm run build:debug && ava",
"universal": "napi universal", "universal": "napi universal",
"version": "napi version", "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:test": "pnpm run cargo:unit && pnpm run cargo:integration",
"cargo:unit": "cargo test unit_test && cargo test -F napi unit_test", "cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
"cargo:integration": "cargo test int_test" "cargo:integration": "cargo test int_test"

View file

@ -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(),
}
}

View file

@ -0,0 +1,2 @@
pub mod environment;
pub mod server;

View file

@ -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<String>,
pub disable_hsts: Option<bool>,
pub db: DbConfig,
pub redis: RedisConfig,
pub cache_server: Option<RedisConfig>,
pub proxy: Option<String>,
pub proxy_smtp: Option<String>,
pub proxy_bypass_hosts: Option<Vec<String>>,
pub allowed_private_networks: Option<Vec<String>>,
/// `NapiValue` is not implemented for `u64`
pub max_file_size: Option<i64>,
pub access_log: Option<String>,
pub cluster_limits: Option<WorkerConfig>,
pub cuid: Option<IdConfig>,
pub outgoing_address: Option<String>,
pub deliver_job_concurrency: Option<u32>,
pub inbox_job_concurrency: Option<u32>,
pub deliver_job_per_sec: Option<u32>,
pub inbox_job_per_sec: Option<u32>,
pub deliver_job_max_attempts: Option<u32>,
pub inbox_job_max_attempts: Option<u32>,
pub log_level: Option<Vec<String>>,
pub syslog: Option<SysLogConfig>,
pub proxy_remote_files: Option<bool>,
pub media_proxy: Option<String>,
pub summaly_proxy_url: Option<String>,
pub reserved_usernames: Option<Vec<String>>,
pub max_user_signups: Option<u32>,
pub is_managed_hosting: Option<bool>,
pub max_note_length: Option<u32>,
pub max_caption_length: Option<u32>,
pub deepl: Option<DeepLConfig>,
pub libre_translate: Option<LibreTranslateConfig>,
pub email: Option<EmailConfig>,
pub object_storage: Option<ObjectStorageConfig>,
}
#[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<bool>,
pub extra: Option<serde_json::Value>,
}
#[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<u8>,
pub user: Option<String>,
pub pass: Option<String>,
pub tls: Option<TlsConfig>,
#[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<u32>,
pub queue: Option<u32>,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
#[crate::export(object, use_nullable = false)]
pub struct IdConfig {
pub length: Option<u8>,
pub fingerprint: Option<String>,
}
#[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<bool>,
pub auth_key: Option<String>,
pub is_pro: Option<bool>,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
#[crate::export(object, use_nullable = false)]
pub struct LibreTranslateConfig {
pub managed: Option<bool>,
pub api_url: Option<String>,
pub api_key: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
#[crate::export(object, use_nullable = false)]
pub struct EmailConfig {
pub managed: Option<bool>,
pub address: Option<String>,
pub host: Option<String>,
pub port: Option<u16>,
pub user: Option<String>,
pub pass: Option<String>,
pub use_implicit_ssl_tls: Option<bool>,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
#[crate::export(object, use_nullable = false)]
pub struct ObjectStorageConfig {
pub managed: Option<bool>,
pub base_url: Option<String>,
pub bucket: Option<String>,
pub prefix: Option<String>,
pub endpoint: Option<String>,
pub region: Option<String>,
pub access_key: Option<String>,
pub secret_key: Option<String>,
pub use_ssl: Option<bool>,
pub connnect_over_proxy: Option<bool>,
pub set_public_read_on_upload: Option<bool>,
pub s3_force_path_style: Option<bool>,
}
#[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<ServerConfig> = Lazy::new(read_server_config);

View file

@ -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);

View file

@ -1,26 +1,34 @@
pub mod error; use crate::config::server::SERVER_CONFIG;
use sea_orm::{Database, DbConn, DbErr};
use error::Error;
use sea_orm::{Database, DbConn};
static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new(); static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
pub async fn init_database(conn_uri: impl Into<String>) -> Result<(), Error> { async fn init_database() -> Result<&'static DbConn, DbErr> {
let conn = Database::connect(conn_uri.into()).await?; let database_uri = format!(
DB_CONN.get_or_init(move || conn); "postgres://{}:{}@{}:{}/{}",
Ok(()) 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> { pub async fn db_conn() -> Result<&'static DbConn, DbErr> {
DB_CONN.get().ok_or(Error::Uninitialized) match DB_CONN.get() {
Some(conn) => Ok(conn),
None => init_database().await,
}
} }
#[cfg(test)] #[cfg(test)]
mod unit_test { mod unit_test {
use super::{error::Error, get_database}; use super::db_conn;
#[test] #[tokio::test]
fn error_uninitialized() { async fn connect_test() {
assert_eq!(get_database().unwrap_err(), Error::Uninitialized); assert!(db_conn().await.is_ok());
} }
} }

View file

@ -1,7 +1,7 @@
pub use macro_rs::export;
pub mod config;
pub mod database; pub mod database;
pub mod macros; pub mod misc;
pub mod model; pub mod model;
pub mod util; pub mod util;
#[cfg(feature = "napi")]
pub mod mastodon_api;

View file

@ -1,11 +0,0 @@
#[macro_export]
macro_rules! impl_into_napi_error {
($a:ty) => {
#[cfg(feature = "napi")]
impl Into<napi::Error> for $a {
fn into(self) -> napi::Error {
napi::Error::from_reason(self.to_string())
}
}
};
}

View file

@ -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<String> {
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<u8> {
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> {
CHAR_COLLECTION
.chars()
.nth(number as usize)
.ok_or(Error::from_status(Status::Unknown))
}

View file

@ -0,0 +1,74 @@
#[derive(Debug, PartialEq)]
#[crate::export(object)]
pub struct Acct {
pub username: String,
pub host: Option<String>,
}
#[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);
}
}

View file

@ -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<String>,
pub user_id: Option<String>,
pub text: Option<String>,
pub cw: Option<String>,
pub renote_id: Option<String>,
pub reply_id: Option<String>,
}
async fn all_texts(note: NoteLike) -> Result<Vec<String>, DbErr> {
let db = db_conn().await?;
let mut texts: Vec<String> = 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::<Option<String>>()
.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<String>, Option<String>)>()
.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<String>, Option<String>)>()
.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<Regex> = 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<String>],
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<Vec<String>>,
muted_patterns: Vec<String>,
) -> Result<bool, DbErr> {
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,
))
}
}

View file

@ -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<String, Error> {
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<bool, Error> {
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<bool, Error> {
Ok(url::Url::parse(uri)?.origin().ascii_serialization() == SERVER_CONFIG.url)
}
#[crate::export]
pub fn extract_host(uri: &str) -> Result<String, Error> {
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<String, idna::Errors> {
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"
);
}
}

View file

@ -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:"));
}
}

View file

@ -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%"));
}
}

View file

@ -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<String> = 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)"
);
}
}

View file

@ -0,0 +1,90 @@
/// TODO: handle name collisions better
#[crate::export(object, js_name = "NoteLikeForGetNoteSummary")]
pub struct NoteLike {
pub file_ids: Vec<String>,
pub text: Option<String>,
pub cw: Option<String>,
pub has_poll: bool,
}
#[crate::export]
pub fn get_note_summary(note: NoteLike) -> String {
let mut buf: Vec<String> = 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) 📊");
}
}

View file

@ -0,0 +1,35 @@
#[crate::export]
pub fn to_mastodon_id(firefish_id: &str) -> Option<String> {
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<String> {
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);
}
}

View file

@ -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<Option<Meta>> = 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<Meta, DbErr> {
// 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<String>,
pub title: String,
pub instance_name: String,
pub desc: Option<String>,
pub icon: Option<String>,
pub splash_icon: Option<String>,
pub theme_color: Option<String>,
pub random_motd: String,
pub private_mode: Option<bool>,
}
#[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,
}
}

View file

@ -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;

View file

@ -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<Regex> =
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<Regex> = Lazy::new(|| Regex::new(r"다([..。…?!\s]|$)").unwrap());
to_return = RE.replace_all(&to_return, r"다냥$1").to_string();
}
{
static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"야([?\s]|$)").unwrap());
to_return = RE.replace_all(&to_return, r"냥$1").to_string();
}
{
static RE: Lazy<Regex> = 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<Regex> = 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), "일어냐다냥");
}
}

View file

@ -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<String, password_hash::errors::Error> {
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<bool, VerifyError> {
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());
}
}

View file

@ -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<String>,
pub host: Option<String>,
}
#[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<Regex> =
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<String, u32>) -> HashMap<String, u32> {
let mut res = HashMap::<String, u32>::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<String, Error> {
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<Regex> =
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);
}
}

View file

@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "abuse_user_report")] #[sea_orm(table_name = "abuse_user_report")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "AbuseUserReport", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "targetUserId")] #[sea_orm(column_name = "targetUserId")]
pub target_user_id: String, pub target_user_id: String,
#[sea_orm(column_name = "reporterId")] #[sea_orm(column_name = "reporterId")]

View file

@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "access_token")] #[sea_orm(table_name = "access_token")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "AccessToken", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
pub token: String, pub token: String,
pub hash: String, pub hash: String,
#[sea_orm(column_name = "userId")] #[sea_orm(column_name = "userId")]
@ -16,7 +20,7 @@ pub struct Model {
#[sea_orm(column_name = "appId")] #[sea_orm(column_name = "appId")]
pub app_id: Option<String>, pub app_id: Option<String>,
#[sea_orm(column_name = "lastUsedAt")] #[sea_orm(column_name = "lastUsedAt")]
pub last_used_at: Option<DateTimeWithTimeZone>, pub last_used_at: Option<DateTime>,
pub session: Option<String>, pub session: Option<String>,
pub name: Option<String>, pub name: Option<String>,
pub description: Option<String>, pub description: Option<String>,

View file

@ -4,13 +4,17 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "ad")] #[sea_orm(table_name = "ad")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "Ad", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "expiresAt")] #[sea_orm(column_name = "expiresAt")]
pub expires_at: DateTimeWithTimeZone, pub expires_at: DateTime,
pub place: String, pub place: String,
pub priority: String, pub priority: String,
pub url: String, pub url: String,

View file

@ -4,17 +4,21 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "announcement")] #[sea_orm(table_name = "announcement")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "Announcement", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
pub text: String, pub text: String,
pub title: String, pub title: String,
#[sea_orm(column_name = "imageUrl")] #[sea_orm(column_name = "imageUrl")]
pub image_url: Option<String>, pub image_url: Option<String>,
#[sea_orm(column_name = "updatedAt")] #[sea_orm(column_name = "updatedAt")]
pub updated_at: Option<DateTimeWithTimeZone>, pub updated_at: Option<DateTime>,
#[sea_orm(column_name = "showPopup")] #[sea_orm(column_name = "showPopup")]
pub show_popup: bool, pub show_popup: bool,
#[sea_orm(column_name = "isGoodNews")] #[sea_orm(column_name = "isGoodNews")]

View file

@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "announcement_read")] #[sea_orm(table_name = "announcement_read")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "AnnouncementRead", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
@ -12,7 +16,7 @@ pub struct Model {
#[sea_orm(column_name = "announcementId")] #[sea_orm(column_name = "announcementId")]
pub announcement_id: String, pub announcement_id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
} }
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View file

@ -5,11 +5,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "antenna")] #[sea_orm(table_name = "antenna")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "Antenna", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "userId")] #[sea_orm(column_name = "userId")]
pub user_id: String, pub user_id: String,
pub name: String, pub name: String,

View file

@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "app")] #[sea_orm(table_name = "app")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "App", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "userId")] #[sea_orm(column_name = "userId")]
pub user_id: Option<String>, pub user_id: Option<String>,
pub secret: String, pub secret: String,

View file

@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "attestation_challenge")] #[sea_orm(table_name = "attestation_challenge")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "AttestationChallenge", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
@ -11,7 +15,7 @@ pub struct Model {
pub user_id: String, pub user_id: String,
pub challenge: String, pub challenge: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "registrationChallenge")] #[sea_orm(column_name = "registrationChallenge")]
pub registration_challenge: bool, pub registration_challenge: bool,
} }

View file

@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "auth_session")] #[sea_orm(table_name = "auth_session")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "AuthSession", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
pub token: String, pub token: String,
#[sea_orm(column_name = "userId")] #[sea_orm(column_name = "userId")]
pub user_id: Option<String>, pub user_id: Option<String>,

View file

@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "blocking")] #[sea_orm(table_name = "blocking")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "Blocking", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "blockeeId")] #[sea_orm(column_name = "blockeeId")]
pub blockee_id: String, pub blockee_id: String,
#[sea_orm(column_name = "blockerId")] #[sea_orm(column_name = "blockerId")]

View file

@ -4,13 +4,17 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "channel")] #[sea_orm(table_name = "channel")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "Channel", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "lastNotedAt")] #[sea_orm(column_name = "lastNotedAt")]
pub last_noted_at: Option<DateTimeWithTimeZone>, pub last_noted_at: Option<DateTime>,
#[sea_orm(column_name = "userId")] #[sea_orm(column_name = "userId")]
pub user_id: Option<String>, pub user_id: Option<String>,
pub name: String, pub name: String,

View file

@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "channel_following")] #[sea_orm(table_name = "channel_following")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "ChannelFollowing", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "followeeId")] #[sea_orm(column_name = "followeeId")]
pub followee_id: String, pub followee_id: String,
#[sea_orm(column_name = "followerId")] #[sea_orm(column_name = "followerId")]

View file

@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "channel_note_pining")] #[sea_orm(table_name = "channel_note_pining")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "ChannelNotePining", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "channelId")] #[sea_orm(column_name = "channelId")]
pub channel_id: String, pub channel_id: String,
#[sea_orm(column_name = "noteId")] #[sea_orm(column_name = "noteId")]

View file

@ -4,11 +4,15 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "clip")] #[sea_orm(table_name = "clip")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "Clip", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,
#[sea_orm(column_name = "createdAt")] #[sea_orm(column_name = "createdAt")]
pub created_at: DateTimeWithTimeZone, pub created_at: DateTime,
#[sea_orm(column_name = "userId")] #[sea_orm(column_name = "userId")]
pub user_id: String, pub user_id: String,
pub name: String, pub name: String,

View file

@ -4,6 +4,10 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "clip_note")] #[sea_orm(table_name = "clip_note")]
#[cfg_attr(
feature = "napi",
napi_derive::napi(object, js_name = "ClipNote", use_nullable = true)
)]
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id: String, pub id: String,

Some files were not shown because too many files have changed in this diff Show more