mirror of https://github.com/kitsune-soc/kitsune
Compare commits
11 Commits
2f364c2313
...
7e1e2a2237
Author | SHA1 | Date |
---|---|---|
Aumetra Weisman | 7e1e2a2237 | |
Aumetra Weisman | 9018f05404 | |
vesdev | 987f151441 | |
Aumetra Weisman | 4e9c8293fe | |
Aumetra Weisman | 5f0ef5b676 | |
Aumetra Weisman | 5e5e746348 | |
Aumetra Weisman | 208c90c611 | |
Aumetra Weisman | 748c4f7f01 | |
Aumetra Weisman | 41b777c9ef | |
Aumetra Weisman | 9911cc0658 | |
Aumetra Weisman | 03e8ca3cf9 |
File diff suppressed because it is too large
Load Diff
|
@ -25,6 +25,8 @@ members = [
|
|||
"crates/kitsune-config",
|
||||
"crates/kitsune-core",
|
||||
"crates/kitsune-db",
|
||||
"crates/kitsune-derive",
|
||||
"crates/kitsune-derive/impl",
|
||||
"crates/kitsune-email",
|
||||
"crates/kitsune-embed",
|
||||
"crates/kitsune-error",
|
||||
|
@ -122,3 +124,4 @@ install-updater = true
|
|||
|
||||
[patch.crates-io]
|
||||
diesel-async = { git = "https://github.com/weiznich/diesel_async.git", rev = "d02798c67065d763154d7272dd0c09b39757d0f2" }
|
||||
scraper = { git = "https://github.com/causal-agent/scraper.git", rev = "d67111f5cc0b7da6e6ff10e4549d87cf09ba3e5b" }
|
||||
|
|
|
@ -155,15 +155,10 @@ path = "./mrf-storage"
|
|||
|
||||
# OpenTelemetry configuration
|
||||
#
|
||||
# Kitsune supports exporting traces and metrics via the OpenTelemetry Protocol (OTLP, for short)
|
||||
# Kitsune supports exporting traces via the OpenTelemetry Protocol (OTLP, for short)
|
||||
# It's by now the de-facto standard wire protocol for exporting telemetry data
|
||||
#
|
||||
# As of now, you can only export all data to a single endpoint.
|
||||
# This configuration might become more granular in the future.
|
||||
#
|
||||
#[opentelemetry]
|
||||
#metrics-transport = "http" # "grpc" or "http"
|
||||
#metrics-endpoint = "http://localhost:4317"
|
||||
#tracing-transport = "http" # "grpc" or "http"
|
||||
#tracing-endpoint = "http://localhost:4317"
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ license.workspace = true
|
|||
|
||||
[dependencies]
|
||||
async-trait = "0.1.80"
|
||||
autometrics = { version = "1.0.1", default-features = false }
|
||||
base64-simd = "0.8.0"
|
||||
diesel = "2.1.6"
|
||||
diesel-async = "0.4.1"
|
||||
|
@ -37,6 +36,7 @@ sha2 = "0.10.8"
|
|||
simd-json = "0.13.10"
|
||||
speedy-uuid = { path = "../../lib/speedy-uuid" }
|
||||
tracing = "0.1.40"
|
||||
triomphe = "0.1.11"
|
||||
typed-builder = "0.18.2"
|
||||
url = "2.5.0"
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use autometrics::autometrics;
|
||||
use futures_util::{stream::FuturesUnordered, Stream, StreamExt};
|
||||
use http::{Method, Request};
|
||||
use kitsune_core::consts::USER_AGENT;
|
||||
|
@ -26,7 +25,6 @@ pub struct Deliverer {
|
|||
|
||||
impl Deliverer {
|
||||
/// Deliver the activity to an inbox
|
||||
#[autometrics(track_concurrency)]
|
||||
#[instrument(skip_all, fields(%inbox_url, activity_url = %activity.id))]
|
||||
pub async fn deliver(
|
||||
&self,
|
||||
|
|
|
@ -21,7 +21,7 @@ use kitsune_service::attachment::AttachmentService;
|
|||
use kitsune_type::ap::{ap_context, Activity, ActivityType, ObjectField};
|
||||
use kitsune_url::UrlService;
|
||||
use kitsune_util::try_join;
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
pub mod core;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use super::Fetcher;
|
||||
use crate::process_attachments;
|
||||
use autometrics::autometrics;
|
||||
use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, SelectableHelper};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use kitsune_cache::CacheBackend;
|
||||
|
@ -23,7 +22,6 @@ impl Fetcher {
|
|||
///
|
||||
/// - Panics if the URL doesn't contain a host section
|
||||
#[instrument(skip(self))]
|
||||
#[autometrics(track_concurrency)]
|
||||
pub(crate) async fn fetch_actor(
|
||||
&self,
|
||||
opts: AccountFetchOptions<'_>,
|
||||
|
|
|
@ -6,6 +6,7 @@ use kitsune_config::language_detection::Configuration as LanguageDetectionConfig
|
|||
use kitsune_core::{
|
||||
consts::USER_AGENT,
|
||||
traits::{
|
||||
coerce::CoerceResolver,
|
||||
fetcher::{AccountFetchOptions, PostFetchOptions},
|
||||
Fetcher as FetcherTrait, Resolver,
|
||||
},
|
||||
|
@ -21,7 +22,7 @@ use kitsune_http_client::Client;
|
|||
use kitsune_type::jsonld::RdfNode;
|
||||
use mime::Mime;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
use url::Url;
|
||||
|
||||
|
@ -120,7 +121,7 @@ impl Fetcher {
|
|||
#[async_trait]
|
||||
impl FetcherTrait for Fetcher {
|
||||
fn resolver(&self) -> Arc<dyn Resolver> {
|
||||
Arc::new(self.resolver.clone())
|
||||
Arc::new(self.resolver.clone()).coerce()
|
||||
}
|
||||
|
||||
async fn fetch_account(&self, opts: AccountFetchOptions<'_>) -> Result<Option<Account>> {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use super::Fetcher;
|
||||
use crate::{process_new_object, ProcessNewObject};
|
||||
use autometrics::autometrics;
|
||||
use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, SelectableHelper};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use kitsune_cache::CacheBackend;
|
||||
|
@ -13,7 +12,6 @@ pub const MAX_FETCH_DEPTH: u32 = 15;
|
|||
|
||||
impl Fetcher {
|
||||
#[instrument(skip(self))]
|
||||
#[autometrics(track_concurrency)]
|
||||
pub(crate) async fn fetch_object(&self, url: &str, call_depth: u32) -> Result<Option<Post>> {
|
||||
if call_depth > MAX_FETCH_DEPTH {
|
||||
return Ok(None);
|
||||
|
|
|
@ -4,7 +4,7 @@ use diesel_async::RunQueryDsl;
|
|||
use kitsune_activitypub::Fetcher;
|
||||
use kitsune_cache::NoopCache;
|
||||
use kitsune_config::instance::FederationFilterConfiguration;
|
||||
use kitsune_core::traits::Fetcher as _;
|
||||
use kitsune_core::traits::{coerce::CoerceResolver, Fetcher as _};
|
||||
use kitsune_db::{
|
||||
model::{account::Account, media_attachment::MediaAttachment},
|
||||
schema::{accounts, media_attachments},
|
||||
|
@ -16,8 +16,8 @@ use kitsune_search::NoopSearchService;
|
|||
use kitsune_test::{database_test, language_detection_config};
|
||||
use kitsune_webfinger::Webfinger;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::sync::Arc;
|
||||
use tower::service_fn;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_actor() {
|
||||
|
@ -36,10 +36,7 @@ async fn fetch_actor() {
|
|||
)
|
||||
.language_detection_config(language_detection_config())
|
||||
.search_backend(NoopSearchService)
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.account_cache(Arc::new(NoopCache.into()))
|
||||
.post_cache(Arc::new(NoopCache.into()))
|
||||
.build();
|
||||
|
@ -78,7 +75,7 @@ async fn fetch_emoji() {
|
|||
)
|
||||
.language_detection_config(language_detection_config())
|
||||
.search_backend(NoopSearchService)
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.account_cache(Arc::new(NoopCache.into()))
|
||||
.post_cache(Arc::new(NoopCache.into()))
|
||||
.build();
|
||||
|
@ -129,10 +126,7 @@ async fn fetch_note() {
|
|||
)
|
||||
.language_detection_config(language_detection_config())
|
||||
.search_backend(NoopSearchService)
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.account_cache(Arc::new(NoopCache.into()))
|
||||
.post_cache(Arc::new(NoopCache.into()))
|
||||
.build();
|
||||
|
|
|
@ -4,14 +4,15 @@ use hyper::{body::Bytes, Request, Response};
|
|||
use kitsune_activitypub::Fetcher;
|
||||
use kitsune_cache::NoopCache;
|
||||
use kitsune_config::instance::FederationFilterConfiguration;
|
||||
use kitsune_core::traits::Fetcher as _;
|
||||
use kitsune_core::traits::{coerce::CoerceResolver, Fetcher as _};
|
||||
use kitsune_federation_filter::FederationFilter;
|
||||
use kitsune_http_client::Client;
|
||||
use kitsune_search::NoopSearchService;
|
||||
use kitsune_test::{assert_display_eq, database_test, language_detection_config};
|
||||
use kitsune_webfinger::Webfinger;
|
||||
use std::{convert::Infallible, sync::Arc};
|
||||
use std::convert::Infallible;
|
||||
use tower::service_fn;
|
||||
use triomphe::Arc;
|
||||
|
||||
macro_rules! assert_blocked {
|
||||
($error:expr) => {
|
||||
|
@ -46,10 +47,7 @@ async fn federation_allow() {
|
|||
.clone()
|
||||
.client(client.clone())
|
||||
.language_detection_config(language_detection_config())
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.build();
|
||||
|
||||
assert_blocked!(fetcher
|
||||
|
@ -67,10 +65,7 @@ async fn federation_allow() {
|
|||
.clone()
|
||||
.client(client.clone())
|
||||
.language_detection_config(language_detection_config())
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.build();
|
||||
|
||||
assert!(matches!(
|
||||
|
@ -106,10 +101,7 @@ async fn federation_deny() {
|
|||
)
|
||||
.language_detection_config(language_detection_config())
|
||||
.search_backend(NoopSearchService)
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.account_cache(Arc::new(NoopCache.into()))
|
||||
.post_cache(Arc::new(NoopCache.into()))
|
||||
.build();
|
||||
|
|
|
@ -4,7 +4,7 @@ use iso8601_timestamp::Timestamp;
|
|||
use kitsune_activitypub::{fetcher::MAX_FETCH_DEPTH, Fetcher};
|
||||
use kitsune_cache::NoopCache;
|
||||
use kitsune_config::instance::FederationFilterConfiguration;
|
||||
use kitsune_core::traits::Fetcher as _;
|
||||
use kitsune_core::traits::{coerce::CoerceResolver, Fetcher as _};
|
||||
use kitsune_federation_filter::FederationFilter;
|
||||
use kitsune_http_client::Client;
|
||||
use kitsune_search::NoopSearchService;
|
||||
|
@ -16,12 +16,10 @@ use kitsune_type::ap::{
|
|||
use kitsune_webfinger::Webfinger;
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
sync::{
|
||||
atomic::{AtomicU32, Ordering},
|
||||
Arc,
|
||||
},
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
use tower::service_fn;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_infinitely_long_reply_chain() {
|
||||
|
@ -104,7 +102,7 @@ async fn fetch_infinitely_long_reply_chain() {
|
|||
)
|
||||
.language_detection_config(language_detection_config())
|
||||
.search_backend(NoopSearchService)
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.account_cache(Arc::new(NoopCache.into()))
|
||||
.post_cache(Arc::new(NoopCache.into()))
|
||||
.build();
|
||||
|
|
|
@ -4,14 +4,15 @@ use hyper::Request;
|
|||
use kitsune_activitypub::Fetcher;
|
||||
use kitsune_cache::NoopCache;
|
||||
use kitsune_config::instance::FederationFilterConfiguration;
|
||||
use kitsune_core::traits::Fetcher as _;
|
||||
use kitsune_core::traits::{coerce::CoerceResolver, Fetcher as _};
|
||||
use kitsune_federation_filter::FederationFilter;
|
||||
use kitsune_http_client::Client;
|
||||
use kitsune_search::NoopSearchService;
|
||||
use kitsune_test::{assert_display_eq, database_test, language_detection_config};
|
||||
use kitsune_webfinger::Webfinger;
|
||||
use std::{convert::Infallible, sync::Arc};
|
||||
use std::convert::Infallible;
|
||||
use tower::service_fn;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_ap_id_authority() {
|
||||
|
@ -38,10 +39,7 @@ async fn check_ap_id_authority() {
|
|||
.clone()
|
||||
.client(client.clone())
|
||||
.language_detection_config(language_detection_config())
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.build();
|
||||
|
||||
// The mock HTTP client ensures that the fetcher doesn't access the correct server
|
||||
|
@ -64,10 +62,7 @@ async fn check_ap_id_authority() {
|
|||
.clone()
|
||||
.client(client.clone())
|
||||
.language_detection_config(language_detection_config())
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.build();
|
||||
|
||||
let _ = fetcher
|
||||
|
@ -100,10 +95,7 @@ async fn check_ap_content_type() {
|
|||
)
|
||||
.language_detection_config(language_detection_config())
|
||||
.search_backend(NoopSearchService)
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.account_cache(Arc::new(NoopCache.into()))
|
||||
.post_cache(Arc::new(NoopCache.into()))
|
||||
.build();
|
||||
|
|
|
@ -4,7 +4,7 @@ use hyper::{Request, Response};
|
|||
use kitsune_activitypub::Fetcher;
|
||||
use kitsune_cache::NoopCache;
|
||||
use kitsune_config::instance::FederationFilterConfiguration;
|
||||
use kitsune_core::traits::Fetcher as _;
|
||||
use kitsune_core::traits::{coerce::CoerceResolver, Fetcher as _};
|
||||
use kitsune_federation_filter::FederationFilter;
|
||||
use kitsune_http_client::Client;
|
||||
use kitsune_search::NoopSearchService;
|
||||
|
@ -12,8 +12,9 @@ use kitsune_test::{database_test, language_detection_config};
|
|||
use kitsune_type::webfinger::{Link, Resource};
|
||||
use kitsune_webfinger::Webfinger;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::{convert::Infallible, sync::Arc};
|
||||
use std::convert::Infallible;
|
||||
use tower::service_fn;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_actor_with_custom_acct() {
|
||||
|
@ -57,10 +58,7 @@ async fn fetch_actor_with_custom_acct() {
|
|||
)
|
||||
.language_detection_config(language_detection_config())
|
||||
.search_backend(NoopSearchService)
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.account_cache(Arc::new(NoopCache.into()))
|
||||
.post_cache(Arc::new(NoopCache.into()))
|
||||
.build();
|
||||
|
@ -138,10 +136,7 @@ async fn ignore_fake_webfinger_acct() {
|
|||
)
|
||||
.language_detection_config(language_detection_config())
|
||||
.search_backend(NoopSearchService)
|
||||
.resolver(Arc::new(Webfinger::with_client(
|
||||
client,
|
||||
Arc::new(NoopCache.into()),
|
||||
)))
|
||||
.resolver(Arc::new(Webfinger::with_client(client, Arc::new(NoopCache.into()))).coerce())
|
||||
.account_cache(Arc::new(NoopCache.into()))
|
||||
.post_cache(Arc::new(NoopCache.into()))
|
||||
.build();
|
||||
|
|
|
@ -17,6 +17,7 @@ redis = { version = "0.25.3", default-features = false, features = [
|
|||
serde = "1.0.201"
|
||||
simd-json = "0.13.10"
|
||||
tracing = "0.1.40"
|
||||
triomphe = "0.1.11"
|
||||
typed-builder = "0.18.2"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -4,7 +4,8 @@ extern crate tracing;
|
|||
use enum_dispatch::enum_dispatch;
|
||||
use kitsune_error::Result;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::{fmt::Display, sync::Arc};
|
||||
use std::fmt::Display;
|
||||
use triomphe::Arc;
|
||||
|
||||
pub use self::in_memory::InMemory as InMemoryCache;
|
||||
pub use self::redis::Redis as RedisCache;
|
||||
|
|
|
@ -11,8 +11,6 @@ pub enum Transport {
|
|||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Configuration {
|
||||
pub metrics_transport: Transport,
|
||||
pub metrics_endpoint: SmolStr,
|
||||
pub tracing_transport: Transport,
|
||||
pub tracing_endpoint: SmolStr,
|
||||
}
|
||||
|
|
|
@ -11,8 +11,11 @@ async-trait = "0.1.80"
|
|||
const_format = "0.2.32"
|
||||
kitsune-db = { path = "../kitsune-db" }
|
||||
kitsune-error = { path = "../kitsune-error" }
|
||||
paste = "1.0.15"
|
||||
serde = { version = "1.0.201", features = ["derive"] }
|
||||
triomphe = { version = "0.1.11", features = ["unsize"] }
|
||||
typed-builder = "0.18.2"
|
||||
unsize = "1.1.0"
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { version = "8.3.1", features = ["build", "git", "gitcl"] }
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
use super::{Deliverer, Fetcher, Resolver};
|
||||
use paste::paste;
|
||||
use triomphe::Arc;
|
||||
use unsize::{CoerceUnsize, Coercion};
|
||||
|
||||
macro_rules! create_coerce {
|
||||
($trait:ident) => {
|
||||
paste! {
|
||||
pub trait [<Coerce $trait>] {
|
||||
fn coerce(self) -> Arc<dyn $trait>;
|
||||
}
|
||||
|
||||
impl<T> [<Coerce $trait>] for Arc<T> where T: $trait {
|
||||
fn coerce(self) -> Arc<dyn $trait> {
|
||||
self.unsize(Coercion!(to dyn $trait))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
create_coerce!(Deliverer);
|
||||
create_coerce!(Fetcher);
|
||||
create_coerce!(Resolver);
|
|
@ -2,7 +2,7 @@ use async_trait::async_trait;
|
|||
use kitsune_db::model::{account::Account, favourite::Favourite, follower::Follow, post::Post};
|
||||
use kitsune_error::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub enum Action {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use super::Resolver;
|
||||
use super::{coerce::CoerceResolver, Resolver};
|
||||
use async_trait::async_trait;
|
||||
use kitsune_db::model::{account::Account, custom_emoji::CustomEmoji, post::Post};
|
||||
use kitsune_error::Result;
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(Clone, Copy, Debug, TypedBuilder)]
|
||||
|
@ -82,7 +82,7 @@ where
|
|||
T: Fetcher,
|
||||
{
|
||||
fn resolver(&self) -> Arc<dyn Resolver> {
|
||||
Arc::new(self.iter().map(Fetcher::resolver).collect::<Vec<_>>())
|
||||
Arc::new(self.iter().map(Fetcher::resolver).collect::<Vec<_>>()).coerce()
|
||||
}
|
||||
|
||||
async fn fetch_account(&self, opts: AccountFetchOptions<'_>) -> Result<Option<Account>> {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub mod coerce;
|
||||
pub mod deliverer;
|
||||
pub mod fetcher;
|
||||
pub mod resolver;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use async_trait::async_trait;
|
||||
use kitsune_error::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
|
||||
/// Description of a resolved account
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "kitsune-derive"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
kitsune-derive-impl = { path = "impl" }
|
||||
triomphe = "0.1.11"
|
||||
typed-builder = "0.18.2"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
|
@ -0,0 +1 @@
|
|||
../../LICENSE-AGPL-3.0
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "kitsune-derive-impl"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.82"
|
||||
quote = "1.0.36"
|
||||
syn = { version = "2.0.61", features = ["full"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
|
@ -0,0 +1,116 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use std::iter;
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
punctuated::Punctuated,
|
||||
spanned::Spanned,
|
||||
Token, Visibility,
|
||||
};
|
||||
|
||||
struct Attributes {
|
||||
expand_builder: bool,
|
||||
}
|
||||
|
||||
impl Default for Attributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
expand_builder: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Attributes {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let mut attributes = Self::default();
|
||||
let punctuated = Punctuated::<syn::Ident, Token![,]>::parse_terminated(input)?;
|
||||
|
||||
for ident in punctuated {
|
||||
if ident == "omit_builder" {
|
||||
attributes.expand_builder = false;
|
||||
} else {
|
||||
return Err(syn::Error::new(
|
||||
ident.span(),
|
||||
format!("unknown attribute: {ident}"),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(attributes)
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_builder(
|
||||
parsed_struct: &syn::ItemStruct,
|
||||
inner_struct_name: &syn::Ident,
|
||||
) -> (TokenStream, TokenStream) {
|
||||
let struct_name = &parsed_struct.ident;
|
||||
let inner_builder_name = format_ident!("{inner_struct_name}Builder");
|
||||
|
||||
let num_lifetimes = parsed_struct.generics.lifetimes().count();
|
||||
let lifetimes = iter::repeat(quote!('_)).take(num_lifetimes);
|
||||
|
||||
let attrs = quote! {
|
||||
#[derive(::kitsune_derive::typed_builder::TypedBuilder)]
|
||||
#[builder(build_method(into = #struct_name))]
|
||||
#[builder(crate_module_path = ::kitsune_derive::typed_builder)]
|
||||
};
|
||||
let impls = quote! {
|
||||
impl #struct_name {
|
||||
pub fn builder() -> #inner_builder_name<#(#lifetimes),*> {
|
||||
#inner_struct_name::builder()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(attrs, impls)
|
||||
}
|
||||
|
||||
pub fn expand(attrs: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
|
||||
let attributes = syn::parse2::<Attributes>(attrs)?;
|
||||
let mut parsed_struct = syn::parse2::<syn::ItemStruct>(input)?;
|
||||
|
||||
let struct_name = parsed_struct.ident.clone();
|
||||
let inner_struct_name = format_ident!("__{struct_name}__Inner");
|
||||
|
||||
let (builder_attrs, builder_impls) = if attributes.expand_builder {
|
||||
expand_builder(&parsed_struct, &inner_struct_name)
|
||||
} else {
|
||||
(TokenStream::new(), TokenStream::new())
|
||||
};
|
||||
|
||||
parsed_struct.ident = inner_struct_name.clone();
|
||||
parsed_struct.vis = Visibility::Public(Token![pub](parsed_struct.span()));
|
||||
|
||||
let output = quote! {
|
||||
#builder_attrs
|
||||
#[allow(non_camel_case_types)]
|
||||
#[doc(hidden)]
|
||||
#parsed_struct
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct #struct_name {
|
||||
inner: ::kitsune_derive::triomphe::Arc<#inner_struct_name>,
|
||||
}
|
||||
|
||||
#builder_impls
|
||||
|
||||
impl ::core::ops::Deref for #struct_name {
|
||||
type Target = #inner_struct_name;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<#inner_struct_name> for #struct_name {
|
||||
fn from(inner: #inner_struct_name) -> Self {
|
||||
Self {
|
||||
inner: ::kitsune_derive::triomphe::Arc::new(inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(output)
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
mod expand;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn kitsune_service(
|
||||
attrs: proc_macro::TokenStream,
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
match self::expand::expand(attrs.into(), input.into()) {
|
||||
Ok(out) => out.into(),
|
||||
Err(error) => error.to_compile_error().into(),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub use ::kitsune_derive_impl::kitsune_service;
|
||||
pub use ::triomphe;
|
||||
pub use ::typed_builder;
|
|
@ -14,6 +14,7 @@ askama_axum = "0.4.0" # Damn it, cargo. Because "kitsune" uses "askama" with the
|
|||
diesel = "2.1.6"
|
||||
diesel-async = "0.4.1"
|
||||
kitsune-db = { path = "../kitsune-db" }
|
||||
kitsune-derive = { path = "../kitsune-derive" }
|
||||
kitsune-error = { path = "../kitsune-error" }
|
||||
kitsune-url = { path = "../kitsune-url" }
|
||||
lettre = { version = "0.11.7", default-features = false, features = [
|
||||
|
@ -31,6 +32,7 @@ mrml = { version = "3.1.5", default-features = false, features = [
|
|||
"render",
|
||||
] }
|
||||
speedy-uuid = { path = "../../lib/speedy-uuid" }
|
||||
triomphe = "0.1.11"
|
||||
typed-builder = "0.18.2"
|
||||
|
||||
[lints]
|
||||
|
|
|
@ -4,7 +4,8 @@ use lettre::{
|
|||
message::{Mailbox, MultiPart},
|
||||
AsyncTransport, Message,
|
||||
};
|
||||
use std::{iter, sync::Arc};
|
||||
use std::iter;
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
pub use self::service::Mailing as MailingService;
|
||||
|
|
|
@ -2,13 +2,13 @@ use crate::{mails::confirm_account::ConfirmAccount, MailSender};
|
|||
use diesel::{ExpressionMethods, NullableExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use kitsune_db::{function::now, model::user::User, schema::users, with_connection, PgPool};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::Result;
|
||||
use kitsune_url::UrlService;
|
||||
use lettre::{AsyncSmtpTransport, Tokio1Executor};
|
||||
use speedy_uuid::Uuid;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct Mailing {
|
||||
db_pool: PgPool,
|
||||
sender: Option<MailSender<AsyncSmtpTransport<Tokio1Executor>>>,
|
||||
|
|
|
@ -12,12 +12,12 @@ embed-sdk = { git = "https://github.com/Lantern-chat/embed-service.git", rev = "
|
|||
http = "1.1.0"
|
||||
iso8601-timestamp = "0.2.17"
|
||||
kitsune-db = { path = "../kitsune-db" }
|
||||
kitsune-derive = { path = "../kitsune-derive" }
|
||||
kitsune-error = { path = "../kitsune-error" }
|
||||
kitsune-http-client = { path = "../kitsune-http-client" }
|
||||
once_cell = "1.19.0"
|
||||
scraper = { version = "0.19.0", default-features = false }
|
||||
smol_str = "0.2.1"
|
||||
typed-builder = "0.18.2"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -9,12 +9,12 @@ use kitsune_db::{
|
|||
schema::link_previews,
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::Result;
|
||||
use kitsune_http_client::Client as HttpClient;
|
||||
use once_cell::sync::Lazy;
|
||||
use scraper::{Html, Selector};
|
||||
use smol_str::SmolStr;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
pub use embed_sdk;
|
||||
pub use embed_sdk::Embed;
|
||||
|
@ -32,7 +32,7 @@ fn first_link_from_fragment(fragment: &str) -> Option<String> {
|
|||
.and_then(|element| element.value().attr("href").map(ToString::to_string))
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct Client {
|
||||
db_pool: PgPool,
|
||||
#[builder(setter(into))]
|
||||
|
|
|
@ -8,6 +8,7 @@ license.workspace = true
|
|||
[dependencies]
|
||||
globset = "0.4.14"
|
||||
kitsune-config = { path = "../kitsune-config" }
|
||||
kitsune-derive = { path = "../kitsune-derive" }
|
||||
kitsune-error = { path = "../kitsune-error" }
|
||||
kitsune-type = { path = "../kitsune-type" }
|
||||
url = "2.5.0"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||
use kitsune_config::instance::FederationFilterConfiguration;
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{kitsune_error, Result};
|
||||
use kitsune_type::ap::{actor::Actor, Activity, Object};
|
||||
use std::sync::Arc;
|
||||
use url::Url;
|
||||
|
||||
pub trait Entity {
|
||||
|
@ -33,9 +33,9 @@ enum FilterMode {
|
|||
Deny,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[kitsune_service(omit_builder)]
|
||||
pub struct FederationFilter {
|
||||
domains: Arc<GlobSet>,
|
||||
domains: GlobSet,
|
||||
filter: FilterMode,
|
||||
}
|
||||
|
||||
|
@ -50,9 +50,12 @@ impl FederationFilter {
|
|||
for glob in globs {
|
||||
globset.add(Glob::new(glob)?);
|
||||
}
|
||||
let domains = Arc::new(globset.build()?);
|
||||
|
||||
Ok(Self { domains, filter })
|
||||
Ok(__FederationFilter__Inner {
|
||||
domains: globset.build()?,
|
||||
filter,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
pub fn is_url_allowed(&self, url: &Url) -> Result<bool> {
|
||||
|
|
|
@ -18,6 +18,7 @@ kitsune-service = { path = "../kitsune-service" }
|
|||
kitsune-url = { path = "../kitsune-url" }
|
||||
kitsune-wasm-mrf = { path = "../kitsune-wasm-mrf" }
|
||||
kitsune-webfinger = { path = "../kitsune-webfinger" }
|
||||
triomphe = "0.1.11"
|
||||
typed-builder = "0.18.2"
|
||||
|
||||
[lints]
|
||||
|
|
|
@ -4,7 +4,11 @@ use kitsune_activitypub::{
|
|||
};
|
||||
use kitsune_cache::ArcCache;
|
||||
use kitsune_config::language_detection::Configuration as LanguageDetectionConfig;
|
||||
use kitsune_core::traits::{resolver::AccountResource, Deliverer, Fetcher};
|
||||
use kitsune_core::traits::{
|
||||
coerce::{CoerceDeliverer, CoerceFetcher, CoerceResolver},
|
||||
resolver::AccountResource,
|
||||
Deliverer, Fetcher,
|
||||
};
|
||||
use kitsune_db::{
|
||||
model::{account::Account, post::Post},
|
||||
PgPool,
|
||||
|
@ -15,7 +19,7 @@ use kitsune_service::attachment::AttachmentService;
|
|||
use kitsune_url::UrlService;
|
||||
use kitsune_wasm_mrf::MrfService;
|
||||
use kitsune_webfinger::Webfinger;
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(TypedBuilder)]
|
||||
|
@ -58,6 +62,7 @@ pub(crate) fn prepare_deliverer(prepare: PrepareDeliverer) -> Arc<dyn Deliverer>
|
|||
.inbox_resolver(inbox_resolver)
|
||||
.service(service)
|
||||
.build()
|
||||
.coerce()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -71,7 +76,8 @@ pub(crate) fn prepare_fetcher(prepare: PrepareFetcher) -> Arc<dyn Fetcher> {
|
|||
.federation_filter(prepare.federation_filter.clone())
|
||||
.language_detection_config(prepare.language_detection_config)
|
||||
.post_cache(prepare.post_cache)
|
||||
.resolver(Arc::new(webfinger))
|
||||
.resolver(Arc::new(webfinger).coerce())
|
||||
.search_backend(prepare.search_backend)
|
||||
.build()
|
||||
.coerce()
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use kitsune_core::traits::{Deliverer, Fetcher};
|
||||
use std::sync::Arc;
|
||||
use kitsune_core::traits::{
|
||||
coerce::{CoerceDeliverer, CoerceFetcher},
|
||||
Deliverer, Fetcher,
|
||||
};
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
pub mod activitypub;
|
||||
|
@ -29,14 +32,14 @@ pub struct Prepare {
|
|||
#[must_use]
|
||||
pub fn prepare_deliverer(prepare: PrepareDeliverer) -> Arc<dyn Deliverer> {
|
||||
let deliverer = self::activitypub::prepare_deliverer(prepare.activitypub);
|
||||
Arc::new(vec![deliverer])
|
||||
Arc::new(vec![deliverer]).coerce()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn prepare_fetcher(prepare: PrepareFetcher) -> Arc<dyn Fetcher> {
|
||||
let fetcher = self::activitypub::prepare_fetcher(prepare.activitypub);
|
||||
Arc::new(vec![fetcher])
|
||||
Arc::new(vec![fetcher]).coerce()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -13,10 +13,6 @@ http-compat = { path = "../../lib/http-compat" }
|
|||
hyper = { version = "1.3.1", default-features = false }
|
||||
kitsune-config = { path = "../kitsune-config" }
|
||||
kitsune-http-client = { path = "../kitsune-http-client" }
|
||||
metrics = "0.22.3"
|
||||
metrics-opentelemetry = { git = "https://github.com/aumetra/metrics-opentelemetry.git", rev = "95537b16370e595981e195be52f98ea5983a7a8e" }
|
||||
metrics-tracing-context = "0.15.0"
|
||||
metrics-util = "0.16.3"
|
||||
opentelemetry = { version = "0.22.0", default-features = false, features = [
|
||||
"trace",
|
||||
] }
|
||||
|
@ -24,7 +20,6 @@ opentelemetry-http = "0.11.1"
|
|||
opentelemetry-otlp = { version = "0.15.0", default-features = false, features = [
|
||||
"grpc-tonic",
|
||||
"http-proto",
|
||||
"metrics",
|
||||
"tls",
|
||||
"tls-roots",
|
||||
"trace",
|
||||
|
|
|
@ -3,15 +3,9 @@ use eyre::WrapErr;
|
|||
use http_body_util::BodyExt;
|
||||
use http_compat::Compat;
|
||||
use kitsune_config::{open_telemetry::Transport, Configuration};
|
||||
use metrics_opentelemetry::OpenTelemetryRecorder;
|
||||
use metrics_tracing_context::{MetricsLayer, TracingContextLayer};
|
||||
use metrics_util::layers::Layer as _;
|
||||
use opentelemetry::{
|
||||
metrics::{noop::NoopMeterProvider, Meter, MeterProvider},
|
||||
trace::{noop::NoopTracer, Tracer},
|
||||
};
|
||||
use opentelemetry::trace::{noop::NoopTracer, Tracer};
|
||||
use opentelemetry_http::{Bytes, HttpClient, HttpError, Request, Response};
|
||||
use opentelemetry_otlp::{MetricsExporterBuilder, SpanExporterBuilder, WithExportConfig};
|
||||
use opentelemetry_otlp::{SpanExporterBuilder, WithExportConfig};
|
||||
use opentelemetry_sdk::runtime::Tokio;
|
||||
use std::{env, fmt};
|
||||
use tracing_error::ErrorLayer;
|
||||
|
@ -81,23 +75,13 @@ where
|
|||
.with(ErrorLayer::default())
|
||||
.with(OpenTelemetryLayer::new(tracer));
|
||||
|
||||
let subscriber = subscriber.with(MetricsLayer::new());
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber)
|
||||
.wrap_err("Couldn't install the global tracing subscriber")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialise_metrics(meter: Meter) -> eyre::Result<()> {
|
||||
let recorder = TracingContextLayer::all().layer(OpenTelemetryRecorder::new(meter));
|
||||
metrics::set_global_recorder(recorder)
|
||||
.wrap_err("Couldn't install the global metrics recorder")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn initialise(app_name: &'static str, config: &Configuration) -> eyre::Result<()> {
|
||||
pub fn initialise(config: &Configuration) -> eyre::Result<()> {
|
||||
if let Some(ref opentelemetry_config) = config.opentelemetry {
|
||||
let http_client = HttpClientAdapter {
|
||||
inner: kitsune_http_client::Client::default(),
|
||||
|
@ -116,23 +100,8 @@ pub fn initialise(app_name: &'static str, config: &Configuration) -> eyre::Resul
|
|||
.install_batch(Tokio)?;
|
||||
|
||||
initialise_logging(tracer)?;
|
||||
|
||||
let metrics_exporter = build_exporter!(
|
||||
MetricsExporterBuilder:
|
||||
opentelemetry_config.metrics_transport,
|
||||
&http_client,
|
||||
opentelemetry_config.tracing_endpoint.as_str(),
|
||||
);
|
||||
|
||||
let meter_provider = opentelemetry_otlp::new_pipeline()
|
||||
.metrics(Tokio)
|
||||
.with_exporter(metrics_exporter)
|
||||
.build()?;
|
||||
|
||||
initialise_metrics(meter_provider.meter(app_name))?;
|
||||
} else {
|
||||
initialise_logging(NoopTracer::new())?;
|
||||
initialise_metrics(NoopMeterProvider::new().meter(app_name))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -10,6 +10,7 @@ enum_dispatch = "0.3.13"
|
|||
http = "1.1.0"
|
||||
http-body-util = "0.1.1"
|
||||
kitsune-config = { path = "../kitsune-config" }
|
||||
kitsune-derive = { path = "../kitsune-derive" }
|
||||
kitsune-error = { path = "../kitsune-error" }
|
||||
kitsune-http-client = { path = "../kitsune-http-client" }
|
||||
moka = { version = "0.12.7", features = ["future"] }
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::state::{
|
|||
LoginState, OAuth2LoginState, Store,
|
||||
};
|
||||
use kitsune_config::oidc::{Configuration, StoreConfiguration};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{bail, kitsune_error, Result};
|
||||
use multiplex_pool::RoundRobinStrategy;
|
||||
use openidconnect::{
|
||||
|
@ -66,7 +67,7 @@ pub struct UserInfo {
|
|||
pub oauth2: OAuth2Info,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[kitsune_service(omit_builder)]
|
||||
pub struct OidcService {
|
||||
client: OidcClient,
|
||||
login_state_store: self::state::AnyStore,
|
||||
|
@ -103,10 +104,11 @@ impl OidcService {
|
|||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
Ok(__OidcService__Inner {
|
||||
client,
|
||||
login_state_store,
|
||||
})
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
pub async fn authorisation_url(
|
||||
|
|
|
@ -17,6 +17,7 @@ futures-util = "0.3.30"
|
|||
http = "1.1.0"
|
||||
kitsune-config = { path = "../kitsune-config" }
|
||||
kitsune-db = { path = "../kitsune-db" }
|
||||
kitsune-derive = { path = "../kitsune-derive" }
|
||||
kitsune-error = { path = "../kitsune-error" }
|
||||
kitsune-http-client = { path = "../kitsune-http-client" }
|
||||
kitsune-language = { path = "../kitsune-language" }
|
||||
|
@ -27,7 +28,6 @@ serde_urlencoded = "0.7.1"
|
|||
speedy-uuid = { path = "../../lib/speedy-uuid" }
|
||||
strum = { version = "0.26.2", features = ["derive"] }
|
||||
tracing = "0.1.40"
|
||||
typed-builder = "0.18.2"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use self::http_client::HttpClient;
|
||||
use super::{Result, SearchBackend, SearchIndex, SearchItem, SearchResultReference};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use meilisearch_sdk::{client::Client, indexes::Index, settings::Settings};
|
||||
use serde::Deserialize;
|
||||
use speedy_uuid::Uuid;
|
||||
|
@ -12,7 +13,7 @@ struct MeilisearchResult {
|
|||
id: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[kitsune_service(omit_builder)]
|
||||
pub struct MeiliSearchService {
|
||||
client: Client<HttpClient>,
|
||||
}
|
||||
|
@ -29,9 +30,9 @@ impl MeiliSearchService {
|
|||
.content_length_limit(None)
|
||||
.build(),
|
||||
};
|
||||
let service = Self {
|
||||
let service = Self::from(__MeiliSearchService__Inner {
|
||||
client: Client::new_with_client(host, Some(api_key), http_client),
|
||||
};
|
||||
});
|
||||
|
||||
let settings = Settings::new()
|
||||
.with_filterable_attributes(["created_at"])
|
||||
|
|
|
@ -11,10 +11,10 @@ use kitsune_db::{
|
|||
schema::{accounts, posts},
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use speedy_uuid::Uuid;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct SearchService {
|
||||
db_pool: PgPool,
|
||||
language_detection_config: LanguageDetectionConfig,
|
||||
|
|
|
@ -32,6 +32,7 @@ kitsune-captcha = { path = "../kitsune-captcha" }
|
|||
kitsune-config = { path = "../kitsune-config" }
|
||||
kitsune-core = { path = "../kitsune-core" }
|
||||
kitsune-db = { path = "../kitsune-db" }
|
||||
kitsune-derive = { path = "../kitsune-derive" }
|
||||
kitsune-email = { path = "../kitsune-email" }
|
||||
kitsune-embed = { path = "../kitsune-embed" }
|
||||
kitsune-error = { path = "../kitsune-error" }
|
||||
|
@ -59,6 +60,7 @@ smol_str = "0.2.1"
|
|||
speedy-uuid = { path = "../../lib/speedy-uuid" }
|
||||
tokio = { version = "1.37.0", features = ["macros", "sync"] }
|
||||
tracing = "0.1.40"
|
||||
triomphe = "0.1.11"
|
||||
typed-builder = "0.18.2"
|
||||
url = "2.5.0"
|
||||
zxcvbn = { version = "2.2.2", default-features = false }
|
||||
|
|
|
@ -27,6 +27,7 @@ use kitsune_db::{
|
|||
schema::{accounts, accounts_follows, accounts_preferences, notifications, posts},
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{Error, Result};
|
||||
use kitsune_jobs::deliver::{
|
||||
accept::DeliverAccept,
|
||||
|
@ -38,7 +39,7 @@ use kitsune_jobs::deliver::{
|
|||
use kitsune_url::UrlService;
|
||||
use kitsune_util::{sanitize::CleanHtmlExt, try_join};
|
||||
use speedy_uuid::Uuid;
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
|
@ -178,7 +179,7 @@ impl<A, H> Update<A, H> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct AccountService {
|
||||
attachment_service: AttachmentService,
|
||||
db_pool: PgPool,
|
||||
|
|
|
@ -11,6 +11,7 @@ use kitsune_db::{
|
|||
schema::media_attachments,
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{kitsune_error, Error, ErrorType, Result};
|
||||
use kitsune_http_client::Client;
|
||||
use kitsune_storage::{AnyStorageBackend, StorageBackend};
|
||||
|
@ -73,7 +74,7 @@ impl<S> Upload<S> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct AttachmentService {
|
||||
#[builder(default =
|
||||
Client::builder()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use kitsune_captcha::{AnyCaptcha, CaptchaBackend, ChallengeStatus};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::Result;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct CaptchaService {
|
||||
#[builder(setter(into))]
|
||||
pub backend: Option<AnyCaptcha>,
|
||||
|
|
|
@ -14,6 +14,7 @@ use kitsune_db::{
|
|||
schema::{custom_emojis, media_attachments, posts, posts_custom_emojis},
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{Error, Result};
|
||||
use kitsune_url::UrlService;
|
||||
use speedy_uuid::Uuid;
|
||||
|
@ -60,7 +61,7 @@ pub struct EmojiUpload<S> {
|
|||
stream: S,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct CustomEmojiService {
|
||||
attachment_service: AttachmentService,
|
||||
db_pool: PgPool,
|
||||
|
|
|
@ -4,11 +4,11 @@ use kitsune_db::{
|
|||
schema::{accounts, posts, users},
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{Error, Result};
|
||||
use smol_str::SmolStr;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct InstanceService {
|
||||
db_pool: PgPool,
|
||||
#[builder(setter(into))]
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use athena::{JobDetails, JobQueue};
|
||||
use iso8601_timestamp::Timestamp;
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::Result;
|
||||
use kitsune_jobs::{Job, KitsuneContextRepo};
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(TypedBuilder)]
|
||||
|
@ -12,7 +13,7 @@ pub struct Enqueue<T> {
|
|||
run_at: Option<Timestamp>,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct JobService {
|
||||
job_queue: Arc<dyn JobQueue<ContextRepository = KitsuneContextRepo>>,
|
||||
}
|
||||
|
|
|
@ -11,11 +11,12 @@ use kitsune_db::{
|
|||
schema::{accounts, accounts_follows, accounts_preferences, notifications, posts},
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{Error, Result};
|
||||
use speedy_uuid::Uuid;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct NotificationService {
|
||||
db_pool: PgPool,
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ use kitsune_db::{
|
|||
},
|
||||
with_connection, with_transaction, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_embed::Client as EmbedClient;
|
||||
use kitsune_error::{bail, Error, ErrorType, Result};
|
||||
use kitsune_jobs::deliver::{
|
||||
|
@ -294,7 +295,7 @@ pub struct GetAccountsInteractingWithPost {
|
|||
max_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct PostService {
|
||||
db_pool: PgPool,
|
||||
embed_client: Option<EmbedClient>,
|
||||
|
|
|
@ -111,7 +111,7 @@ mod test {
|
|||
account::AccountService, attachment::AttachmentService, custom_emoji::CustomEmojiService,
|
||||
job::JobService,
|
||||
};
|
||||
use athena::RedisJobQueue;
|
||||
use athena::{Coerce, RedisJobQueue};
|
||||
use core::convert::Infallible;
|
||||
use diesel::{QueryDsl, SelectableHelper};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
@ -121,6 +121,7 @@ mod test {
|
|||
use kitsune_activitypub::Fetcher;
|
||||
use kitsune_cache::NoopCache;
|
||||
use kitsune_config::instance::FederationFilterConfiguration;
|
||||
use kitsune_core::traits::coerce::{CoerceFetcher, CoerceResolver};
|
||||
use kitsune_db::{
|
||||
model::{
|
||||
account::Account, custom_emoji::CustomEmoji, media_attachment::NewMediaAttachment,
|
||||
|
@ -139,8 +140,8 @@ mod test {
|
|||
use kitsune_webfinger::Webfinger;
|
||||
use pretty_assertions::assert_eq;
|
||||
use speedy_uuid::Uuid;
|
||||
use std::sync::Arc;
|
||||
use tower::service_fn;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
|
@ -164,7 +165,7 @@ mod test {
|
|||
});
|
||||
let client = Client::builder().service(client);
|
||||
|
||||
let webfinger = Arc::new(Webfinger::with_client(client.clone(), Arc::new(NoopCache.into())));
|
||||
let webfinger = Arc::new(Webfinger::with_client(client.clone(), Arc::new(NoopCache.into()))).coerce();
|
||||
|
||||
let fetcher = Fetcher::builder()
|
||||
.client(client)
|
||||
|
@ -190,7 +191,7 @@ mod test {
|
|||
.redis_pool(redis_pool)
|
||||
.build();
|
||||
|
||||
let job_service = JobService::builder().job_queue(Arc::new(job_queue)).build();
|
||||
let job_service = JobService::builder().job_queue(Arc::new(job_queue).coerce()).build();
|
||||
|
||||
let url_service = UrlService::builder()
|
||||
.domain("example.com")
|
||||
|
@ -207,7 +208,7 @@ mod test {
|
|||
let account_service = AccountService::builder()
|
||||
.attachment_service(attachment_service.clone())
|
||||
.db_pool(db_pool.clone())
|
||||
.fetcher(fetcher)
|
||||
.fetcher(fetcher.coerce())
|
||||
.job_service(job_service)
|
||||
.resolver(webfinger)
|
||||
.url_service(url_service.clone())
|
||||
|
|
|
@ -13,8 +13,9 @@ use kitsune_storage::{fs::Storage as FsStorage, s3::Storage as S3Storage, AnySto
|
|||
use multiplex_pool::RoundRobinStrategy;
|
||||
use redis::aio::ConnectionManager;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::{fmt::Display, str::FromStr, sync::Arc, time::Duration};
|
||||
use std::{fmt::Display, str::FromStr, time::Duration};
|
||||
use tokio::sync::OnceCell;
|
||||
use triomphe::Arc;
|
||||
|
||||
pub async fn cache<K, V>(
|
||||
config: &cache::Configuration,
|
||||
|
|
|
@ -9,10 +9,11 @@ use kitsune_db::{
|
|||
schema::{accounts, posts},
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::Result;
|
||||
use kitsune_search::{SearchBackend, SearchIndex};
|
||||
use speedy_uuid::Uuid;
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
use typed_builder::TypedBuilder;
|
||||
use url::Url;
|
||||
|
||||
|
@ -37,7 +38,7 @@ pub struct Search<'a> {
|
|||
max_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct SearchService {
|
||||
db_pool: PgPool,
|
||||
fetcher: Arc<dyn Fetcher>,
|
||||
|
|
|
@ -9,6 +9,7 @@ use kitsune_db::{
|
|||
schema::{accounts_follows, posts, posts_mentions},
|
||||
with_connection, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{Error, Result};
|
||||
use speedy_uuid::Uuid;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
@ -62,7 +63,7 @@ pub struct GetPublic {
|
|||
only_remote: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct TimelineService {
|
||||
db_pool: PgPool,
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -16,6 +16,7 @@ use kitsune_db::{
|
|||
schema::{accounts, accounts_preferences, users},
|
||||
with_transaction, PgPool,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::{bail, kitsune_error, Error, ErrorType, Result};
|
||||
use kitsune_jobs::mailing::confirmation::SendConfirmationMail;
|
||||
use kitsune_url::UrlService;
|
||||
|
@ -112,7 +113,7 @@ pub struct Register {
|
|||
force_registration: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct UserService {
|
||||
allow_non_ascii_usernames: bool,
|
||||
captcha_service: CaptchaService,
|
||||
|
|
|
@ -14,6 +14,7 @@ kitsune-s3 = { path = "../kitsune-s3" }
|
|||
rusty-s3 = { version = "0.5.0", default-features = false }
|
||||
tokio = { version = "1.37.0", features = ["fs", "io-util"] }
|
||||
tokio-util = { version = "0.7.11", features = ["io"] }
|
||||
triomphe = "0.1.11"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.10.1"
|
||||
|
|
|
@ -7,7 +7,7 @@ use bytes::Bytes;
|
|||
use futures_util::{Stream, StreamExt};
|
||||
use kitsune_error::Result;
|
||||
use rusty_s3::{Bucket, Credentials};
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[derive(Clone)]
|
||||
/// S3-backed storage
|
||||
|
|
|
@ -23,13 +23,8 @@ redis = { version = "0.25.3", default-features = false, features = [
|
|||
"tokio-rustls-comp",
|
||||
] }
|
||||
rusty-s3 = { version = "0.5.0", default-features = false }
|
||||
testcontainers = "0.16.7"
|
||||
testcontainers-modules = { version = "0.4.2", features = [
|
||||
"minio",
|
||||
"postgres",
|
||||
"redis",
|
||||
] }
|
||||
tokio = { version = "1.37.0", features = ["time"] }
|
||||
triomphe = "0.1.11"
|
||||
url = "2.5.0"
|
||||
uuid = { version = "1.8.0", features = ["fast-rng", "v4"] }
|
||||
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
use testcontainers::{core::ContainerAsync, runners::AsyncRunner, RunnableImage};
|
||||
use testcontainers_modules::{minio::MinIO, postgres::Postgres, redis::Redis};
|
||||
|
||||
pub trait Service {
|
||||
const PORT: u16;
|
||||
|
||||
async fn url(&self) -> String;
|
||||
}
|
||||
|
||||
impl Service for ContainerAsync<MinIO> {
|
||||
const PORT: u16 = 9000;
|
||||
|
||||
async fn url(&self) -> String {
|
||||
let port = self.get_host_port_ipv4(Self::PORT).await;
|
||||
format!("http://127.0.0.1:{port}")
|
||||
}
|
||||
}
|
||||
|
||||
impl Service for ContainerAsync<Postgres> {
|
||||
const PORT: u16 = 5432;
|
||||
|
||||
async fn url(&self) -> String {
|
||||
let port = self.get_host_port_ipv4(Self::PORT).await;
|
||||
format!("postgres://postgres:postgres@127.0.0.1:{port}/test_db")
|
||||
}
|
||||
}
|
||||
|
||||
impl Service for ContainerAsync<Redis> {
|
||||
const PORT: u16 = 6379;
|
||||
|
||||
async fn url(&self) -> String {
|
||||
let port = self.get_host_port_ipv4(Self::PORT).await;
|
||||
format!("redis://127.0.0.1:{port}")
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn minio() -> impl Service {
|
||||
MinIO::default().start().await
|
||||
}
|
||||
|
||||
pub async fn postgres() -> impl Service {
|
||||
let base = Postgres::default()
|
||||
.with_user("postgres")
|
||||
.with_password("postgres")
|
||||
.with_db_name("test_db");
|
||||
|
||||
RunnableImage::from(base)
|
||||
.with_tag("15-alpine")
|
||||
.start()
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn redis() -> impl Service {
|
||||
#[allow(clippy::default_constructed_unit_structs)]
|
||||
Redis::default().start().await
|
||||
}
|
|
@ -12,12 +12,12 @@ use kitsune_config::{
|
|||
use kitsune_db::PgPool;
|
||||
use multiplex_pool::RoundRobinStrategy;
|
||||
use resource::provide_resource;
|
||||
use std::sync::Arc;
|
||||
use std::env;
|
||||
use triomphe::Arc;
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
||||
mod catch_panic;
|
||||
mod container;
|
||||
mod macros;
|
||||
mod redis;
|
||||
mod resource;
|
||||
|
@ -37,8 +37,8 @@ where
|
|||
F: FnOnce(PgPool) -> Fut,
|
||||
Fut: Future,
|
||||
{
|
||||
let resource_handle = get_resource!("DATABASE_URL", self::container::postgres);
|
||||
let mut url = Url::parse(&resource_handle.url().await).unwrap();
|
||||
let db_url = env::var("DATABASE_URL").unwrap();
|
||||
let mut url = Url::parse(&db_url).unwrap();
|
||||
|
||||
// Create a new separate database for this test
|
||||
let id = Uuid::new_v4().as_simple().to_string();
|
||||
|
@ -84,8 +84,8 @@ where
|
|||
F: FnOnce(Arc<kitsune_s3::Client>) -> Fut,
|
||||
Fut: Future,
|
||||
{
|
||||
let resource_handle = get_resource!("MINIO_URL", self::container::minio);
|
||||
let endpoint = resource_handle.url().await.parse().unwrap();
|
||||
let endpoint = env::var("MINIO_URL").unwrap();
|
||||
let endpoint = endpoint.parse().unwrap();
|
||||
|
||||
// Create a new bucket with a random ID
|
||||
let bucket_id = Uuid::new_v4().as_simple().to_string();
|
||||
|
@ -116,8 +116,8 @@ where
|
|||
F: FnOnce(multiplex_pool::Pool<ConnectionManager>) -> Fut,
|
||||
Fut: Future,
|
||||
{
|
||||
let resource_handle = get_resource!("REDIS_URL", self::container::redis);
|
||||
let client = ::redis::Client::open(resource_handle.url().await.as_ref()).unwrap();
|
||||
let redis_url = env::var("REDIS_URL").unwrap();
|
||||
let client = ::redis::Client::open(redis_url.as_ref()).unwrap();
|
||||
|
||||
// Connect to a random Redis database
|
||||
let db_id = self::redis::find_unused_database(&client).await;
|
||||
|
|
|
@ -1,37 +1,5 @@
|
|||
use crate::{catch_panic::CatchPanic, container::Service};
|
||||
use std::{borrow::Cow, future::Future, panic};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! get_resource {
|
||||
($env_name:literal, $container_fn:path) => {
|
||||
if let Ok(url) = ::std::env::var($env_name) {
|
||||
$crate::resource::ResourceHandle::Url(url)
|
||||
} else {
|
||||
let container = $container_fn().await;
|
||||
$crate::resource::ResourceHandle::Container(container)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub enum ResourceHandle<S>
|
||||
where
|
||||
S: Service,
|
||||
{
|
||||
Container(S),
|
||||
Url(String),
|
||||
}
|
||||
|
||||
impl<S> ResourceHandle<S>
|
||||
where
|
||||
S: Service,
|
||||
{
|
||||
pub async fn url(&self) -> Cow<'_, str> {
|
||||
match self {
|
||||
Self::Container(container) => Cow::Owned(container.url().await),
|
||||
Self::Url(ref url) => Cow::Borrowed(url),
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::catch_panic::CatchPanic;
|
||||
use std::{future::Future, panic};
|
||||
|
||||
/// Provide a resource to the `run` closure, catch any panics that may occur while polling the future returned by `run`,
|
||||
/// then run the `cleanup` closure, and resume any panic unwinds that were caught
|
||||
|
|
|
@ -6,9 +6,9 @@ version.workspace = true
|
|||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
kitsune-derive = { path = "../kitsune-derive" }
|
||||
smol_str = "0.2.1"
|
||||
speedy-uuid = { path = "../../lib/speedy-uuid" }
|
||||
typed-builder = "0.18.2"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use kitsune_derive::kitsune_service;
|
||||
use smol_str::SmolStr;
|
||||
use speedy_uuid::Uuid;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
/// Small "service" to centralise the creation of URLs
|
||||
///
|
||||
/// For some light deduplication purposes and to centralise the whole formatting story.
|
||||
/// Allows for easier adjustments of URLs.
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct UrlService {
|
||||
#[builder(setter(into))]
|
||||
scheme: SmolStr,
|
||||
|
|
|
@ -16,6 +16,7 @@ futures-util = { version = "0.3.30", default-features = false, features = [
|
|||
"alloc",
|
||||
] }
|
||||
kitsune-config = { path = "../kitsune-config" }
|
||||
kitsune-derive = { path = "../kitsune-derive" }
|
||||
kitsune-error = { path = "../kitsune-error" }
|
||||
kitsune-type = { path = "../kitsune-type" }
|
||||
mrf-manifest = { path = "../../lib/mrf-manifest", features = ["decode"] }
|
||||
|
@ -30,7 +31,7 @@ sled = "0.34.7"
|
|||
smol_str = "0.2.1"
|
||||
tokio = { version = "1.37.0", features = ["fs"] }
|
||||
tracing = "0.1.40"
|
||||
typed-builder = "0.18.2"
|
||||
triomphe = "0.1.11"
|
||||
walkdir = "2.5.0"
|
||||
wasmtime = { version = "20.0.2", default-features = false, features = [
|
||||
"addr2line",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::kv_storage;
|
||||
use slab::Slab;
|
||||
use std::sync::Arc;
|
||||
use triomphe::Arc;
|
||||
use wasmtime::{component::ResourceTable, Engine, Store};
|
||||
use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiView};
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use futures_util::{stream::FuturesUnordered, Stream, TryFutureExt, TryStreamExt}
|
|||
use kitsune_config::mrf::{
|
||||
Configuration as MrfConfiguration, FsKvStorage, KvStorage, RedisKvStorage,
|
||||
};
|
||||
use kitsune_derive::kitsune_service;
|
||||
use kitsune_error::Error;
|
||||
use kitsune_type::ap::Activity;
|
||||
use mrf_manifest::{Manifest, ManifestV1};
|
||||
|
@ -20,10 +21,9 @@ use std::{
|
|||
fmt::Debug,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use tokio::fs;
|
||||
use typed_builder::TypedBuilder;
|
||||
use triomphe::Arc;
|
||||
use walkdir::WalkDir;
|
||||
use wasmtime::{
|
||||
component::{Component, Linker},
|
||||
|
@ -111,7 +111,7 @@ pub struct MrfModule {
|
|||
pub manifest: ManifestV1<'static>,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[kitsune_service]
|
||||
pub struct MrfService {
|
||||
engine: Engine,
|
||||
linker: Arc<Linker<Context>>,
|
||||
|
@ -131,12 +131,13 @@ impl MrfService {
|
|||
mrf_wit::v1::Mrf::add_to_linker(&mut linker, |ctx| ctx).map_err(eyre::Report::msg)?;
|
||||
wasmtime_wasi::add_to_linker_async(&mut linker).map_err(eyre::Report::msg)?;
|
||||
|
||||
Ok(Self {
|
||||
Ok(__MrfService__Inner {
|
||||
engine,
|
||||
linker: Arc::new(linker),
|
||||
modules: modules.into(),
|
||||
storage: Arc::new(storage),
|
||||
})
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(module_dir = %config.module_dir))]
|
||||
|
|
|
@ -7,7 +7,6 @@ license.workspace = true
|
|||
|
||||
[dependencies]
|
||||
async-trait = "0.1.80"
|
||||
autometrics = { version = "1.0.1", default-features = false }
|
||||
futures-util = "0.3.30"
|
||||
http = "1.1.0"
|
||||
kitsune-cache = { path = "../kitsune-cache" }
|
||||
|
@ -22,6 +21,7 @@ redis = { version = "0.25.3", default-features = false, features = [
|
|||
"tokio-comp",
|
||||
] }
|
||||
tracing = "0.1.40"
|
||||
triomphe = "0.1.11"
|
||||
urlencoding = "2.1.3"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
extern crate tracing;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use autometrics::autometrics;
|
||||
use futures_util::future::{FutureExt, OptionFuture};
|
||||
use http::{HeaderValue, StatusCode};
|
||||
use kitsune_cache::{ArcCache, CacheBackend, RedisCache};
|
||||
|
@ -15,7 +14,8 @@ use kitsune_http_client::Client;
|
|||
use kitsune_type::webfinger::Resource;
|
||||
use kitsune_util::try_join;
|
||||
use redis::aio::ConnectionManager;
|
||||
use std::{ptr, sync::Arc, time::Duration};
|
||||
use std::{ptr, time::Duration};
|
||||
use triomphe::Arc;
|
||||
|
||||
const CACHE_DURATION: Duration = Duration::from_secs(10 * 60); // 10 minutes
|
||||
|
||||
|
@ -68,7 +68,6 @@ impl Resolver for Webfinger {
|
|||
/// `acct:{preferredUsername}@{domain}` URI points back to the resolved `acct:` resource,
|
||||
/// which the caller should check by themselves before trusting the result.
|
||||
#[instrument(skip(self))]
|
||||
#[autometrics(track_concurrency)]
|
||||
async fn resolve_account(
|
||||
&self,
|
||||
username: &str,
|
||||
|
|
|
@ -5,8 +5,9 @@ use kitsune_core::traits::Resolver;
|
|||
use kitsune_http_client::Client;
|
||||
use kitsune_webfinger::Webfinger;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::{convert::Infallible, sync::Arc};
|
||||
use std::convert::Infallible;
|
||||
use tower::service_fn;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn basic() {
|
||||
|
|
|
@ -6,8 +6,9 @@ use kitsune_http_client::Client;
|
|||
use kitsune_type::webfinger::Resource;
|
||||
use kitsune_webfinger::{Webfinger, MAX_JRD_REDIRECTS};
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::{convert::Infallible, sync::Arc};
|
||||
use std::convert::Infallible;
|
||||
use tower::service_fn;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn follow_jrd_redirect() {
|
||||
|
|
|
@ -23,8 +23,6 @@ postgres://database-user:password-here@localhost:5432/db-name-here
|
|||
The `max-connections` setting defines how many connections the globally shared connection pool will open to the database server _at maximum_.
|
||||
What you should set this value to depends on many factors.
|
||||
|
||||
> We currently do not report any pool metrics via the Prometheus endpoint. This might be added in the future.
|
||||
|
||||
## TLS support
|
||||
|
||||
If you want to connect to a database using TLS, set the parameter `use-tls` to `true`.
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
# OpenTelemetry
|
||||
|
||||
Kitsune can export its traces and metrics via the OpenTelemetry Protocol (or OTLP, for short).
|
||||
Kitsune can export its traces via the OpenTelemetry Protocol (or OTLP, for short).
|
||||
|
||||
To push the data to an endpoint, add the following to your configuration:
|
||||
|
||||
```toml
|
||||
[opentelemetry]
|
||||
# Where Kitsune pushes metrics (eg. Prometheus)
|
||||
metrics-transport = "http" # "http" or "grpc"
|
||||
metrics-endpoint = "https://localhost:5050/metrics-endpoint"
|
||||
# Where Kitsune pushes traces (eg. Jaeger)
|
||||
tracing-transport = "http" # "http" or "grpc"
|
||||
tracing-endpoint = "https://localhost:5050/tracing-endpoint"
|
||||
|
|
352
flake.nix
352
flake.nix
|
@ -26,169 +26,209 @@
|
|||
# like so `nix build --override-input debugBuild github:boolean-option/true`
|
||||
debugBuild.url = "github:boolean-option/false/d06b4794a134686c70a1325df88a6e6768c6b212";
|
||||
};
|
||||
outputs = { self, devenv, flake-utils, nixpkgs, rust-overlay, crane, ... } @ inputs:
|
||||
(flake-utils.lib.eachDefaultSystem
|
||||
(system:
|
||||
let
|
||||
features = "--all-features";
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit overlays system;
|
||||
};
|
||||
stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.stdenv;
|
||||
rustPlatform = pkgs.makeRustPlatform {
|
||||
cargo = pkgs.rust-bin.stable.latest.minimal;
|
||||
rustc = pkgs.rust-bin.stable.latest.minimal;
|
||||
inherit stdenv;
|
||||
};
|
||||
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain pkgs.rust-bin.stable.latest.minimal;
|
||||
buildInputs = with pkgs; [
|
||||
openssl
|
||||
sqlite
|
||||
zlib
|
||||
];
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
protobuf
|
||||
pkg-config
|
||||
rustPlatform.bindgenHook
|
||||
];
|
||||
|
||||
src = pkgs.lib.cleanSourceWith {
|
||||
src = pkgs.lib.cleanSource ./.;
|
||||
filter = name: type:
|
||||
let baseName = baseNameOf (toString name);
|
||||
in !(baseName == "flake.lock" || pkgs.lib.hasSuffix ".nix" baseName);
|
||||
};
|
||||
|
||||
commonArgs = {
|
||||
inherit src stdenv buildInputs nativeBuildInputs;
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
meta = {
|
||||
description = "ActivityPub-federated microblogging";
|
||||
homepage = "https://joinkitsune.org";
|
||||
outputs =
|
||||
{ self
|
||||
, devenv
|
||||
, flake-utils
|
||||
, nixpkgs
|
||||
, rust-overlay
|
||||
, crane
|
||||
, ...
|
||||
}@inputs:
|
||||
(
|
||||
flake-utils.lib.eachDefaultSystem
|
||||
(
|
||||
system:
|
||||
let
|
||||
features = "--all-features";
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs { inherit overlays system; };
|
||||
stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.stdenv;
|
||||
rustPlatform = pkgs.makeRustPlatform {
|
||||
cargo = pkgs.rust-bin.stable.latest.minimal;
|
||||
rustc = pkgs.rust-bin.stable.latest.minimal;
|
||||
inherit stdenv;
|
||||
};
|
||||
|
||||
OPENSSL_NO_VENDOR = 1;
|
||||
NIX_OUTPATH_USED_AS_RANDOM_SEED = "aaaaaaaaaa";
|
||||
cargoExtraArgs = "--locked ${features}";
|
||||
} // (pkgs.lib.optionalAttrs inputs.debugBuild.value {
|
||||
# do a debug build, as `dev` is the default debug profile
|
||||
CARGO_PROFILE = "dev";
|
||||
});
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain pkgs.rust-bin.stable.latest.minimal;
|
||||
buildInputs = with pkgs; [
|
||||
openssl
|
||||
sqlite
|
||||
zlib
|
||||
];
|
||||
|
||||
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
|
||||
version = cargoToml.workspace.package.version;
|
||||
nativeBuildInputs = with pkgs; [
|
||||
protobuf
|
||||
pkg-config
|
||||
rustPlatform.bindgenHook
|
||||
];
|
||||
|
||||
cargoArtifacts = craneLib.buildDepsOnly (commonArgs // {
|
||||
pname = "kitsune-workspace";
|
||||
src = craneLib.cleanCargoSource src;
|
||||
});
|
||||
in
|
||||
{
|
||||
formatter = pkgs.nixpkgs-fmt;
|
||||
packages = rec {
|
||||
default = main;
|
||||
|
||||
cli = craneLib.buildPackage (commonArgs // {
|
||||
pname = "kitsune-cli";
|
||||
cargoExtraArgs = commonArgs.cargoExtraArgs + " --bin kitsune-cli";
|
||||
inherit cargoArtifacts;
|
||||
doCheck = false;
|
||||
});
|
||||
|
||||
mrf-tool = craneLib.buildPackage (commonArgs // {
|
||||
pname = "mrf-tool";
|
||||
cargoExtraArgs = commonArgs.cargoExtraArgs + " --bin mrf-tool";
|
||||
inherit cargoArtifacts;
|
||||
doCheck = false;
|
||||
});
|
||||
|
||||
main = craneLib.buildPackage (commonArgs // rec {
|
||||
pname = "kitsune";
|
||||
cargoExtraArgs = commonArgs.cargoExtraArgs + " --bin kitsune --bin kitsune-job-runner";
|
||||
inherit cargoArtifacts;
|
||||
doCheck = false;
|
||||
});
|
||||
|
||||
frontend = pkgs.mkYarnPackage {
|
||||
inherit version;
|
||||
packageJSON = "${src}/kitsune-fe/package.json";
|
||||
yarnLock = "${src}/kitsune-fe/yarn.lock";
|
||||
src = "${src}/kitsune-fe";
|
||||
|
||||
buildPhase = ''
|
||||
export HOME=$(mktemp -d)
|
||||
yarn --offline build
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -R deps/kitsune-fe/dist $out
|
||||
'';
|
||||
|
||||
distPhase = "true";
|
||||
};
|
||||
};
|
||||
|
||||
devShells = rec {
|
||||
default = backend;
|
||||
|
||||
backend = devenv.lib.mkShell {
|
||||
inherit pkgs inputs;
|
||||
|
||||
modules = [
|
||||
({ pkgs, ... }: {
|
||||
packages = with pkgs; [
|
||||
cargo-insta
|
||||
diesel-cli
|
||||
rust-bin.stable.latest.default
|
||||
]
|
||||
++
|
||||
buildInputs ++ nativeBuildInputs;
|
||||
|
||||
enterShell = ''
|
||||
export PG_HOST=127.0.0.1
|
||||
export PG_PORT=5432
|
||||
[ -z "$DATABASE_URL" ] && export DATABASE_URL=postgres://$USER@$PG_HOST:$PG_PORT/$USER
|
||||
|
||||
export REDIS_PORT=6379
|
||||
[ -z "$REDIS_URL" ] && export REDIS_URL="redis://127.0.0.1:$REDIS_PORT"
|
||||
'';
|
||||
|
||||
services = {
|
||||
postgres = {
|
||||
enable = true;
|
||||
listen_addresses = "127.0.0.1";
|
||||
};
|
||||
redis.enable = true;
|
||||
};
|
||||
})
|
||||
];
|
||||
src = pkgs.lib.cleanSourceWith {
|
||||
src = pkgs.lib.cleanSource ./.;
|
||||
filter =
|
||||
name: type:
|
||||
let
|
||||
baseName = baseNameOf (toString name);
|
||||
in
|
||||
!(baseName == "flake.lock" || pkgs.lib.hasSuffix ".nix" baseName);
|
||||
};
|
||||
|
||||
frontend = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
nodejs
|
||||
yarn
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
) // {
|
||||
overlays = rec {
|
||||
default = kitsune;
|
||||
kitsune = (import ./overlay.nix self);
|
||||
};
|
||||
commonArgs =
|
||||
{
|
||||
inherit
|
||||
src
|
||||
stdenv
|
||||
buildInputs
|
||||
nativeBuildInputs
|
||||
;
|
||||
|
||||
nixosModules = rec {
|
||||
default = kitsune;
|
||||
kitsune = (import ./module.nix);
|
||||
};
|
||||
}) // {
|
||||
strictDeps = true;
|
||||
|
||||
meta = {
|
||||
description = "ActivityPub-federated microblogging";
|
||||
homepage = "https://joinkitsune.org";
|
||||
};
|
||||
|
||||
OPENSSL_NO_VENDOR = 1;
|
||||
NIX_OUTPATH_USED_AS_RANDOM_SEED = "aaaaaaaaaa";
|
||||
cargoExtraArgs = "--locked ${features}";
|
||||
}
|
||||
// (pkgs.lib.optionalAttrs inputs.debugBuild.value {
|
||||
# do a debug build, as `dev` is the default debug profile
|
||||
CARGO_PROFILE = "dev";
|
||||
});
|
||||
|
||||
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
|
||||
version = cargoToml.workspace.package.version;
|
||||
|
||||
cargoArtifacts = craneLib.buildDepsOnly (
|
||||
commonArgs
|
||||
// {
|
||||
pname = "kitsune-workspace";
|
||||
src = craneLib.cleanCargoSource src;
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
formatter = pkgs.nixpkgs-fmt;
|
||||
packages = rec {
|
||||
default = main;
|
||||
|
||||
cli = craneLib.buildPackage (
|
||||
commonArgs
|
||||
// {
|
||||
pname = "kitsune-cli";
|
||||
cargoExtraArgs = commonArgs.cargoExtraArgs + " --bin kitsune-cli";
|
||||
inherit cargoArtifacts;
|
||||
doCheck = false;
|
||||
}
|
||||
);
|
||||
|
||||
mrf-tool = craneLib.buildPackage (
|
||||
commonArgs
|
||||
// {
|
||||
pname = "mrf-tool";
|
||||
cargoExtraArgs = commonArgs.cargoExtraArgs + " --bin mrf-tool";
|
||||
inherit cargoArtifacts;
|
||||
doCheck = false;
|
||||
}
|
||||
);
|
||||
|
||||
main = craneLib.buildPackage (
|
||||
commonArgs
|
||||
// {
|
||||
pname = "kitsune";
|
||||
cargoExtraArgs = commonArgs.cargoExtraArgs + " --bin kitsune --bin kitsune-job-runner";
|
||||
inherit cargoArtifacts;
|
||||
doCheck = false;
|
||||
}
|
||||
);
|
||||
|
||||
frontend = pkgs.mkYarnPackage {
|
||||
inherit version;
|
||||
packageJSON = "${src}/kitsune-fe/package.json";
|
||||
yarnLock = "${src}/kitsune-fe/yarn.lock";
|
||||
src = "${src}/kitsune-fe";
|
||||
|
||||
buildPhase = ''
|
||||
export HOME=$(mktemp -d)
|
||||
yarn --offline build
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -R deps/kitsune-fe/dist $out
|
||||
'';
|
||||
|
||||
distPhase = "true";
|
||||
};
|
||||
};
|
||||
|
||||
devShells = rec {
|
||||
default = backend;
|
||||
|
||||
backend = devenv.lib.mkShell {
|
||||
inherit pkgs inputs;
|
||||
|
||||
modules = [
|
||||
(
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
packages =
|
||||
with pkgs;
|
||||
[
|
||||
cargo-insta
|
||||
diesel-cli
|
||||
rust-bin.stable.latest.default
|
||||
]
|
||||
++ buildInputs
|
||||
++ nativeBuildInputs;
|
||||
|
||||
enterShell = ''
|
||||
export PG_HOST=127.0.0.1
|
||||
export PG_PORT=5432
|
||||
[ -z "$DATABASE_URL" ] && export DATABASE_URL=postgres://$USER@$PG_HOST:$PG_PORT/$USER
|
||||
|
||||
export REDIS_PORT=6379
|
||||
[ -z "$REDIS_URL" ] && export REDIS_URL="redis://127.0.0.1:$REDIS_PORT"
|
||||
'';
|
||||
|
||||
services = {
|
||||
postgres = {
|
||||
enable = true;
|
||||
listen_addresses = "127.0.0.1";
|
||||
};
|
||||
redis.enable = true;
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
};
|
||||
|
||||
frontend = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
nodejs
|
||||
yarn
|
||||
nodePackages.svelte-language-server
|
||||
nodePackages.typescript-language-server
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
// {
|
||||
overlays = rec {
|
||||
default = kitsune;
|
||||
kitsune = (import ./overlay.nix self);
|
||||
};
|
||||
|
||||
nixosModules = rec {
|
||||
default = kitsune;
|
||||
kitsune = (import ./module.nix);
|
||||
};
|
||||
}
|
||||
)
|
||||
// {
|
||||
nixci.default = {
|
||||
debug = {
|
||||
dir = ".";
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
|
@ -0,0 +1 @@
|
|||
dist/
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"endOfLine": "lf",
|
||||
"importOrder": ["^\\w", "^[./|~/]"],
|
||||
"importOrderSeparation": true,
|
||||
"importOrderParserPlugins": ["typescript"],
|
||||
"plugins": [
|
||||
"@trivago/prettier-plugin-sort-imports",
|
||||
"prettier-plugin-css-order"
|
||||
],
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"vueIndentScriptAndStyle": true
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
# Kitsune FE
|
||||
|
||||
Frontend for Kitsune using its GraphQL API
|
||||
|
||||
## Build
|
||||
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
## Development server
|
||||
|
||||
```
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Set the backend the frontend uses inside `.env.development`
|
||||
|
||||
## Autogenerate GraphQL typings in the background
|
||||
|
||||
```
|
||||
yarn graphql-codegen --watch
|
||||
```
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"name": "kitsune-fe",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint src",
|
||||
"format": "prettier . --write"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluent/bundle": "^0.18.0",
|
||||
"@formkit/core": "^1.6.2",
|
||||
"@formkit/validation": "^1.6.2",
|
||||
"@formkit/vue": "^1.6.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.6",
|
||||
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
|
||||
"@mcaptcha/vanilla-glue": "^0.1.0-alpha-3",
|
||||
"@tiptap/pm": "^2.3.0",
|
||||
"@tiptap/starter-kit": "^2.3.0",
|
||||
"@tiptap/vue-3": "^2.3.0",
|
||||
"@urql/exchange-graphcache": "^7.0.1",
|
||||
"@urql/vue": "^1.1.3",
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"@zxcvbn-ts/core": "^3.0.4",
|
||||
"@zxcvbn-ts/language-common": "^3.0.4",
|
||||
"@zxcvbn-ts/language-en": "^3.0.2",
|
||||
"floating-vue": "^5.2.2",
|
||||
"fluent-vue": "^3.5.2",
|
||||
"graphql": "^16.8.1",
|
||||
"lodash": "^4.17.21",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"rollup": "npm:@rollup/wasm-node",
|
||||
"tiptap-markdown": "^0.8.10",
|
||||
"unhead": "^1.9.7",
|
||||
"vue": "^3.4.23",
|
||||
"vue-powerglitch": "^1.0.0",
|
||||
"vue-router": "^4.3.2",
|
||||
"vue-virtual-scroller": "^2.0.0-beta.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "^5.0.2",
|
||||
"@graphql-codegen/client-preset": "^4.2.5",
|
||||
"@parcel/watcher": "^2.4.1",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@types/lodash": "^4.17.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
||||
"@typescript-eslint/parser": "^7.7.0",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"eslint": "^9.1.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-vue": "^9.25.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-css-order": "^2.1.2",
|
||||
"sass": "^1.75.0",
|
||||
"typescript": "^5.4.5",
|
||||
"unplugin-fluent-vue": "^1.3.0",
|
||||
"vite": "^5.2.10",
|
||||
"vue-tsc": "^2.0.13"
|
||||
},
|
||||
"resolutions": {
|
||||
"rollup": "npm:@rollup/wasm-node"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue