diff --git a/.config/example.yml b/.config/example.yml
index 9082dfb868..17149f6c3a 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -178,19 +178,13 @@ logLevel: [
# Media Proxy
#mediaProxy: https://example.com/proxy
-# Proxy remote files (default: false)
+# Proxy remote files (default: true)
#proxyRemoteFiles: true
#allowedPrivateNetworks: [
# '127.0.0.1/32'
#]
-# TWA
-#twa:
-# nameSpace: android_app
-# packageName: tld.domain.twa
-# sha256CertFingerprints: ['AB:CD:EF']
-
# Upload or download file size limits (bytes)
#maxFileSize: 262144000
diff --git a/.dockerignore b/.dockerignore
index f1c6bfd84a..3819d675c8 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -10,7 +10,7 @@ node_modules
report.*.json
# Rust
-packages/backend-rs/target
+/target
# Coverage
coverage
diff --git a/.gitignore b/.gitignore
index 8ad525d636..beb0b8df5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,9 @@ packages/backend/.idea/vcs.xml
node_modules
report.*.json
+# Cargo
+/target
+
# Cypress
cypress/screenshots
cypress/videos
diff --git a/.gitlab/issue_templates/bug.md b/.gitlab/issue_templates/bug.md
index b02cf3b4d0..f96bdec01e 100644
--- a/.gitlab/issue_templates/bug.md
+++ b/.gitlab/issue_templates/bug.md
@@ -3,27 +3,47 @@
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md)
🤝 By submitting this issue, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) -->
-**What happened?** _(Please give us a brief description of what happened.)_
+## What happened?
-**What did you expect to happen?** _(Please give us a brief description of what you expected to happen.)_
-**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_
+## What did you expect to happen?
-**Instance** _(What instance of firefish are you using?)_
-**What type of issue is this?** _(If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side.)_
+## Version
-**What browser are you using? (Client-side issues only)**
-**What operating system are you using? (Client-side issues only)**
+## What type of issue is this?
-**How do you deploy Firefish on your server? (Server-side issues only)**
+- [ ] server-side
+- [ ] client-side
+- [ ] not sure
-**What operating system are you using? (Server-side issues only)**
+
-**Relevant log output** _(Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks.)_
+### Instance
-**Contribution Guidelines**
+
+### What browser are you using? (client-side issues only)
+
+
+### What operating system are you using? (client-side issues only)
+
+
+### How do you deploy Firefish on your server? (server-side issues only)
+
+
+### What operating system are you using? (Server-side issues only)
+
+
+### Relevant log output
+
+
+
+
+## Contribution Guidelines
By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar issues, and this is not a duplicate.
+
+## Are you willing to fix this bug? (optional)
+- [ ] Yes. I will fix this bug and open a merge request if the change is agreed upon.
diff --git a/.gitlab/issue_templates/feature.md b/.gitlab/issue_templates/feature.md
index 0593b5f61a..4c9ee56226 100644
--- a/.gitlab/issue_templates/feature.md
+++ b/.gitlab/issue_templates/feature.md
@@ -3,15 +3,22 @@
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md)
🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) -->
-**What feature would you like implemented?** _(Please give us a brief description of what you'd like.)_
+## What feature would you like implemented?
-**Why should we add this feature?** _(Please give us a brief description of why your feature is important.)_
-**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_
+## Why should we add this feature?
-**Instance** _(What instance of firefish are you using?)_
-**Contribution Guidelines**
+## Version
+
+
+## Instance
+
+
+## Contribution Guidelines
By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar requests, and this is not a duplicate.
+
+## Are you willing to implement this feature? (optional)
+- [ ] Yes. I will implement this feature and open a merge request if the change is agreed upon.
diff --git a/.gitlab/merge_request_templates/default.md b/.gitlab/merge_request_templates/default.md
index 4672f6a30c..d13a146da0 100644
--- a/.gitlab/merge_request_templates/default.md
+++ b/.gitlab/merge_request_templates/default.md
@@ -1,9 +1,11 @@
-**What does this PR do?** _(Please give us a brief description of what this PR does.)_
+## What does this PR do?
-**Contribution Guidelines**
+
+## Contribution Guidelines
By submitting this merge request, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
+- [ ] This change is reviewed in an issue / This is a minor bug fix
- [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have made sure to test this pull request
- [ ] I have made sure to run `pnpm run format` before submitting this pull request
@@ -12,4 +14,4 @@ If this merge request makes changes to the Firefish API, please update `docs/api
- [ ] I updated the document / This merge request doesn't include API changes
-
+
diff --git a/.gitlab/merge_request_templates/release.md b/.gitlab/merge_request_templates/release.md
index b16db00212..ea40f38813 100644
--- a/.gitlab/merge_request_templates/release.md
+++ b/.gitlab/merge_request_templates/release.md
@@ -10,6 +10,7 @@ I have updated...
- [ ] `docs/changelog.md`
- [ ] `docs/notice-for-admins.md`
- [ ] `docs/api-change.md`
+- [ ] `packages/backend-rs/index.js`
- [ ] OCI container image
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 0083604d44..de0385be2a 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -12,6 +12,7 @@
"esbenp.prettier-vscode",
"redhat.vscode-yaml",
"yoavbls.pretty-ts-errors",
- "biomejs.biome"
+ "biomejs.biome",
+ "rust-lang.rust-analyzer"
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 64b14985cd..0000000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "rust-analyzer.linkedProjects": [
- "packages/backend-rs/Cargo.toml"
- ]
-}
diff --git a/COPYING b/COPYING
index 5b35f69f26..0621b4a8e6 100644
--- a/COPYING
+++ b/COPYING
@@ -1,6 +1,7 @@
Unless specified otherwise, the entirety of this repository is subject to the following:
Copyright © 2014-2023 syuilo and contributors
Copyright © 2022-2023 Kainoa Kanter and contributors
+Copyright © 2024 Firefish contributors
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
@@ -13,6 +14,7 @@ These specific configuration directories:
and their contents are
Copyright © 2022-2023 Kainoa Kanter and contributors
+Copyright © 2024 Firefish contributors
And are distributed under The Apache License, Version 2.0, you should have received a copy of the license file as LICENSE in each specified directory.
diff --git a/packages/backend-rs/Cargo.lock b/Cargo.lock
similarity index 89%
rename from packages/backend-rs/Cargo.lock
rename to Cargo.lock
index 02d294df58..c6ba96e683 100644
--- a/packages/backend-rs/Cargo.lock
+++ b/Cargo.lock
@@ -59,9 +59,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
[[package]]
name = "allocator-api2"
-version = "0.2.16"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]]
name = "android-tzdata"
@@ -128,9 +128,21 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.81"
+version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
+checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
+
+[[package]]
+name = "argon2"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
+dependencies = [
+ "base64ct",
+ "blake2",
+ "cpufeatures",
+ "password-hash",
+]
[[package]]
name = "arrayvec"
@@ -157,18 +169,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
name = "async-trait"
-version = "0.1.79"
+version = "0.1.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681"
+checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -190,12 +202,17 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
name = "backend-rs"
version = "0.0.0"
dependencies = [
+ "argon2",
"async-trait",
"basen",
+ "bcrypt",
"cfg-if",
"chrono",
"cuid2",
+ "emojis",
+ "idna",
"jsonschema",
+ "macro_rs",
"napi",
"napi-build",
"napi-derive",
@@ -203,12 +220,16 @@ dependencies = [
"parse-display",
"pretty_assertions",
"rand",
+ "regex",
"schemars",
"sea-orm",
"serde",
"serde_json",
+ "serde_yaml",
"thiserror",
"tokio",
+ "url",
+ "urlencoding",
]
[[package]]
@@ -232,6 +253,12 @@ version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
+[[package]]
+name = "base64"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
+
[[package]]
name = "base64ct"
version = "1.6.0"
@@ -244,6 +271,19 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dbe4bb73fd931c4d1aaf53b35d1286c8a948ad00ec92c8e3c856f15fd027f43"
+[[package]]
+name = "bcrypt"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7"
+dependencies = [
+ "base64 0.22.0",
+ "blowfish",
+ "getrandom",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "bigdecimal"
version = "0.3.1"
@@ -297,6 +337,15 @@ dependencies = [
"wyz",
]
+[[package]]
+name = "blake2"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
+dependencies = [
+ "digest",
+]
+
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -307,10 +356,20 @@ dependencies = [
]
[[package]]
-name = "borsh"
-version = "1.3.1"
+name = "blowfish"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667"
+checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
+dependencies = [
+ "byteorder",
+ "cipher",
+]
+
+[[package]]
+name = "borsh"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6"
dependencies = [
"borsh-derive",
"cfg_aliases",
@@ -318,23 +377,23 @@ dependencies = [
[[package]]
name = "borsh-derive"
-version = "1.3.1"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd"
+checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5"
dependencies = [
"once_cell",
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
"syn_derive",
]
[[package]]
name = "bumpalo"
-version = "3.15.4"
+version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "bytecheck"
@@ -378,9 +437,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]]
name = "cc"
-version = "1.0.90"
+version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
+checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
[[package]]
name = "cfg-if"
@@ -396,9 +455,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chrono"
-version = "0.4.35"
+version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
+checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -406,7 +465,17 @@ dependencies = [
"num-traits",
"serde",
"wasm-bindgen",
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
]
[[package]]
@@ -440,7 +509,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -497,9 +566,9 @@ dependencies = [
[[package]]
name = "crc"
-version = "3.0.1"
+version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
+checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
dependencies = [
"crc-catalog",
]
@@ -542,7 +611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c"
dependencies = [
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -565,9 +634,9 @@ dependencies = [
[[package]]
name = "der"
-version = "0.7.8"
+version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
+checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
dependencies = [
"const-oid",
"pem-rfc7468",
@@ -627,18 +696,27 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "either"
-version = "1.10.0"
+version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
+checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
dependencies = [
"serde",
]
[[package]]
-name = "encoding_rs"
-version = "0.8.33"
+name = "emojis"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
+checksum = "4ee61eb945bff65ee7d19d157d39c67c33290ff0742907413fd5eefd29edc979"
+dependencies = [
+ "phf",
+]
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
dependencies = [
"cfg-if",
]
@@ -839,9 +917,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.12"
+version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [
"cfg-if",
"js-sys",
@@ -858,9 +936,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "h2"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb"
+checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
dependencies = [
"bytes",
"fnv",
@@ -1066,7 +1144,16 @@ checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
]
[[package]]
@@ -1116,7 +1203,7 @@ checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978"
dependencies = [
"ahash 0.8.11",
"anyhow",
- "base64",
+ "base64 0.21.7",
"bytecount",
"clap",
"fancy-regex",
@@ -1169,7 +1256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if",
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
]
[[package]]
@@ -1211,6 +1298,18 @@ version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+[[package]]
+name = "macro_rs"
+version = "0.0.0"
+dependencies = [
+ "convert_case",
+ "napi",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
+ "thiserror",
+]
+
[[package]]
name = "md-5"
version = "0.10.6"
@@ -1223,9 +1322,9 @@ dependencies = [
[[package]]
name = "memchr"
-version = "2.7.1"
+version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "mime"
@@ -1261,43 +1360,46 @@ dependencies = [
[[package]]
name = "napi"
-version = "2.16.1"
+version = "2.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4ca998356d8ff9fba7a070dae4508a2298439c98c9f3bc9c07669538b999e8f"
+checksum = "70d04890ef4ec001fad791be785b8b920e2a3f5a6b1188e7a81dfa6197c0dee4"
dependencies = [
"bitflags 2.5.0",
+ "chrono",
"ctor",
"napi-derive",
"napi-sys",
"once_cell",
+ "serde",
+ "serde_json",
"tokio",
]
[[package]]
name = "napi-build"
-version = "2.1.2"
+version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f9130fccc5f763cf2069b34a089a18f0d0883c66aceb81f2fad541a3d823c43"
+checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a"
[[package]]
name = "napi-derive"
-version = "2.16.1"
+version = "2.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b138cecf1141ae0ff5d62f4aa0e2f269aec339f66070f346ba6fb4279f1fc178"
+checksum = "aff4a63f26a7aa9fa25df6ea36675890115972b207ae516e86bd0c47e31eba39"
dependencies = [
"cfg-if",
"convert_case",
"napi-derive-backend",
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
name = "napi-derive-backend"
-version = "1.0.63"
+version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce5126b64f6ad9e28e30e6d15213dd378626b38f556454afebc42f7f02a90902"
+checksum = "e5e76afe642e2424ebe465406e328e4316d82af1f79256231d4b0f184c67550a"
dependencies = [
"convert_case",
"once_cell",
@@ -1305,14 +1407,14 @@ dependencies = [
"quote",
"regex",
"semver",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
name = "napi-sys"
-version = "2.3.0"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2503fa6af34dc83fb74888df8b22afe933b58d37daf7d80424b1c60c68196b8b"
+checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3"
dependencies = [
"libloading",
]
@@ -1329,9 +1431,9 @@ dependencies = [
[[package]]
name = "num"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
+checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41"
dependencies = [
"num-bigint",
"num-complex",
@@ -1487,7 +1589,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -1515,28 +1617,38 @@ dependencies = [
[[package]]
name = "parse-display"
-version = "0.8.2"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6509d08722b53e8dafe97f2027b22ccbe3a5db83cb352931e9716b0aa44bc5c"
+checksum = "06af5f9333eb47bd9ba8462d612e37a8328a5cb80b13f0af4de4c3b89f52dee5"
dependencies = [
- "once_cell",
"parse-display-derive",
"regex",
+ "regex-syntax",
]
[[package]]
name = "parse-display-derive"
-version = "0.8.2"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68517892c8daf78da08c0db777fcc17e07f2f63ef70041718f8a7630ad84f341"
+checksum = "dc9252f259500ee570c75adcc4e317fa6f57a1e47747d622e0bf838002a7b790"
dependencies = [
- "once_cell",
"proc-macro2",
"quote",
"regex",
- "regex-syntax 0.7.5",
+ "regex-syntax",
"structmeta",
- "syn 2.0.55",
+ "syn 2.0.58",
+]
+
+[[package]]
+name = "password-hash"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
+dependencies = [
+ "base64ct",
+ "rand_core",
+ "subtle",
]
[[package]]
@@ -1561,10 +1673,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
-name = "pin-project-lite"
-version = "0.2.13"
+name = "phf"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pin-utils"
@@ -1685,9 +1815,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.35"
+version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
@@ -1746,7 +1876,7 @@ dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
- "regex-syntax 0.8.2",
+ "regex-syntax",
]
[[package]]
@@ -1757,20 +1887,14 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
dependencies = [
"aho-corasick",
"memchr",
- "regex-syntax 0.8.2",
+ "regex-syntax",
]
[[package]]
name = "regex-syntax"
-version = "0.7.5"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "rend"
@@ -1787,7 +1911,7 @@ version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
- "base64",
+ "base64 0.21.7",
"bytes",
"encoding_rs",
"futures-core",
@@ -1883,9 +2007,9 @@ dependencies = [
[[package]]
name = "rust_decimal"
-version = "1.34.3"
+version = "1.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b39449a79f45e8da28c57c341891b69a183044b29518bb8f86dbac9df60bb7df"
+checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a"
dependencies = [
"arrayvec",
"borsh",
@@ -1933,7 +2057,7 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
dependencies = [
- "base64",
+ "base64 0.21.7",
]
[[package]]
@@ -2003,7 +2127,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -2044,7 +2168,7 @@ dependencies = [
"proc-macro2",
"quote",
"sea-bae",
- "syn 2.0.55",
+ "syn 2.0.58",
"unicode-ident",
]
@@ -2110,7 +2234,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -2147,6 +2271,19 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_yaml"
+version = "0.9.34+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "ryu",
+ "serde",
+ "unsafe-libyaml",
+]
+
[[package]]
name = "sha1"
version = "0.10.6"
@@ -2204,6 +2341,12 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
[[package]]
name = "slab"
version = "0.4.9"
@@ -2371,7 +2514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
dependencies = [
"atoi",
- "base64",
+ "base64 0.21.7",
"bigdecimal",
"bitflags 2.5.0",
"byteorder",
@@ -2418,7 +2561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
dependencies = [
"atoi",
- "base64",
+ "base64 0.21.7",
"bigdecimal",
"bitflags 2.5.0",
"byteorder",
@@ -2500,31 +2643,31 @@ dependencies = [
[[package]]
name = "strsim"
-version = "0.11.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "structmeta"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ad9e09554f0456d67a69c1584c9798ba733a5b50349a6c0d0948710523922d"
+checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329"
dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
name = "structmeta-derive"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
+checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -2552,9 +2695,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.55"
+version = "2.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0"
+checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
dependencies = [
"proc-macro2",
"quote",
@@ -2570,7 +2713,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -2635,14 +2778,14 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
name = "time"
-version = "0.3.34"
+version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
@@ -2661,9 +2804,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
-version = "0.2.17"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
@@ -2686,9 +2829,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.36.0"
+version = "1.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
+checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
dependencies = [
"backtrace",
"bytes",
@@ -2711,7 +2854,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -2782,7 +2925,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
@@ -2839,6 +2982,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
+[[package]]
+name = "unsafe-libyaml"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
+
[[package]]
name = "untrusted"
version = "0.9.0"
@@ -2931,7 +3080,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
"wasm-bindgen-shared",
]
@@ -2965,7 +3114,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -3008,7 +3157,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
]
[[package]]
@@ -3026,7 +3175,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
]
[[package]]
@@ -3046,17 +3195,18 @@ dependencies = [
[[package]]
name = "windows-targets"
-version = "0.52.4"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
- "windows_aarch64_gnullvm 0.52.4",
- "windows_aarch64_msvc 0.52.4",
- "windows_i686_gnu 0.52.4",
- "windows_i686_msvc 0.52.4",
- "windows_x86_64_gnu 0.52.4",
- "windows_x86_64_gnullvm 0.52.4",
- "windows_x86_64_msvc 0.52.4",
+ "windows_aarch64_gnullvm 0.52.5",
+ "windows_aarch64_msvc 0.52.5",
+ "windows_i686_gnu 0.52.5",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.5",
+ "windows_x86_64_gnu 0.52.5",
+ "windows_x86_64_gnullvm 0.52.5",
+ "windows_x86_64_msvc 0.52.5",
]
[[package]]
@@ -3067,9 +3217,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
@@ -3079,9 +3229,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.52.4"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
@@ -3091,9 +3241,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
-version = "0.52.4"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
@@ -3103,9 +3259,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
-version = "0.52.4"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
@@ -3115,9 +3271,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.52.4"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -3127,9 +3283,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
@@ -3139,9 +3295,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.52.4"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "winnow"
@@ -3194,7 +3350,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.55",
+ "syn 2.0.58",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000000..7ca43c960b
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,42 @@
+[workspace]
+members = ["packages/backend-rs", "packages/macro-rs"]
+resolver = "2"
+
+[workspace.dependencies]
+macro_rs = { path = "packages/macro-rs" }
+
+napi = { version = "2.16.2", default-features = false }
+napi-derive = "2.16.2"
+napi-build = "2.1.3"
+
+argon2 = "0.5.3"
+async-trait = "0.1.80"
+basen = "0.1.0"
+bcrypt = "0.15.1"
+cfg-if = "1.0.0"
+chrono = "0.4.37"
+convert_case = "0.6.0"
+cuid2 = "0.1.2"
+emojis = "0.6.1"
+idna = "0.5.0"
+jsonschema = "0.17.1"
+once_cell = "1.19.0"
+parse-display = "0.9.0"
+pretty_assertions = "1.4.0"
+proc-macro2 = "1.0.79"
+quote = "1.0.36"
+rand = "0.8.5"
+regex = "1.10.4"
+schemars = "0.8.16"
+sea-orm = "0.12.15"
+serde = "1.0.197"
+serde_json = "1.0.115"
+serde_yaml = "0.9.34"
+syn = "2.0.58"
+thiserror = "1.0.58"
+tokio = "1.37.0"
+url = "2.5.0"
+urlencoding = "2.1.3"
+
+[profile.release]
+lto = true
diff --git a/Dockerfile b/Dockerfile
index b19001772a..65c37e32b7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,9 +8,12 @@ RUN curl --proto '=https' --tlsv1.2 --silent --show-error --fail https://sh.rust
ENV PATH="/root/.cargo/bin:${PATH}"
# Copy only the cargo dependency-related files first, to cache efficiently
+COPY Cargo.toml Cargo.toml
+COPY Cargo.lock Cargo.lock
COPY packages/backend-rs/Cargo.toml packages/backend-rs/Cargo.toml
-COPY packages/backend-rs/Cargo.lock packages/backend-rs/Cargo.lock
COPY packages/backend-rs/src/lib.rs packages/backend-rs/src/
+COPY packages/macro-rs/Cargo.toml packages/macro-rs/Cargo.toml
+COPY packages/macro-rs/src/lib.rs packages/macro-rs/src/
# Install cargo dependencies
RUN cargo fetch --locked --manifest-path /firefish/packages/backend-rs/Cargo.toml
diff --git a/Makefile b/Makefile
index 37dc019648..55c711855c 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ export
.PHONY: pre-commit
-pre-commit: format entities update-index-js
+pre-commit: format entities napi-index
.PHONY: format
format:
@@ -14,9 +14,9 @@ entities:
pnpm run migrate
$(MAKE) -C ./packages/backend-rs regenerate-entities
-.PHONY: update-index-js
-update-index-js:
- $(MAKE) -C ./packages/backend-rs index.js
+.PHONY: napi-index
+napi-index:
+ $(MAKE) -C ./packages/backend-rs update-index
.PHONY: build
@@ -27,13 +27,13 @@ build:
pnpm run migrate
-.PHONY: db.init db.up db.down
-db.init:
- $(MAKE) -C ./dev/db-container init
+.PHONY: db.up db.down db.init
db.up:
$(MAKE) -C ./dev/db-container up
db.down:
$(MAKE) -C ./dev/db-container down
+db.init:
+ $(MAKE) -C ./dev/db-container init
.PHONY: psql redis-cli
psql:
diff --git a/biome.json b/biome.json
index 2fa6846b64..21b711f457 100644
--- a/biome.json
+++ b/biome.json
@@ -1,12 +1,31 @@
{
- "$schema": "https://biomejs.dev/schemas/1.0.0/schema.json",
+ "$schema": "https://biomejs.dev/schemas/1.6.4/schema.json",
"organizeImports": {
- "enabled": true
+ "enabled": false
},
"linter": {
"enabled": true,
"rules": {
- "recommended": true
+ "recommended": true,
+ "style": {
+ "noUselessElse": "off"
+ }
}
- }
+ },
+ "overrides": [
+ {
+ "include": ["*.vue"],
+ "linter": {
+ "rules": {
+ "style": {
+ "useImportType": "warn",
+ "useShorthandFunctionType": "warn",
+ "useTemplate": "warn",
+ "noNonNullAssertion": "off",
+ "useNodejsImportProtocol": "off"
+ }
+ }
+ }
+ }
+ ]
}
diff --git a/dev/db-container/Makefile b/dev/db-container/Makefile
index 0238308de4..a762e95110 100644
--- a/dev/db-container/Makefile
+++ b/dev/db-container/Makefile
@@ -1,9 +1,11 @@
-.PHONY: init up down
-init: down up
+.PHONY: up down init
up:
$(COMPOSE) up --detach
down:
$(COMPOSE) down
+init:
+ $(COMPOSE) down --volumes
+ $(COMPOSE) up --detach
.PHONY: psql redis-cli
psql:
diff --git a/dev/db-container/docker-compose.yml b/dev/db-container/docker-compose.yml
index 4cd121d2d4..770d8fb18d 100644
--- a/dev/db-container/docker-compose.yml
+++ b/dev/db-container/docker-compose.yml
@@ -5,6 +5,8 @@ services:
image: docker.io/redis:7-alpine
ports:
- "26379:6379"
+ volumes:
+ - "redis-data:/data"
db:
image: docker.io/groonga/pgroonga:3.1.8-alpine-12
env_file:
@@ -13,3 +15,10 @@ services:
- "25432:5432"
volumes:
- "./install.sql:/docker-entrypoint-initdb.d/install.sql:ro"
+ - "postgres-data:/var/lib/postgresql/data"
+
+volumes:
+ redis-data:
+ name: redis-data
+ postgres-data:
+ name: postgres-data
diff --git a/dev/docs/local-installation.md b/dev/docs/local-installation.md
index 154f768037..15c7dad7d4 100644
--- a/dev/docs/local-installation.md
+++ b/dev/docs/local-installation.md
@@ -42,6 +42,8 @@ cargo --version
### PostgreSQL and PGroonga
+Firefish requires PostgreSQL v12 or later. We recommend that you install v12.x for the same reason as Node.js.
+
PostgreSQL install instructions can be found at [this page](https://www.postgresql.org/download/).
```sh
diff --git a/docker-compose.example.yml b/docker-compose.example.yml
index fc6c0268a2..9cd6d1cdce 100644
--- a/docker-compose.example.yml
+++ b/docker-compose.example.yml
@@ -17,6 +17,7 @@ services:
# - web
environment:
NODE_ENV: production
+ NODE_OPTIONS: --max-old-space-size=3072
volumes:
- ./custom:/firefish/custom:ro
- ./files:/firefish/files
diff --git a/docs/api-change.md b/docs/api-change.md
index fdda2e78b4..dcd4329a27 100644
--- a/docs/api-change.md
+++ b/docs/api-change.md
@@ -2,6 +2,18 @@
Breaking changes are indicated by the :warning: icon.
+## Unreleased
+
+- Added `antennaLimit` field to the response of `meta` and `admin/meta`, and the request of `admin/update-meta` (optional).
+
+## v20240413
+
+- :warning: Removed `patrons` endpoint.
+
+## v20240405
+
+- Added `notes/history` endpoint.
+
## v20240319
- :warning: `followingCount` and `followersCount` in `users/show` will be `null` (instead of 0) if these values are unavailable.
diff --git a/docs/changelog.md b/docs/changelog.md
index cd553ea014..70f8b34fbe 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -5,6 +5,27 @@ Critical security updates are indicated by the :warning: icon.
- Server administrators should check [notice-for-admins.md](./notice-for-admins.md) as well.
- Third-party client/bot developers may want to check [api-change.md](./api-change.md) as well.
+## [v20240421](https://firefish.dev/firefish/firefish/-/merge_requests/10756/commits)
+
+- Fix bugs
+
+## [v20240413](https://firefish.dev/firefish/firefish/-/merge_requests/10741/commits)
+
+- Add "Media" tab to user page
+- Improve federation and rendering of mathematical expressions
+- Remove donor information from the web client
+ - See also: https://info.firefish.dev/notes/9s1n283sb10rh869
+- Fix bugs
+
+## [v20240405](https://firefish.dev/firefish/firefish/-/merge_requests/10733/commits)
+
+- Add ability to view the history of post edits (!10714)
+- Fix bugs
+
+## [v20240401](https://firefish.dev/firefish/firefish/-/merge_requests/10724/commits)
+
+- Fix bugs
+
## :warning: [v20240330](https://firefish.dev/firefish/firefish/-/merge_requests/10719/commits)
- Fix bugs (including a critical security issue)
diff --git a/docs/downgrade.sql b/docs/downgrade.sql
index 88e08c40ad..44222f818f 100644
--- a/docs/downgrade.sql
+++ b/docs/downgrade.sql
@@ -1,6 +1,11 @@
BEGIN;
DELETE FROM "migrations" WHERE name IN (
+ 'AddDriveFileUsage1713451569342',
+ 'ConvertCwVarcharToText1713225866247',
+ 'FixChatFileConstraint1712855579316',
+ 'DropTimeZone1712425488543',
+ 'ExpandNoteEdit1711936358554',
'markLocalFilesNsfwByDefault1709305200000',
'FixMutingIndices1710690239308',
'NoteFile1710304584214',
@@ -19,6 +24,99 @@ DELETE FROM "migrations" WHERE name IN (
'RemoveNativeUtilsMigration1705877093218'
);
+-- AddDriveFileUsage
+ALTER TABLE "drive_file" DROP COLUMN "usageHint";
+DROP TYPE "drive_file_usage_hint_enum";
+
+-- convert-cw-varchar-to-text
+DROP INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f";
+ALTER TABLE "note" ALTER COLUMN "cw" TYPE character varying(512);
+CREATE INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f" ON "note" USING "pgroonga" ("cw" pgroonga_varchar_full_text_search_ops_v2);
+
+-- fix-chat-file-constraint
+ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_535def119223ac05ad3fa9ef64b";
+ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_535def119223ac05ad3fa9ef64b" FOREIGN KEY ("fileId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
+
+-- drop-time-zone
+ALTER TABLE "abuse_user_report" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "access_token" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "access_token" ALTER "lastUsedAt" TYPE timestamp with time zone;
+ALTER TABLE "ad" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "ad" ALTER "expiresAt" TYPE timestamp with time zone;
+ALTER TABLE "announcement" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "announcement" ALTER "updatedAt" TYPE timestamp with time zone;
+ALTER TABLE "announcement_read" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "antenna" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "app" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "attestation_challenge" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "auth_session" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "blocking" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "channel" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "channel" ALTER "lastNotedAt" TYPE timestamp with time zone;
+ALTER TABLE "channel_following" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "channel_note_pining" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "clip" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "drive_file" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "drive_folder" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "emoji" ALTER "updatedAt" TYPE timestamp with time zone;
+ALTER TABLE "following" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "follow_request" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "gallery_like" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "gallery_post" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "gallery_post" ALTER "updatedAt" TYPE timestamp with time zone;
+ALTER TABLE "instance" ALTER "caughtAt" TYPE timestamp with time zone;
+ALTER TABLE "instance" ALTER "infoUpdatedAt" TYPE timestamp with time zone;
+ALTER TABLE "instance" ALTER "lastCommunicatedAt" TYPE timestamp with time zone;
+ALTER TABLE "instance" ALTER "latestRequestReceivedAt" TYPE timestamp with time zone;
+ALTER TABLE "instance" ALTER "latestRequestSentAt" TYPE timestamp with time zone;
+ALTER TABLE "messaging_message" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "moderation_log" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "muting" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "muting" ALTER "expiresAt" TYPE timestamp with time zone;
+ALTER TABLE "note" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "note" ALTER "updatedAt" TYPE timestamp with time zone;
+ALTER TABLE "note_edit" ALTER "updatedAt" TYPE timestamp with time zone;
+ALTER TABLE "note_favorite" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "note_reaction" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "note_thread_muting" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "note_watching" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "notification" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "page" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "page" ALTER "updatedAt" TYPE timestamp with time zone;
+ALTER TABLE "page_like" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "password_reset_request" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "poll" ALTER "expiresAt" TYPE timestamp with time zone;
+ALTER TABLE "poll_vote" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "promo_note" ALTER "expiresAt" TYPE timestamp with time zone;
+ALTER TABLE "promo_read" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "registration_ticket" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "registry_item" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "registry_item" ALTER "updatedAt" TYPE timestamp with time zone;
+ALTER TABLE "renote_muting" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "reply_muting" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "signin" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "sw_subscription" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "used_username" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user" ALTER "lastActiveDate" TYPE timestamp with time zone;
+ALTER TABLE "user" ALTER "lastFetchedAt" TYPE timestamp with time zone;
+ALTER TABLE "user" ALTER "updatedAt" TYPE timestamp with time zone;
+ALTER TABLE "user_group" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_group_invitation" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_group_invite" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_group_joining" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_ip" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_list" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_list_joining" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_note_pining" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_pending" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "user_security_key" ALTER "lastUsed" TYPE timestamp with time zone;
+ALTER TABLE "webhook" ALTER "createdAt" TYPE timestamp with time zone;
+ALTER TABLE "webhook" ALTER "latestSentAt" TYPE timestamp with time zone;
+
+-- expand-note-edit
+ALTER TABLE "note_edit" DROP COLUMN "emojis";
+
-- markLocalFilesNsfwByDefault
ALTER TABLE "meta" DROP COLUMN "markLocalFilesNsfwByDefault";
diff --git a/docs/install.md b/docs/install.md
index 061000fa32..0e850e2545 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -1,9 +1,36 @@
# Install Firefish
-This document shows an example procedure for installing Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation.
+Firefish depends on the following software.
+
+## Runtime dependencies
+
+- At least [NodeJS](https://nodejs.org/en/) v18.17.0 (v20/v21 recommended)
+- At least [PostgreSQL](https://www.postgresql.org/) v12 (v16 recommended) with [PGroonga](https://pgroonga.github.io/) extension
+- At least [Redis](https://redis.io/) v7
+- Web Proxy (one of the following)
+ - Caddy (recommended)
+ - Nginx (recommended)
+ - Apache
+- [FFmpeg](https://ffmpeg.org/) for video transcoding (**optional**)
+- Caching server (**optional**, one of the following)
+ - [DragonflyDB](https://www.dragonflydb.io/)
+ - [KeyDB](https://keydb.dev/)
+ - Another [Redis](https://redis.io/) server
+
+## Build dependencies
+
+- At least [Rust](https://www.rust-lang.org/) v1.74
+- C/C++ compiler & build tools
+ - `build-essential` on Debian/Ubuntu Linux
+ - `base-devel` on Arch Linux
+- [Python 3](https://www.python.org/)
+
+This document shows an example procedure for installing these dependencies and Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation.
If you want to use the pre-built container image, please refer to [`install-container.md`](./install-container.md).
+If you do not prepare your environment as document, be sure to meet the minimum dependencies given at the bottom of the page.
+
Make sure that you can use the `sudo` command before proceeding.
## 1. Install dependencies
@@ -154,7 +181,7 @@ sudo apt install ffmpeg
1. Build
```sh
pnpm install --frozen-lockfile
- NODE_ENV=production pnpm run build
+ NODE_ENV=production NODE_OPTIONS='--max-old-space-size=3072' pnpm run build
```
1. Execute database migrations
```sh
@@ -242,6 +269,7 @@ In this instruction, we use [Caddy](https://caddyserver.com/) to make the Firefi
WorkingDirectory=/home/firefish/firefish
Environment="NODE_ENV=production"
Environment="npm_config_cache=/tmp"
+ Environment="NODE_OPTIONS=--max-old-space-size=3072"
# uncomment the following line if you use jemalloc (note that the path varies on different environments)
# Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
StandardOutput=journal
diff --git a/docs/notice-for-admins.md b/docs/notice-for-admins.md
index 5c2eb9b966..9bff40a65c 100644
--- a/docs/notice-for-admins.md
+++ b/docs/notice-for-admins.md
@@ -2,6 +2,33 @@
You can skip intermediate versions when upgrading from an old version, but please read the notices and follow the instructions for each intermediate version before [upgrading](./upgrade.md).
+## v20240413
+
+### For all users
+
+Upgrading may take a long time due to the large changes in the database. Please make sure to perform the operations when you have time.
+
+The time required to upgrade varies greatly depending on the database size and the environment. For reference, we have checked that the database migration takes
+
+- 70 seconds if the database stores 600,000 posts
+- 28 minutes if the database stores 12,000,000 posts
+
+(i.e., it takes roughly (𝑛 / 470,000) minutes where 𝑛 is the number of posts) on a server with 2 GB of RAM. You may want to tweak your database configuration (`postgres.conf`) if the process is significantly slower than our experimental result.
+
+The number of posts stored on your database can be found at `https://yourserver.example.com/admin/database` (or `notesCount` of `stats` API response).
+
+### For systemd/pm2 users
+
+- Please remove `packages/backend-rs/target` before building Firefish.
+ ```sh
+ rm --recursive --force packages/backend-rs/target
+ ```
+- Please do not terminate `pnpm run migrate` even if it appears to be frozen.
+
+### For Docker/Podman users
+
+You may not be able to access your server for a while after starting the container.
+
## v20240326
### For Docker/Podman users
@@ -31,11 +58,11 @@ psql (PostgreSQL) 16.1
In this case, your PostgreSQL major version is `16`.
-There are official installation instructions for many operating systems on , so please follow the instructions on this page. However, since many users are using Ubuntu, and there are no instructions for Arch Linux and Fedora, we explicitly list the instructions for Ubuntu, Arch Linux and Fedora here. Please keep in mind that this is not official information and the procedures may change.
+There are official installation instructions for many operating systems on , so please follow the instructions on this page. However, since many users are using Ubuntu LTS or Debian, and there are no instructions for Arch Linux and Fedora, we explicitly list the instructions for Ubuntu LTS, Debian, Arch Linux and Fedora here. Please keep in mind that this is not official information and the procedures may change.
-##### Ubuntu
+##### Ubuntu LTS
-1. Install subdependencies and add apt repository
+1. Install subdependencies
```sh
sudo apt install -y software-properties-common
sudo add-apt-repository -y universe
@@ -43,14 +70,35 @@ There are official installation instructions for many operating systems on
+ allowedPrivateNetworks?: Array
+ /** `NapiValue` is not implemented for `u64` */
+ maxFileSize?: number
+ accessLog?: string
+ clusterLimits?: WorkerConfig
+ cuid?: IdConfig
+ outgoingAddress?: string
+ deliverJobConcurrency?: number
+ inboxJobConcurrency?: number
+ deliverJobPerSec?: number
+ inboxJobPerSec?: number
+ deliverJobMaxAttempts?: number
+ inboxJobMaxAttempts?: number
+ logLevel?: Array
+ syslog?: SysLogConfig
+ proxyRemoteFiles?: boolean
+ mediaProxy?: string
+ summalyProxyUrl?: string
+ reservedUsernames?: Array
+ maxUserSignups?: number
+ isManagedHosting?: boolean
+ maxNoteLength?: number
+ maxCaptionLength?: number
+ deepl?: DeepLConfig
+ libreTranslate?: LibreTranslateConfig
+ email?: EmailConfig
+ objectStorage?: ObjectStorageConfig
+}
+export interface DbConfig {
+ host: string
+ port: number
+ db: string
+ user: string
+ pass: string
+ disableCache?: boolean
+ extra?: any
+}
+export interface RedisConfig {
+ host: string
+ port: number
+ family?: number
+ user?: string
+ pass?: string
+ tls?: TlsConfig
+ db: number
+ prefix: string
+}
+export interface TlsConfig {
+ host: string
+ rejectUnauthorized: boolean
+}
+export interface WorkerConfig {
+ web?: number
+ queue?: number
+}
+export interface IdConfig {
+ length?: number
+ fingerprint?: string
+}
+export interface SysLogConfig {
+ host: string
+ port: number
+}
+export interface DeepLConfig {
+ managed?: boolean
+ authKey?: string
+ isPro?: boolean
+}
+export interface LibreTranslateConfig {
+ managed?: boolean
+ apiUrl?: string
+ apiKey?: string
+}
+export interface EmailConfig {
+ managed?: boolean
+ address?: string
+ host?: string
+ port?: number
+ user?: string
+ pass?: string
+ useImplicitSslTls?: boolean
+}
+export interface ObjectStorageConfig {
+ managed?: boolean
+ baseUrl?: string
+ bucket?: string
+ prefix?: string
+ endpoint?: string
+ region?: string
+ accessKey?: string
+ secretKey?: string
+ useSsl?: boolean
+ connnectOverProxy?: boolean
+ setPublicReadOnUpload?: boolean
+ s3ForcePathStyle?: boolean
+}
+export function readServerConfig(): ServerConfig
+export interface Acct {
+ username: string
+ host: string | null
+}
+export function stringToAcct(acct: string): Acct
+export function acctToString(acct: Acct): string
+/** TODO: handle name collisions better */
+export interface NoteLikeForCheckWordMute {
+ fileIds: Array
+ userId: string | null
+ text: string | null
+ cw: string | null
+ renoteId: string | null
+ replyId: string | null
+}
+export function checkWordMute(note: NoteLikeForCheckWordMute, mutedWordLists: Array>, mutedPatterns: Array): Promise
+export function getFullApAccount(username: string, host?: string | undefined | null): string
+export function isSelfHost(host?: string | undefined | null): boolean
+export function isSameOrigin(uri: string): boolean
+export function extractHost(uri: string): string
+export function toPuny(host: string): string
+export function isUnicodeEmoji(s: string): boolean
+export function sqlLikeEscape(src: string): string
+export function safeForSql(src: string): boolean
+/** Convert milliseconds to a human readable string */
+export function formatMilliseconds(milliseconds: number): string
+/** TODO: handle name collisions better */
+export interface NoteLikeForGetNoteSummary {
+ fileIds: Array
+ text: string | null
+ cw: string | null
+ hasPoll: boolean
+}
+export function getNoteSummary(note: NoteLikeForGetNoteSummary): string
+export function toMastodonId(firefishId: string): string | null
+export function fromMastodonId(mastodonId: string): string | null
+export function fetchMeta(useCache: boolean): Promise
+export interface PugArgs {
+ img: string | null
+ title: string
+ instanceName: string
+ desc: string | null
+ icon: string | null
+ splashIcon: string | null
+ themeColor: string | null
+ randomMotd: string
+ privateMode: boolean | null
+}
+export function metaToPugArgs(meta: Meta): PugArgs
+export function nyaify(text: string, lang?: string | undefined | null): string
+export function hashPassword(password: string): string
+export function verifyPassword(password: string, hash: string): boolean
+export function isOldPasswordAlgorithm(hash: string): boolean
+export interface DecodedReaction {
+ reaction: string
+ name: string | null
+ host: string | null
+}
+export function decodeReaction(reaction: string): DecodedReaction
+export function countReactions(reactions: Record): Record
+export function toDbReaction(reaction?: string | undefined | null, host?: string | undefined | null): Promise
+export interface AbuseUserReport {
+ id: string
+ createdAt: Date
+ targetUserId: string
+ reporterId: string
+ assigneeId: string | null
+ resolved: boolean
+ comment: string
+ targetUserHost: string | null
+ reporterHost: string | null
+ forwarded: boolean
+}
+export interface AccessToken {
+ id: string
+ createdAt: Date
+ token: string
+ hash: string
+ userId: string
+ appId: string | null
+ lastUsedAt: Date | null
+ session: string | null
+ name: string | null
+ description: string | null
+ iconUrl: string | null
+ permission: Array
+ fetched: boolean
+}
+export interface Ad {
+ id: string
+ createdAt: Date
+ expiresAt: Date
+ place: string
+ priority: string
+ url: string
+ imageUrl: string
+ memo: string
+ ratio: number
+}
+export interface Announcement {
+ id: string
+ createdAt: Date
+ text: string
+ title: string
+ imageUrl: string | null
+ updatedAt: Date | null
+ showPopup: boolean
+ isGoodNews: boolean
+}
+export interface AnnouncementRead {
+ id: string
+ userId: string
+ announcementId: string
+ createdAt: Date
+}
+export interface Antenna {
+ id: string
+ createdAt: Date
+ userId: string
+ name: string
+ src: AntennaSrcEnum
+ userListId: string | null
+ keywords: Json
+ withFile: boolean
+ expression: string | null
+ notify: boolean
+ caseSensitive: boolean
+ withReplies: boolean
+ userGroupJoiningId: string | null
+ users: Array
+ excludeKeywords: Json
+ instances: Json
+}
+export interface App {
+ id: string
+ createdAt: Date
+ userId: string | null
+ secret: string
+ name: string
+ description: string
+ permission: Array
+ callbackUrl: string | null
+}
+export interface AttestationChallenge {
+ id: string
+ userId: string
+ challenge: string
+ createdAt: Date
+ registrationChallenge: boolean
+}
+export interface AuthSession {
+ id: string
+ createdAt: Date
+ token: string
+ userId: string | null
+ appId: string
+}
+export interface Blocking {
+ id: string
+ createdAt: Date
+ blockeeId: string
+ blockerId: string
+}
+export interface Channel {
+ id: string
+ createdAt: Date
+ lastNotedAt: Date | null
+ userId: string | null
+ name: string
+ description: string | null
+ bannerId: string | null
+ notesCount: number
+ usersCount: number
+}
+export interface ChannelFollowing {
+ id: string
+ createdAt: Date
+ followeeId: string
+ followerId: string
+}
+export interface ChannelNotePining {
+ id: string
+ createdAt: Date
+ channelId: string
+ noteId: string
+}
+export interface Clip {
+ id: string
+ createdAt: Date
+ userId: string
+ name: string
+ isPublic: boolean
+ description: string | null
+}
+export interface ClipNote {
+ id: string
+ noteId: string
+ clipId: string
+}
+export interface DriveFile {
+ id: string
+ createdAt: Date
+ userId: string | null
+ userHost: string | null
+ md5: string
+ name: string
+ type: string
+ size: number
+ comment: string | null
+ properties: Json
+ storedInternal: boolean
+ url: string
+ thumbnailUrl: string | null
+ webpublicUrl: string | null
+ accessKey: string | null
+ thumbnailAccessKey: string | null
+ webpublicAccessKey: string | null
+ uri: string | null
+ src: string | null
+ folderId: string | null
+ isSensitive: boolean
+ isLink: boolean
+ blurhash: string | null
+ webpublicType: string | null
+ requestHeaders: Json | null
+ requestIp: string | null
+ usageHint: DriveFileUsageHintEnum | null
+}
+export interface DriveFolder {
+ id: string
+ createdAt: Date
+ name: string
+ userId: string | null
+ parentId: string | null
+}
+export interface Emoji {
+ id: string
+ updatedAt: Date | null
+ name: string
+ host: string | null
+ originalUrl: string
+ uri: string | null
+ type: string | null
+ aliases: Array
+ category: string | null
+ publicUrl: string
+ license: string | null
+ width: number | null
+ height: number | null
+}
+export interface FollowRequest {
+ id: string
+ createdAt: Date
+ followeeId: string
+ followerId: string
+ requestId: string | null
+ followerHost: string | null
+ followerInbox: string | null
+ followerSharedInbox: string | null
+ followeeHost: string | null
+ followeeInbox: string | null
+ followeeSharedInbox: string | null
+}
+export interface Following {
+ id: string
+ createdAt: Date
+ followeeId: string
+ followerId: string
+ followerHost: string | null
+ followerInbox: string | null
+ followerSharedInbox: string | null
+ followeeHost: string | null
+ followeeInbox: string | null
+ followeeSharedInbox: string | null
+}
+export interface GalleryLike {
+ id: string
+ createdAt: Date
+ userId: string
+ postId: string
+}
+export interface GalleryPost {
+ id: string
+ createdAt: Date
+ updatedAt: Date
+ title: string
+ description: string | null
+ userId: string
+ fileIds: Array
+ isSensitive: boolean
+ likedCount: number
+ tags: Array
+}
+export interface Hashtag {
+ id: string
+ name: string
+ mentionedUserIds: Array
+ mentionedUsersCount: number
+ mentionedLocalUserIds: Array
+ mentionedLocalUsersCount: number
+ mentionedRemoteUserIds: Array
+ mentionedRemoteUsersCount: number
+ attachedUserIds: Array
+ attachedUsersCount: number
+ attachedLocalUserIds: Array
+ attachedLocalUsersCount: number
+ attachedRemoteUserIds: Array
+ attachedRemoteUsersCount: number
+}
+export interface Instance {
+ id: string
+ caughtAt: Date
+ host: string
+ usersCount: number
+ notesCount: number
+ followingCount: number
+ followersCount: number
+ latestRequestSentAt: Date | null
+ latestStatus: number | null
+ latestRequestReceivedAt: Date | null
+ lastCommunicatedAt: Date
+ isNotResponding: boolean
+ softwareName: string | null
+ softwareVersion: string | null
+ openRegistrations: boolean | null
+ name: string | null
+ description: string | null
+ maintainerName: string | null
+ maintainerEmail: string | null
+ infoUpdatedAt: Date | null
+ isSuspended: boolean
+ iconUrl: string | null
+ themeColor: string | null
+ faviconUrl: string | null
+}
+export interface MessagingMessage {
+ id: string
+ createdAt: Date
+ userId: string
+ recipientId: string | null
+ text: string | null
+ isRead: boolean
+ fileId: string | null
+ groupId: string | null
+ reads: Array
+ uri: string | null
+}
+export interface Meta {
+ id: string
+ name: string | null
+ description: string | null
+ maintainerName: string | null
+ maintainerEmail: string | null
+ disableRegistration: boolean
+ disableLocalTimeline: boolean
+ disableGlobalTimeline: boolean
+ useStarForReactionFallback: boolean
+ langs: Array
+ hiddenTags: Array
+ blockedHosts: Array
+ mascotImageUrl: string | null
+ bannerUrl: string | null
+ errorImageUrl: string | null
+ iconUrl: string | null
+ cacheRemoteFiles: boolean
+ enableRecaptcha: boolean
+ recaptchaSiteKey: string | null
+ recaptchaSecretKey: string | null
+ localDriveCapacityMb: number
+ remoteDriveCapacityMb: number
+ antennaLimit: number
+ summalyProxy: string | null
+ enableEmail: boolean
+ email: string | null
+ smtpSecure: boolean
+ smtpHost: string | null
+ smtpPort: number | null
+ smtpUser: string | null
+ smtpPass: string | null
+ enableServiceWorker: boolean
+ swPublicKey: string | null
+ swPrivateKey: string | null
+ pinnedUsers: Array
+ tosUrl: string | null
+ repositoryUrl: string
+ feedbackUrl: string | null
+ useObjectStorage: boolean
+ objectStorageBucket: string | null
+ objectStoragePrefix: string | null
+ objectStorageBaseUrl: string | null
+ objectStorageEndpoint: string | null
+ objectStorageRegion: string | null
+ objectStorageAccessKey: string | null
+ objectStorageSecretKey: string | null
+ objectStoragePort: number | null
+ objectStorageUseSsl: boolean
+ proxyAccountId: string | null
+ objectStorageUseProxy: boolean
+ enableHcaptcha: boolean
+ hcaptchaSiteKey: string | null
+ hcaptchaSecretKey: string | null
+ objectStorageSetPublicRead: boolean
+ pinnedPages: Array
+ backgroundImageUrl: string | null
+ logoImageUrl: string | null
+ pinnedClipId: string | null
+ objectStorageS3ForcePathStyle: boolean
+ allowedHosts: Array | null
+ secureMode: boolean | null
+ privateMode: boolean | null
+ deeplAuthKey: string | null
+ deeplIsPro: boolean
+ emailRequiredForSignup: boolean
+ themeColor: string | null
+ defaultLightTheme: string | null
+ defaultDarkTheme: string | null
+ enableIpLogging: boolean
+ enableActiveEmailValidation: boolean
+ customMotd: Array
+ customSplashIcons: Array
+ disableRecommendedTimeline: boolean
+ recommendedInstances: Array
+ enableGuestTimeline: boolean
+ defaultReaction: string
+ libreTranslateApiUrl: string | null
+ libreTranslateApiKey: string | null
+ silencedHosts: Array
+ experimentalFeatures: Json
+ enableServerMachineStats: boolean
+ enableIdenticonGeneration: boolean
+ donationLink: string | null
+ moreUrls: Json
+ markLocalFilesNsfwByDefault: boolean
+}
+export interface Migrations {
+ id: number
+ timestamp: number
+ name: string
+}
+export interface ModerationLog {
+ id: string
+ createdAt: Date
+ userId: string
+ type: string
+ info: Json
+}
+export interface MutedNote {
+ id: string
+ noteId: string
+ userId: string
+ reason: MutedNoteReasonEnum
+}
+export interface Muting {
+ id: string
+ createdAt: Date
+ muteeId: string
+ muterId: string
+ expiresAt: Date | null
+}
+export interface Note {
+ id: string
+ createdAt: Date
+ replyId: string | null
+ renoteId: string | null
+ text: string | null
+ name: string | null
+ cw: string | null
+ userId: string
+ localOnly: boolean
+ renoteCount: number
+ repliesCount: number
+ reactions: Json
+ visibility: NoteVisibilityEnum
+ uri: string | null
+ score: number
+ fileIds: Array
+ attachedFileTypes: Array
+ visibleUserIds: Array
+ mentions: Array
+ mentionedRemoteUsers: string
+ emojis: Array
+ tags: Array
+ hasPoll: boolean
+ userHost: string | null
+ replyUserId: string | null
+ replyUserHost: string | null
+ renoteUserId: string | null
+ renoteUserHost: string | null
+ url: string | null
+ channelId: string | null
+ threadId: string | null
+ updatedAt: Date | null
+ lang: string | null
+}
+export interface NoteEdit {
+ id: string
+ noteId: string
+ text: string | null
+ cw: string | null
+ fileIds: Array
+ updatedAt: Date
+ emojis: Array
+}
+export interface NoteFavorite {
+ id: string
+ createdAt: Date
+ userId: string
+ noteId: string
+}
+export interface NoteFile {
+ serialNo: number
+ noteId: string
+ fileId: string
+}
+export interface NoteReaction {
+ id: string
+ createdAt: Date
+ userId: string
+ noteId: string
+ reaction: string
+}
+export interface NoteThreadMuting {
+ id: string
+ createdAt: Date
+ userId: string
+ threadId: string
+}
+export interface NoteUnread {
+ id: string
+ userId: string
+ noteId: string
+ noteUserId: string
+ isSpecified: boolean
+ isMentioned: boolean
+ noteChannelId: string | null
+}
+export interface NoteWatching {
+ id: string
+ createdAt: Date
+ userId: string
+ noteId: string
+ noteUserId: string
+}
+export interface Notification {
+ id: string
+ createdAt: Date
+ notifieeId: string
+ notifierId: string | null
+ isRead: boolean
+ noteId: string | null
+ reaction: string | null
+ choice: number | null
+ followRequestId: string | null
+ type: NotificationTypeEnum
+ userGroupInvitationId: string | null
+ customBody: string | null
+ customHeader: string | null
+ customIcon: string | null
+ appAccessTokenId: string | null
+}
+export interface Page {
+ id: string
+ createdAt: Date
+ updatedAt: Date
+ title: string
+ name: string
+ summary: string | null
+ alignCenter: boolean
+ font: string
+ userId: string
+ eyeCatchingImageId: string | null
+ content: Json
+ variables: Json
+ visibility: PageVisibilityEnum
+ visibleUserIds: Array
+ likedCount: number
+ hideTitleWhenPinned: boolean
+ script: string
+ isPublic: boolean
+}
+export interface PageLike {
+ id: string
+ createdAt: Date
+ userId: string
+ pageId: string
+}
+export interface PasswordResetRequest {
+ id: string
+ createdAt: Date
+ token: string
+ userId: string
+}
+export interface Poll {
+ noteId: string
+ expiresAt: Date | null
+ multiple: boolean
+ choices: Array
+ votes: Array
+ noteVisibility: PollNotevisibilityEnum
+ userId: string
+ userHost: string | null
+}
+export interface PollVote {
+ id: string
+ createdAt: Date
+ userId: string
+ noteId: string
+ choice: number
+}
+export interface PromoNote {
+ noteId: string
+ expiresAt: Date
+ userId: string
+}
+export interface PromoRead {
+ id: string
+ createdAt: Date
+ userId: string
+ noteId: string
+}
+export interface RegistrationTicket {
+ id: string
+ createdAt: Date
+ code: string
+}
+export interface RegistryItem {
+ id: string
+ createdAt: Date
+ updatedAt: Date
+ userId: string
+ key: string
+ scope: Array
+ domain: string | null
+ value: Json | null
+}
+export interface Relay {
+ id: string
+ inbox: string
+ status: RelayStatusEnum
+}
+export interface RenoteMuting {
+ id: string
+ createdAt: Date
+ muteeId: string
+ muterId: string
+}
+export interface ReplyMuting {
+ id: string
+ createdAt: Date
+ muteeId: string
+ muterId: string
+}
+export enum AntennaSrcEnum {
+ All = 'all',
+ Group = 'group',
+ Home = 'home',
+ Instances = 'instances',
+ List = 'list',
+ Users = 'users'
+}
+export enum DriveFileUsageHintEnum {
+ UserAvatar = 'userAvatar',
+ UserBanner = 'userBanner'
+}
+export enum MutedNoteReasonEnum {
+ Manual = 'manual',
+ Other = 'other',
+ Spam = 'spam',
+ Word = 'word'
+}
+export enum NoteVisibilityEnum {
+ Followers = 'followers',
+ Hidden = 'hidden',
+ Home = 'home',
+ Public = 'public',
+ Specified = 'specified'
+}
+export enum NotificationTypeEnum {
+ App = 'app',
+ Follow = 'follow',
+ FollowRequestAccepted = 'followRequestAccepted',
+ GroupInvited = 'groupInvited',
+ Mention = 'mention',
+ PollEnded = 'pollEnded',
+ PollVote = 'pollVote',
+ Quote = 'quote',
+ Reaction = 'reaction',
+ ReceiveFollowRequest = 'receiveFollowRequest',
+ Renote = 'renote',
+ Reply = 'reply'
+}
+export enum PageVisibilityEnum {
+ Followers = 'followers',
+ Public = 'public',
+ Specified = 'specified'
+}
+export enum PollNotevisibilityEnum {
+ Followers = 'followers',
+ Home = 'home',
+ Public = 'public',
+ Specified = 'specified'
+}
+export enum RelayStatusEnum {
+ Accepted = 'accepted',
+ Rejected = 'rejected',
+ Requesting = 'requesting'
+}
+export enum UserEmojimodpermEnum {
+ Add = 'add',
+ Full = 'full',
+ Mod = 'mod',
+ Unauthorized = 'unauthorized'
+}
+export enum UserProfileFfvisibilityEnum {
+ Followers = 'followers',
+ Private = 'private',
+ Public = 'public'
+}
+export enum UserProfileMutingnotificationtypesEnum {
+ App = 'app',
+ Follow = 'follow',
+ FollowRequestAccepted = 'followRequestAccepted',
+ GroupInvited = 'groupInvited',
+ Mention = 'mention',
+ PollEnded = 'pollEnded',
+ PollVote = 'pollVote',
+ Quote = 'quote',
+ Reaction = 'reaction',
+ ReceiveFollowRequest = 'receiveFollowRequest',
+ Renote = 'renote',
+ Reply = 'reply'
+}
+export interface Signin {
+ id: string
+ createdAt: Date
+ userId: string
+ ip: string
+ headers: Json
+ success: boolean
+}
+export interface SwSubscription {
+ id: string
+ createdAt: Date
+ userId: string
+ endpoint: string
+ auth: string
+ publickey: string
+ sendReadMessage: boolean
+}
+export interface UsedUsername {
+ username: string
+ createdAt: Date
+}
+export interface User {
+ id: string
+ createdAt: Date
+ updatedAt: Date | null
+ lastFetchedAt: Date | null
+ username: string
+ usernameLower: string
+ name: string | null
+ followersCount: number
+ followingCount: number
+ notesCount: number
+ avatarId: string | null
+ bannerId: string | null
+ tags: Array
+ isSuspended: boolean
+ isSilenced: boolean
+ isLocked: boolean
+ isBot: boolean
+ isCat: boolean
+ isAdmin: boolean
+ isModerator: boolean
+ emojis: Array
+ host: string | null
+ inbox: string | null
+ sharedInbox: string | null
+ featured: string | null
+ uri: string | null
+ token: string | null
+ isExplorable: boolean
+ followersUri: string | null
+ lastActiveDate: Date | null
+ hideOnlineStatus: boolean
+ isDeleted: boolean
+ driveCapacityOverrideMb: number | null
+ movedToUri: string | null
+ alsoKnownAs: string | null
+ speakAsCat: boolean
+ emojiModPerm: UserEmojimodpermEnum
+ isIndexable: boolean
+}
+export interface UserGroup {
+ id: string
+ createdAt: Date
+ name: string
+ userId: string
+ isPrivate: boolean
+}
+export interface UserGroupInvitation {
+ id: string
+ createdAt: Date
+ userId: string
+ userGroupId: string
+}
+export interface UserGroupInvite {
+ id: string
+ createdAt: Date
+ userId: string
+ userGroupId: string
+}
+export interface UserGroupJoining {
+ id: string
+ createdAt: Date
+ userId: string
+ userGroupId: string
+}
+export interface UserIp {
+ id: number
+ createdAt: Date
+ userId: string
+ ip: string
+}
+export interface UserKeypair {
+ userId: string
+ publicKey: string
+ privateKey: string
+}
+export interface UserList {
+ id: string
+ createdAt: Date
+ userId: string
+ name: string
+}
+export interface UserListJoining {
+ id: string
+ createdAt: Date
+ userId: string
+ userListId: string
+}
+export interface UserNotePining {
+ id: string
+ createdAt: Date
+ userId: string
+ noteId: string
+}
+export interface UserPending {
+ id: string
+ createdAt: Date
+ code: string
+ username: string
+ email: string
+ password: string
+}
+export interface UserProfile {
+ userId: string
+ location: string | null
+ birthday: string | null
+ description: string | null
+ fields: Json
+ url: string | null
+ email: string | null
+ emailVerifyCode: string | null
+ emailVerified: boolean
+ twoFactorTempSecret: string | null
+ twoFactorSecret: string | null
+ twoFactorEnabled: boolean
+ password: string | null
+ clientData: Json
+ autoAcceptFollowed: boolean
+ alwaysMarkNsfw: boolean
+ carefulBot: boolean
+ userHost: string | null
+ securityKeysAvailable: boolean
+ usePasswordLessLogin: boolean
+ pinnedPageId: string | null
+ room: Json
+ injectFeaturedNote: boolean
+ enableWordMute: boolean
+ mutedWords: Json
+ mutingNotificationTypes: Array
+ noCrawle: boolean
+ receiveAnnouncementEmail: boolean
+ emailNotificationTypes: Json
+ mutedInstances: Json
+ publicReactions: boolean
+ ffVisibility: UserProfileFfvisibilityEnum
+ moderationNote: string
+ preventAiLearning: boolean
+ isIndexable: boolean
+ mutedPatterns: Array
+}
+export interface UserPublickey {
+ userId: string
+ keyId: string
+ keyPem: string
+}
+export interface UserSecurityKey {
+ id: string
+ userId: string
+ publicKey: string
+ lastUsed: Date
+ name: string
+}
+export interface Webhook {
+ id: string
+ createdAt: Date
+ userId: string
+ name: string
+ on: Array
+ url: string
+ secret: string
+ active: boolean
+ latestSentAt: Date | null
+ latestStatus: number | null
+}
+/** Initializes Cuid2 generator. Must be called before any [create_id]. */
+export function initIdGenerator(length: number, fingerprint: string): void
+export function getTimestamp(id: string): number
+/**
+ * The generated ID results in the form of `[8 chars timestamp] + [cuid2]`.
+ * The minimum and maximum lengths are 16 and 24, respectively.
+ * With the length of 16, namely 8 for cuid2, roughly 1427399 IDs are needed
+ * in the same millisecond to reach 50% chance of collision.
+ *
+ * Ref: https://github.com/paralleldrive/cuid2#parameterized-length
+ */
+export function genId(date?: Date | undefined | null): string
+export function secureRndstr(length?: number | undefined | null): string
diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js
index 94960878f3..6d64f6ec75 100644
--- a/packages/backend-rs/index.js
+++ b/packages/backend-rs/index.js
@@ -224,17 +224,32 @@ switch (platform) {
}
break
case 'arm':
- localFileExisted = existsSync(
- join(__dirname, 'backend-rs.linux-arm-gnueabihf.node')
- )
- try {
- if (localFileExisted) {
- nativeBinding = require('./backend-rs.linux-arm-gnueabihf.node')
- } else {
- nativeBinding = require('backend-rs-linux-arm-gnueabihf')
+ if (isMusl()) {
+ localFileExisted = existsSync(
+ join(__dirname, 'backend-rs.linux-arm-musleabihf.node')
+ )
+ try {
+ if (localFileExisted) {
+ nativeBinding = require('./backend-rs.linux-arm-musleabihf.node')
+ } else {
+ nativeBinding = require('backend-rs-linux-arm-musleabihf')
+ }
+ } catch (e) {
+ loadError = e
+ }
+ } else {
+ localFileExisted = existsSync(
+ join(__dirname, 'backend-rs.linux-arm-gnueabihf.node')
+ )
+ try {
+ if (localFileExisted) {
+ nativeBinding = require('./backend-rs.linux-arm-gnueabihf.node')
+ } else {
+ nativeBinding = require('backend-rs-linux-arm-gnueabihf')
+ }
+ } catch (e) {
+ loadError = e
}
- } catch (e) {
- loadError = e
}
break
case 'riscv64':
@@ -295,11 +310,46 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}
-const { nativeRandomStr, IdConvertType, convertId, nativeGetTimestamp, nativeCreateId, nativeInitIdGenerator } = nativeBinding
+const { readEnvironmentConfig, readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getNoteSummary, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
-module.exports.nativeRandomStr = nativeRandomStr
-module.exports.IdConvertType = IdConvertType
-module.exports.convertId = convertId
-module.exports.nativeGetTimestamp = nativeGetTimestamp
-module.exports.nativeCreateId = nativeCreateId
-module.exports.nativeInitIdGenerator = nativeInitIdGenerator
+module.exports.readEnvironmentConfig = readEnvironmentConfig
+module.exports.readServerConfig = readServerConfig
+module.exports.stringToAcct = stringToAcct
+module.exports.acctToString = acctToString
+module.exports.checkWordMute = checkWordMute
+module.exports.getFullApAccount = getFullApAccount
+module.exports.isSelfHost = isSelfHost
+module.exports.isSameOrigin = isSameOrigin
+module.exports.extractHost = extractHost
+module.exports.toPuny = toPuny
+module.exports.isUnicodeEmoji = isUnicodeEmoji
+module.exports.sqlLikeEscape = sqlLikeEscape
+module.exports.safeForSql = safeForSql
+module.exports.formatMilliseconds = formatMilliseconds
+module.exports.getNoteSummary = getNoteSummary
+module.exports.toMastodonId = toMastodonId
+module.exports.fromMastodonId = fromMastodonId
+module.exports.fetchMeta = fetchMeta
+module.exports.metaToPugArgs = metaToPugArgs
+module.exports.nyaify = nyaify
+module.exports.hashPassword = hashPassword
+module.exports.verifyPassword = verifyPassword
+module.exports.isOldPasswordAlgorithm = isOldPasswordAlgorithm
+module.exports.decodeReaction = decodeReaction
+module.exports.countReactions = countReactions
+module.exports.toDbReaction = toDbReaction
+module.exports.AntennaSrcEnum = AntennaSrcEnum
+module.exports.DriveFileUsageHintEnum = DriveFileUsageHintEnum
+module.exports.MutedNoteReasonEnum = MutedNoteReasonEnum
+module.exports.NoteVisibilityEnum = NoteVisibilityEnum
+module.exports.NotificationTypeEnum = NotificationTypeEnum
+module.exports.PageVisibilityEnum = PageVisibilityEnum
+module.exports.PollNotevisibilityEnum = PollNotevisibilityEnum
+module.exports.RelayStatusEnum = RelayStatusEnum
+module.exports.UserEmojimodpermEnum = UserEmojimodpermEnum
+module.exports.UserProfileFfvisibilityEnum = UserProfileFfvisibilityEnum
+module.exports.UserProfileMutingnotificationtypesEnum = UserProfileMutingnotificationtypesEnum
+module.exports.initIdGenerator = initIdGenerator
+module.exports.getTimestamp = getTimestamp
+module.exports.genId = genId
+module.exports.secureRndstr = secureRndstr
diff --git a/packages/backend-rs/package.json b/packages/backend-rs/package.json
index 6cc295dac4..1f3f49e9fb 100644
--- a/packages/backend-rs/package.json
+++ b/packages/backend-rs/package.json
@@ -22,7 +22,7 @@
}
},
"devDependencies": {
- "@napi-rs/cli": "2.18.0",
+ "@napi-rs/cli": "2.18.1",
"ava": "6.1.2"
},
"ava": {
@@ -33,14 +33,12 @@
},
"scripts": {
"artifacts": "napi artifacts",
- "build": "napi build --features napi --platform --release ./built/",
- "build:debug": "napi build --features napi --platform ./built/",
+ "build": "napi build --features napi --no-const-enum --platform --release ./built/",
+ "build:debug": "napi build --features napi --no-const-enum --platform ./built/",
"prepublishOnly": "napi prepublish -t npm",
"test": "pnpm run cargo:test && pnpm run build:debug && ava",
"universal": "napi universal",
"version": "napi version",
- "format": "cargo fmt --all --",
- "lint": "cargo clippy --fix --allow-dirty --allow-staged && cargo fmt --all --",
"cargo:test": "pnpm run cargo:unit && pnpm run cargo:integration",
"cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
"cargo:integration": "cargo test int_test"
diff --git a/packages/backend-rs/src/config/environment.rs b/packages/backend-rs/src/config/environment.rs
new file mode 100644
index 0000000000..7d66aec7ba
--- /dev/null
+++ b/packages/backend-rs/src/config/environment.rs
@@ -0,0 +1,27 @@
+// FIXME: Are these options used?
+#[crate::export(object)]
+pub struct EnvConfig {
+ pub only_queue: bool,
+ pub only_server: bool,
+ pub no_daemons: bool,
+ pub disable_clustering: bool,
+ pub verbose: bool,
+ pub with_log_time: bool,
+ pub slow: bool,
+}
+
+#[crate::export]
+pub fn read_environment_config() -> EnvConfig {
+ let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase();
+ let is_testing = node_env == "test";
+
+ EnvConfig {
+ only_queue: std::env::var("MK_ONLY_QUEUE").is_ok(),
+ only_server: std::env::var("MK_ONLY_SERVER").is_ok(),
+ no_daemons: is_testing || std::env::var("MK_NO_DAEMONS").is_ok(),
+ disable_clustering: is_testing || std::env::var("MK_DISABLE_CLUSTERING").is_ok(),
+ verbose: std::env::var("MK_VERBOSE").is_ok(),
+ with_log_time: std::env::var("MK_WITH_LOG_TIME").is_ok(),
+ slow: std::env::var("MK_SLOW").is_ok(),
+ }
+}
diff --git a/packages/backend-rs/src/config/mod.rs b/packages/backend-rs/src/config/mod.rs
new file mode 100644
index 0000000000..b708f2b265
--- /dev/null
+++ b/packages/backend-rs/src/config/mod.rs
@@ -0,0 +1,2 @@
+pub mod environment;
+pub mod server;
diff --git a/packages/backend-rs/src/config/server.rs b/packages/backend-rs/src/config/server.rs
new file mode 100644
index 0000000000..125bae90b9
--- /dev/null
+++ b/packages/backend-rs/src/config/server.rs
@@ -0,0 +1,183 @@
+use once_cell::sync::Lazy;
+use serde::Deserialize;
+use std::env;
+use std::fs;
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct ServerConfig {
+ pub url: String,
+ pub port: u16,
+ /// host to listen on
+ pub bind: Option,
+ pub disable_hsts: Option,
+
+ pub db: DbConfig,
+ pub redis: RedisConfig,
+ pub cache_server: Option,
+
+ pub proxy: Option,
+ pub proxy_smtp: Option,
+ pub proxy_bypass_hosts: Option>,
+
+ pub allowed_private_networks: Option>,
+ /// `NapiValue` is not implemented for `u64`
+ pub max_file_size: Option,
+ pub access_log: Option,
+ pub cluster_limits: Option,
+ pub cuid: Option,
+ pub outgoing_address: Option,
+
+ pub deliver_job_concurrency: Option,
+ pub inbox_job_concurrency: Option,
+ pub deliver_job_per_sec: Option,
+ pub inbox_job_per_sec: Option,
+ pub deliver_job_max_attempts: Option,
+ pub inbox_job_max_attempts: Option,
+
+ pub log_level: Option>,
+
+ pub syslog: Option,
+
+ pub proxy_remote_files: Option,
+ pub media_proxy: Option,
+ pub summaly_proxy_url: Option,
+
+ pub reserved_usernames: Option>,
+
+ pub max_user_signups: Option,
+ pub is_managed_hosting: Option,
+ pub max_note_length: Option,
+ pub max_caption_length: Option,
+
+ pub deepl: Option,
+ pub libre_translate: Option,
+ pub email: Option,
+ pub object_storage: Option,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct DbConfig {
+ pub host: String,
+ pub port: u16,
+ pub db: String,
+ pub user: String,
+ pub pass: String,
+ pub disable_cache: Option,
+ pub extra: Option,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct RedisConfig {
+ pub host: String,
+ pub port: u16,
+ pub family: Option,
+ pub user: Option,
+ pub pass: Option,
+ pub tls: Option,
+ #[serde(default)]
+ pub db: u32,
+ #[serde(default)]
+ pub prefix: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct TlsConfig {
+ pub host: String,
+ pub reject_unauthorized: bool,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct WorkerConfig {
+ pub web: Option,
+ pub queue: Option,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct IdConfig {
+ pub length: Option,
+ pub fingerprint: Option,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct SysLogConfig {
+ pub host: String,
+ pub port: u16,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct DeepLConfig {
+ pub managed: Option,
+ pub auth_key: Option,
+ pub is_pro: Option,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct LibreTranslateConfig {
+ pub managed: Option,
+ pub api_url: Option,
+ pub api_key: Option,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct EmailConfig {
+ pub managed: Option,
+ pub address: Option,
+ pub host: Option,
+ pub port: Option,
+ pub user: Option,
+ pub pass: Option,
+ pub use_implicit_ssl_tls: Option,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct ObjectStorageConfig {
+ pub managed: Option,
+ pub base_url: Option,
+ pub bucket: Option,
+ pub prefix: Option,
+ pub endpoint: Option,
+ pub region: Option,
+ pub access_key: Option,
+ pub secret_key: Option,
+ pub use_ssl: Option,
+ pub connnect_over_proxy: Option,
+ pub set_public_read_on_upload: Option,
+ pub s3_force_path_style: Option,
+}
+
+#[crate::export]
+pub fn read_server_config() -> ServerConfig {
+ let cwd = env::current_dir().unwrap();
+ let yml = fs::File::open(cwd.join("../../.config/default.yml"))
+ .expect("Failed to open '.config/default.yml'");
+ let mut data: ServerConfig = serde_yaml::from_reader(yml).expect("Failed to parse yaml");
+ data.url = url::Url::parse(&data.url)
+ .expect("Config url is invalid")
+ .origin()
+ .ascii_serialization();
+ data
+}
+
+pub static SERVER_CONFIG: Lazy = Lazy::new(read_server_config);
diff --git a/packages/backend-rs/src/database/error.rs b/packages/backend-rs/src/database/error.rs
deleted file mode 100644
index 68e959e0af..0000000000
--- a/packages/backend-rs/src/database/error.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use sea_orm::error::DbErr;
-
-use crate::impl_into_napi_error;
-
-#[derive(thiserror::Error, Debug, PartialEq, Eq)]
-pub enum Error {
- #[error("The database connections have not been initialized yet")]
- Uninitialized,
- #[error("ORM error: {0}")]
- OrmError(#[from] DbErr),
-}
-
-impl_into_napi_error!(Error);
diff --git a/packages/backend-rs/src/database/mod.rs b/packages/backend-rs/src/database/mod.rs
index 739f39bb64..f598e35cc7 100644
--- a/packages/backend-rs/src/database/mod.rs
+++ b/packages/backend-rs/src/database/mod.rs
@@ -1,26 +1,34 @@
-pub mod error;
-
-use error::Error;
-use sea_orm::{Database, DbConn};
+use crate::config::server::SERVER_CONFIG;
+use sea_orm::{Database, DbConn, DbErr};
static DB_CONN: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new();
-pub async fn init_database(conn_uri: impl Into) -> Result<(), Error> {
- let conn = Database::connect(conn_uri.into()).await?;
- DB_CONN.get_or_init(move || conn);
- Ok(())
+async fn init_database() -> Result<&'static DbConn, DbErr> {
+ let database_uri = format!(
+ "postgres://{}:{}@{}:{}/{}",
+ SERVER_CONFIG.db.user,
+ urlencoding::encode(&SERVER_CONFIG.db.pass),
+ SERVER_CONFIG.db.host,
+ SERVER_CONFIG.db.port,
+ SERVER_CONFIG.db.db,
+ );
+ let conn = Database::connect(database_uri).await?;
+ Ok(DB_CONN.get_or_init(move || conn))
}
-pub fn get_database() -> Result<&'static DbConn, Error> {
- DB_CONN.get().ok_or(Error::Uninitialized)
+pub async fn db_conn() -> Result<&'static DbConn, DbErr> {
+ match DB_CONN.get() {
+ Some(conn) => Ok(conn),
+ None => init_database().await,
+ }
}
#[cfg(test)]
mod unit_test {
- use super::{error::Error, get_database};
+ use super::db_conn;
- #[test]
- fn error_uninitialized() {
- assert_eq!(get_database().unwrap_err(), Error::Uninitialized);
+ #[tokio::test]
+ async fn connect_test() {
+ assert!(db_conn().await.is_ok());
}
}
diff --git a/packages/backend-rs/src/lib.rs b/packages/backend-rs/src/lib.rs
index f18e69a48f..bef7a41808 100644
--- a/packages/backend-rs/src/lib.rs
+++ b/packages/backend-rs/src/lib.rs
@@ -1,7 +1,7 @@
+pub use macro_rs::export;
+
+pub mod config;
pub mod database;
-pub mod macros;
+pub mod misc;
pub mod model;
pub mod util;
-
-#[cfg(feature = "napi")]
-pub mod mastodon_api;
diff --git a/packages/backend-rs/src/macros.rs b/packages/backend-rs/src/macros.rs
deleted file mode 100644
index 49ab826329..0000000000
--- a/packages/backend-rs/src/macros.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#[macro_export]
-macro_rules! impl_into_napi_error {
- ($a:ty) => {
- #[cfg(feature = "napi")]
- impl Into for $a {
- fn into(self) -> napi::Error {
- napi::Error::from_reason(self.to_string())
- }
- }
- };
-}
diff --git a/packages/backend-rs/src/mastodon_api.rs b/packages/backend-rs/src/mastodon_api.rs
deleted file mode 100644
index 61ee4018af..0000000000
--- a/packages/backend-rs/src/mastodon_api.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use napi::{Error, Status};
-use napi_derive::napi;
-
-static CHAR_COLLECTION: &str = "0123456789abcdefghijklmnopqrstuvwxyz";
-
-// -- NAPI exports --
-
-#[napi]
-pub enum IdConvertType {
- MastodonId,
- FirefishId,
-}
-
-#[napi]
-pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result {
- use IdConvertType::*;
- match id_convert_type {
- MastodonId => {
- let mut out: i128 = 0;
- for (i, c) in in_id.to_lowercase().chars().rev().enumerate() {
- out += num_from_char(c)? as i128 * 36_i128.pow(i as u32);
- }
-
- Ok(out.to_string())
- }
- FirefishId => {
- let mut input: i128 = match in_id.parse() {
- Ok(s) => s,
- Err(_) => {
- return Err(Error::new(
- Status::InvalidArg,
- "Unable to parse ID as MastodonId",
- ))
- }
- };
- let mut out = String::new();
-
- while input != 0 {
- out.insert(0, char_from_num((input % 36) as u8)?);
- input /= 36;
- }
-
- Ok(out)
- }
- }
-}
-
-// -- end --
-
-#[inline(always)]
-fn num_from_char(character: char) -> napi::Result {
- for (i, c) in CHAR_COLLECTION.chars().enumerate() {
- if c == character {
- return Ok(i as u8);
- }
- }
-
- Err(Error::new(
- Status::InvalidArg,
- "Invalid character in parsed base36 id",
- ))
-}
-
-#[inline(always)]
-fn char_from_num(number: u8) -> napi::Result {
- CHAR_COLLECTION
- .chars()
- .nth(number as usize)
- .ok_or(Error::from_status(Status::Unknown))
-}
diff --git a/packages/backend-rs/src/misc/acct.rs b/packages/backend-rs/src/misc/acct.rs
new file mode 100644
index 0000000000..6dcb4f9a74
--- /dev/null
+++ b/packages/backend-rs/src/misc/acct.rs
@@ -0,0 +1,74 @@
+#[derive(Debug, PartialEq)]
+#[crate::export(object)]
+pub struct Acct {
+ pub username: String,
+ pub host: Option,
+}
+
+#[crate::export]
+pub fn string_to_acct(acct: &str) -> Acct {
+ let split: Vec<&str> = if let Some(stripped) = acct.strip_prefix('@') {
+ stripped
+ } else {
+ acct
+ }
+ .split('@')
+ .collect();
+
+ Acct {
+ username: split[0].to_string(),
+ host: if split.len() == 1 {
+ None
+ } else {
+ Some(split[1].to_string())
+ },
+ }
+}
+
+#[crate::export]
+pub fn acct_to_string(acct: &Acct) -> String {
+ match &acct.host {
+ Some(host) => format!("{}@{}", acct.username, host),
+ None => acct.username.clone(),
+ }
+}
+
+#[cfg(test)]
+mod unit_test {
+ use super::{acct_to_string, string_to_acct, Acct};
+ use pretty_assertions::assert_eq;
+
+ #[test]
+ fn test_acct_to_string() {
+ let remote_acct = Acct {
+ username: "firefish".to_string(),
+ host: Some("example.com".to_string()),
+ };
+ let local_acct = Acct {
+ username: "MisakaMikoto".to_string(),
+ host: None,
+ };
+
+ assert_eq!(acct_to_string(&remote_acct), "firefish@example.com");
+ assert_ne!(acct_to_string(&remote_acct), "mastodon@example.com");
+ assert_eq!(acct_to_string(&local_acct), "MisakaMikoto");
+ assert_ne!(acct_to_string(&local_acct), "ShiraiKuroko");
+ }
+
+ #[test]
+ fn test_string_to_acct() {
+ let remote_acct = Acct {
+ username: "firefish".to_string(),
+ host: Some("example.com".to_string()),
+ };
+ let local_acct = Acct {
+ username: "MisakaMikoto".to_string(),
+ host: None,
+ };
+
+ assert_eq!(string_to_acct("@firefish@example.com"), remote_acct);
+ assert_eq!(string_to_acct("firefish@example.com"), remote_acct);
+ assert_eq!(string_to_acct("@MisakaMikoto"), local_acct);
+ assert_eq!(string_to_acct("MisakaMikoto"), local_acct);
+ }
+}
diff --git a/packages/backend-rs/src/misc/check_word_mute.rs b/packages/backend-rs/src/misc/check_word_mute.rs
new file mode 100644
index 0000000000..18b550c29b
--- /dev/null
+++ b/packages/backend-rs/src/misc/check_word_mute.rs
@@ -0,0 +1,118 @@
+use crate::database::db_conn;
+use crate::model::entity::{drive_file, note};
+use once_cell::sync::Lazy;
+use regex::Regex;
+use sea_orm::{prelude::*, QuerySelect};
+
+/// TODO: handle name collisions better
+#[crate::export(object, js_name = "NoteLikeForCheckWordMute")]
+pub struct NoteLike {
+ pub file_ids: Vec,
+ pub user_id: Option,
+ pub text: Option,
+ pub cw: Option,
+ pub renote_id: Option,
+ pub reply_id: Option,
+}
+
+async fn all_texts(note: NoteLike) -> Result, DbErr> {
+ let db = db_conn().await?;
+
+ let mut texts: Vec = vec![];
+
+ if let Some(text) = note.text {
+ texts.push(text);
+ }
+ if let Some(cw) = note.cw {
+ texts.push(cw);
+ }
+
+ texts.extend(
+ drive_file::Entity::find()
+ .select_only()
+ .column(drive_file::Column::Comment)
+ .filter(drive_file::Column::Id.is_in(note.file_ids))
+ .into_tuple::