moved stuff around, new lexicons

Orual 5769d46d 0681c021

+232 -149
+25 -24
Cargo.lock
··· 8525 8525 ] 8526 8526 8527 8527 [[package]] 8528 - name = "weaver-appview" 8528 + name = "weaver-app" 8529 + version = "0.1.0" 8530 + dependencies = [ 8531 + "axum", 8532 + "chrono", 8533 + "console_error_panic_hook", 8534 + "dashmap", 8535 + "dioxus", 8536 + "dioxus-primitives", 8537 + "jacquard", 8538 + "jacquard-axum", 8539 + "markdown-weaver", 8540 + "mime-sniffer", 8541 + "mini-moka", 8542 + "n0-future", 8543 + "serde_json", 8544 + "time", 8545 + "weaver-api", 8546 + "weaver-common", 8547 + "weaver-renderer", 8548 + ] 8549 + 8550 + [[package]] 8551 + name = "weaver-app-server" 8529 8552 version = "0.1.0" 8530 8553 dependencies = [ 8531 8554 "axum", ··· 8589 8612 dependencies = [ 8590 8613 "http", 8591 8614 "jacquard", 8615 + "jacquard-common", 8592 8616 "markdown-weaver", 8593 8617 "markdown-weaver-escape", 8594 8618 "miette 7.6.0", ··· 8642 8666 "weaver-api", 8643 8667 "weaver-common", 8644 8668 "yaml-rust2", 8645 - ] 8646 - 8647 - [[package]] 8648 - name = "weaver-server" 8649 - version = "0.1.0" 8650 - dependencies = [ 8651 - "axum", 8652 - "chrono", 8653 - "console_error_panic_hook", 8654 - "dashmap", 8655 - "dioxus", 8656 - "dioxus-primitives", 8657 - "jacquard", 8658 - "jacquard-axum", 8659 - "markdown-weaver", 8660 - "mime-sniffer", 8661 - "mini-moka", 8662 - "n0-future", 8663 - "serde_json", 8664 - "time", 8665 - "weaver-api", 8666 - "weaver-common", 8667 - "weaver-renderer", 8668 8669 ] 8669 8670 8670 8671 [[package]]
+2 -1
Cargo.toml
··· 4 4 # paths because the flake.nix is written in a way such that top-level members 5 5 # (`weaver-cli` and `weaver-server`) are built as different derivations which avoid being 6 6 # rebuilt if the other package's sources change. 7 - members = ["crates/*", "crates/weaver-server", "crates/weaver-server"] 7 + members = ["crates/*"] 8 8 9 9 #default-members = ["crates/weaver-cli"] 10 10 ··· 42 42 43 43 jacquard = { git = "https://tangled.org/@nonbinary.computer/jacquard", default-features = false, features = ["derive", "api_bluesky"] } 44 44 jacquard-api = { git = "https://tangled.org/@nonbinary.computer/jacquard" } 45 + jacquard-common = { git = "https://tangled.org/@nonbinary.computer/jacquard" } 45 46 jacquard-axum = { git = "https://tangled.org/@nonbinary.computer/jacquard" } 46 47 47 48 [profile]
-4
crates/weaver-api/lexicons/app_bsky_actor_defs.json
··· 743 743 "threadViewPref": { 744 744 "type": "object", 745 745 "properties": { 746 - "prioritizeFollowedUsers": { 747 - "type": "boolean", 748 - "description": "Show followed users at the top of all replies." 749 - }, 750 746 "sort": { 751 747 "type": "string", 752 748 "description": "Sorting mode for threads.",
-5
crates/weaver-api/lexicons/app_bsky_unspecced_getPostThreadOtherV2.json
··· 15 15 "type": "string", 16 16 "description": "Reference (AT-URI) to post record. This is the anchor post.", 17 17 "format": "at-uri" 18 - }, 19 - "prioritizeFollowedUsers": { 20 - "type": "boolean", 21 - "description": "Whether to prioritize posts from followed users. It only has effect when the user is authenticated.", 22 - "default": false 23 18 } 24 19 } 25 20 },
-5
crates/weaver-api/lexicons/app_bsky_unspecced_getPostThreadV2.json
··· 35 35 "minimum": 0, 36 36 "maximum": 100 37 37 }, 38 - "prioritizeFollowedUsers": { 39 - "type": "boolean", 40 - "description": "Whether to prioritize posts from followed users. It only has effect when the user is authenticated.", 41 - "default": false 42 - }, 43 38 "sort": { 44 39 "type": "string", 45 40 "description": "Sorting for the thread replies.",
+4
crates/weaver-api/lexicons/sh_weaver_notebook_book.json
··· 32 32 "ref": "com.atproto.repo.strongRef" 33 33 } 34 34 }, 35 + "path": { 36 + "type": "ref", 37 + "ref": "sh.weaver.notebook.defs#path" 38 + }, 35 39 "tags": { 36 40 "type": "ref", 37 41 "ref": "sh.weaver.notebook.defs#tags"
+5
crates/weaver-api/lexicons/sh_weaver_notebook_defs.json
··· 163 163 } 164 164 } 165 165 }, 166 + "path": { 167 + "type": "string", 168 + "description": "The path of the notebook.", 169 + "maxLength": 100 170 + }, 166 171 "renderedView": { 167 172 "type": "object", 168 173 "description": "View of a rendered and cached notebook entry",
-13
crates/weaver-api/src/app_bsky/actor.rs
··· 2125 2125 #[allow(unused_mut)] 2126 2126 let mut map = ::std::collections::BTreeMap::new(); 2127 2127 map.insert( 2128 - ::jacquard_common::smol_str::SmolStr::new_static( 2129 - "prioritizeFollowedUsers", 2130 - ), 2131 - ::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean { 2132 - description: None, 2133 - default: None, 2134 - r#const: None, 2135 - }), 2136 - ); 2137 - map.insert( 2138 2128 ::jacquard_common::smol_str::SmolStr::new_static("sort"), 2139 2129 ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 2140 2130 description: Some( ··· 7111 7101 )] 7112 7102 #[serde(rename_all = "camelCase")] 7113 7103 pub struct ThreadViewPref<'a> { 7114 - /// Show followed users at the top of all replies. 7115 - #[serde(skip_serializing_if = "std::option::Option::is_none")] 7116 - pub prioritize_followed_users: std::option::Option<bool>, 7117 7104 /// Sorting mode for threads. 7118 7105 #[serde(skip_serializing_if = "std::option::Option::is_none")] 7119 7106 #[serde(borrow)]
+1 -29
crates/weaver-api/src/app_bsky/unspecced/get_post_thread_other_v2.rs
··· 18 18 pub struct GetPostThreadOtherV2<'a> { 19 19 #[serde(borrow)] 20 20 pub anchor: jacquard_common::types::string::AtUri<'a>, 21 - /// (default: false) 22 - #[serde(skip_serializing_if = "std::option::Option::is_none")] 23 - pub prioritize_followed_users: std::option::Option<bool>, 24 21 } 25 22 26 23 pub mod get_post_thread_other_v2_state { ··· 60 57 _phantom_state: ::core::marker::PhantomData<fn() -> S>, 61 58 __unsafe_private_named: ( 62 59 ::core::option::Option<jacquard_common::types::string::AtUri<'a>>, 63 - ::core::option::Option<bool>, 64 60 ), 65 61 _phantom: ::core::marker::PhantomData<&'a ()>, 66 62 } ··· 80 76 pub fn new() -> Self { 81 77 GetPostThreadOtherV2Builder { 82 78 _phantom_state: ::core::marker::PhantomData, 83 - __unsafe_private_named: (None, None), 79 + __unsafe_private_named: (None,), 84 80 _phantom: ::core::marker::PhantomData, 85 81 } 86 82 } ··· 105 101 } 106 102 } 107 103 108 - impl<'a, S: get_post_thread_other_v2_state::State> GetPostThreadOtherV2Builder<'a, S> { 109 - /// Set the `prioritizeFollowedUsers` field (optional) 110 - pub fn prioritize_followed_users(mut self, value: impl Into<Option<bool>>) -> Self { 111 - self.__unsafe_private_named.1 = value.into(); 112 - self 113 - } 114 - /// Set the `prioritizeFollowedUsers` field to an Option value (optional) 115 - pub fn maybe_prioritize_followed_users(mut self, value: Option<bool>) -> Self { 116 - self.__unsafe_private_named.1 = value; 117 - self 118 - } 119 - } 120 - 121 104 impl<'a, S> GetPostThreadOtherV2Builder<'a, S> 122 105 where 123 106 S: get_post_thread_other_v2_state::State, ··· 127 110 pub fn build(self) -> GetPostThreadOtherV2<'a> { 128 111 GetPostThreadOtherV2 { 129 112 anchor: self.__unsafe_private_named.0.unwrap(), 130 - prioritize_followed_users: self.__unsafe_private_named.1, 131 113 } 132 114 } 133 115 } ··· 420 402 r#enum: None, 421 403 r#const: None, 422 404 known_values: None, 423 - }), 424 - ); 425 - map.insert( 426 - ::jacquard_common::smol_str::SmolStr::new_static( 427 - "prioritizeFollowedUsers", 428 - ), 429 - ::jacquard_lexicon::lexicon::LexXrpcParametersProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean { 430 - description: None, 431 - default: None, 432 - r#const: None, 433 405 }), 434 406 ); 435 407 map
+4 -32
crates/weaver-api/src/app_bsky/unspecced/get_post_thread_v2.rs
··· 27 27 ///(default: 10, min: 0, max: 100) 28 28 #[serde(skip_serializing_if = "std::option::Option::is_none")] 29 29 pub branching_factor: std::option::Option<i64>, 30 - /// (default: false) 31 - #[serde(skip_serializing_if = "std::option::Option::is_none")] 32 - pub prioritize_followed_users: std::option::Option<bool>, 33 30 ///(default: "oldest") 34 31 #[serde(skip_serializing_if = "std::option::Option::is_none")] 35 32 #[serde(borrow)] ··· 76 73 ::core::option::Option<jacquard_common::types::string::AtUri<'a>>, 77 74 ::core::option::Option<i64>, 78 75 ::core::option::Option<i64>, 79 - ::core::option::Option<bool>, 80 76 ::core::option::Option<jacquard_common::CowStr<'a>>, 81 77 ), 82 78 _phantom: ::core::marker::PhantomData<&'a ()>, ··· 94 90 pub fn new() -> Self { 95 91 GetPostThreadV2Builder { 96 92 _phantom_state: ::core::marker::PhantomData, 97 - __unsafe_private_named: (None, None, None, None, None, None), 93 + __unsafe_private_named: (None, None, None, None, None), 98 94 _phantom: ::core::marker::PhantomData, 99 95 } 100 96 } ··· 159 155 } 160 156 161 157 impl<'a, S: get_post_thread_v2_state::State> GetPostThreadV2Builder<'a, S> { 162 - /// Set the `prioritizeFollowedUsers` field (optional) 163 - pub fn prioritize_followed_users(mut self, value: impl Into<Option<bool>>) -> Self { 164 - self.__unsafe_private_named.4 = value.into(); 165 - self 166 - } 167 - /// Set the `prioritizeFollowedUsers` field to an Option value (optional) 168 - pub fn maybe_prioritize_followed_users(mut self, value: Option<bool>) -> Self { 169 - self.__unsafe_private_named.4 = value; 170 - self 171 - } 172 - } 173 - 174 - impl<'a, S: get_post_thread_v2_state::State> GetPostThreadV2Builder<'a, S> { 175 158 /// Set the `sort` field (optional) 176 159 pub fn sort( 177 160 mut self, 178 161 value: impl Into<Option<jacquard_common::CowStr<'a>>>, 179 162 ) -> Self { 180 - self.__unsafe_private_named.5 = value.into(); 163 + self.__unsafe_private_named.4 = value.into(); 181 164 self 182 165 } 183 166 /// Set the `sort` field to an Option value (optional) 184 167 pub fn maybe_sort(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self { 185 - self.__unsafe_private_named.5 = value; 168 + self.__unsafe_private_named.4 = value; 186 169 self 187 170 } 188 171 } ··· 199 182 anchor: self.__unsafe_private_named.1.unwrap(), 200 183 below: self.__unsafe_private_named.2, 201 184 branching_factor: self.__unsafe_private_named.3, 202 - prioritize_followed_users: self.__unsafe_private_named.4, 203 - sort: self.__unsafe_private_named.5, 185 + sort: self.__unsafe_private_named.4, 204 186 } 205 187 } 206 188 } ··· 550 532 minimum: None, 551 533 maximum: None, 552 534 r#enum: None, 553 - r#const: None, 554 - }), 555 - ); 556 - map.insert( 557 - ::jacquard_common::smol_str::SmolStr::new_static( 558 - "prioritizeFollowedUsers", 559 - ), 560 - ::jacquard_lexicon::lexicon::LexXrpcParametersProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean { 561 - description: None, 562 - default: None, 563 535 r#const: None, 564 536 }), 565 537 );
+21
crates/weaver-api/src/sh_weaver/notebook.rs
··· 601 601 }), 602 602 ); 603 603 map.insert( 604 + ::jacquard_common::smol_str::SmolStr::new_static("path"), 605 + ::jacquard_lexicon::lexicon::LexUserType::String(::jacquard_lexicon::lexicon::LexString { 606 + description: Some( 607 + ::jacquard_common::CowStr::new_static( 608 + "The path of the notebook.", 609 + ), 610 + ), 611 + format: None, 612 + default: None, 613 + min_length: None, 614 + max_length: Some(100usize), 615 + min_graphemes: None, 616 + max_graphemes: None, 617 + r#enum: None, 618 + r#const: None, 619 + known_values: None, 620 + }), 621 + ); 622 + map.insert( 604 623 ::jacquard_common::smol_str::SmolStr::new_static("renderedView"), 605 624 ::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject { 606 625 description: Some( ··· 1815 1834 } 1816 1835 } 1817 1836 1837 + /// The path of the notebook. 1838 + pub type Path<'a> = jacquard_common::CowStr<'a>; 1818 1839 /// View of a rendered and cached notebook entry 1819 1840 #[jacquard_derive::lexicon] 1820 1841 #[derive(
+47 -13
crates/weaver-api/src/sh_weaver/notebook/book.rs
··· 27 27 pub entry_list: Vec<crate::com_atproto::repo::strong_ref::StrongRef<'a>>, 28 28 #[serde(skip_serializing_if = "std::option::Option::is_none")] 29 29 #[serde(borrow)] 30 + pub path: Option<crate::sh_weaver::notebook::Path<'a>>, 31 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 32 + #[serde(borrow)] 30 33 pub tags: Option<crate::sh_weaver::notebook::Tags<'a>>, 31 34 #[serde(skip_serializing_if = "std::option::Option::is_none")] 32 35 #[serde(borrow)] ··· 87 90 ::core::option::Option<Vec<crate::sh_weaver::actor::Author<'a>>>, 88 91 ::core::option::Option<jacquard_common::types::string::Datetime>, 89 92 ::core::option::Option<Vec<crate::com_atproto::repo::strong_ref::StrongRef<'a>>>, 93 + ::core::option::Option<crate::sh_weaver::notebook::Path<'a>>, 90 94 ::core::option::Option<crate::sh_weaver::notebook::Tags<'a>>, 91 95 ::core::option::Option<crate::com_atproto::repo::strong_ref::StrongRef<'a>>, 92 96 ::core::option::Option<crate::sh_weaver::notebook::Title<'a>>, ··· 106 110 pub fn new() -> Self { 107 111 BookBuilder { 108 112 _phantom_state: ::core::marker::PhantomData, 109 - __unsafe_private_named: (None, None, None, None, None, None), 113 + __unsafe_private_named: (None, None, None, None, None, None, None), 110 114 _phantom: ::core::marker::PhantomData, 111 115 } 112 116 } ··· 170 174 } 171 175 172 176 impl<'a, S: book_state::State> BookBuilder<'a, S> { 177 + /// Set the `path` field (optional) 178 + pub fn path( 179 + mut self, 180 + value: impl Into<Option<crate::sh_weaver::notebook::Path<'a>>>, 181 + ) -> Self { 182 + self.__unsafe_private_named.3 = value.into(); 183 + self 184 + } 185 + /// Set the `path` field to an Option value (optional) 186 + pub fn maybe_path( 187 + mut self, 188 + value: Option<crate::sh_weaver::notebook::Path<'a>>, 189 + ) -> Self { 190 + self.__unsafe_private_named.3 = value; 191 + self 192 + } 193 + } 194 + 195 + impl<'a, S: book_state::State> BookBuilder<'a, S> { 173 196 /// Set the `tags` field (optional) 174 197 pub fn tags( 175 198 mut self, 176 199 value: impl Into<Option<crate::sh_weaver::notebook::Tags<'a>>>, 177 200 ) -> Self { 178 - self.__unsafe_private_named.3 = value.into(); 201 + self.__unsafe_private_named.4 = value.into(); 179 202 self 180 203 } 181 204 /// Set the `tags` field to an Option value (optional) ··· 183 206 mut self, 184 207 value: Option<crate::sh_weaver::notebook::Tags<'a>>, 185 208 ) -> Self { 186 - self.__unsafe_private_named.3 = value; 209 + self.__unsafe_private_named.4 = value; 187 210 self 188 211 } 189 212 } ··· 194 217 mut self, 195 218 value: impl Into<Option<crate::com_atproto::repo::strong_ref::StrongRef<'a>>>, 196 219 ) -> Self { 197 - self.__unsafe_private_named.4 = value.into(); 220 + self.__unsafe_private_named.5 = value.into(); 198 221 self 199 222 } 200 223 /// Set the `theme` field to an Option value (optional) ··· 202 225 mut self, 203 226 value: Option<crate::com_atproto::repo::strong_ref::StrongRef<'a>>, 204 227 ) -> Self { 205 - self.__unsafe_private_named.4 = value; 228 + self.__unsafe_private_named.5 = value; 206 229 self 207 230 } 208 231 } ··· 213 236 mut self, 214 237 value: impl Into<Option<crate::sh_weaver::notebook::Title<'a>>>, 215 238 ) -> Self { 216 - self.__unsafe_private_named.5 = value.into(); 239 + self.__unsafe_private_named.6 = value.into(); 217 240 self 218 241 } 219 242 /// Set the `title` field to an Option value (optional) ··· 221 244 mut self, 222 245 value: Option<crate::sh_weaver::notebook::Title<'a>>, 223 246 ) -> Self { 224 - self.__unsafe_private_named.5 = value; 247 + self.__unsafe_private_named.6 = value; 225 248 self 226 249 } 227 250 } ··· 238 261 authors: self.__unsafe_private_named.0.unwrap(), 239 262 created_at: self.__unsafe_private_named.1, 240 263 entry_list: self.__unsafe_private_named.2.unwrap(), 241 - tags: self.__unsafe_private_named.3, 242 - theme: self.__unsafe_private_named.4, 243 - title: self.__unsafe_private_named.5, 264 + path: self.__unsafe_private_named.3, 265 + tags: self.__unsafe_private_named.4, 266 + theme: self.__unsafe_private_named.5, 267 + title: self.__unsafe_private_named.6, 244 268 extra_data: Default::default(), 245 269 } 246 270 } ··· 256 280 authors: self.__unsafe_private_named.0.unwrap(), 257 281 created_at: self.__unsafe_private_named.1, 258 282 entry_list: self.__unsafe_private_named.2.unwrap(), 259 - tags: self.__unsafe_private_named.3, 260 - theme: self.__unsafe_private_named.4, 261 - title: self.__unsafe_private_named.5, 283 + path: self.__unsafe_private_named.3, 284 + tags: self.__unsafe_private_named.4, 285 + theme: self.__unsafe_private_named.5, 286 + title: self.__unsafe_private_named.6, 262 287 extra_data: Some(extra_data), 263 288 } 264 289 } ··· 424 449 }), 425 450 min_length: None, 426 451 max_length: None, 452 + }), 453 + ); 454 + map.insert( 455 + ::jacquard_common::smol_str::SmolStr::new_static("path"), 456 + ::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef { 457 + description: None, 458 + r#ref: ::jacquard_common::CowStr::new_static( 459 + "sh.weaver.notebook.defs#path", 460 + ), 427 461 }), 428 462 ); 429 463 map.insert(
+1 -1
crates/weaver-appview/Cargo.toml crates/weaver-app-server/Cargo.toml
··· 1 1 [package] 2 - name = "weaver-appview" 2 + name = "weaver-app-server" 3 3 version.workspace = true 4 4 edition.workspace = true 5 5 license.workspace = true
crates/weaver-appview/appview-config.toml crates/weaver-app-server/appview-config.toml
crates/weaver-appview/build.rs crates/weaver-app-server/build.rs
crates/weaver-appview/diesel.toml crates/weaver-app-server/diesel.toml
crates/weaver-appview/migrations/.keep crates/weaver-app-server/migrations/.keep
crates/weaver-appview/migrations/00000000000000_diesel_initial_setup/down.sql crates/weaver-app-server/migrations/00000000000000_diesel_initial_setup/down.sql
crates/weaver-appview/migrations/00000000000000_diesel_initial_setup/up.sql crates/weaver-app-server/migrations/00000000000000_diesel_initial_setup/up.sql
crates/weaver-appview/migrations/2025-05-15-230036_create_appviewdb/down.sql crates/weaver-app-server/migrations/2025-05-15-230036_create_appviewdb/down.sql
crates/weaver-appview/migrations/2025-05-15-230036_create_appviewdb/up.sql crates/weaver-app-server/migrations/2025-05-15-230036_create_appviewdb/up.sql
crates/weaver-appview/src/api_error.rs crates/weaver-app-server/src/api_error.rs
crates/weaver-appview/src/config.rs crates/weaver-app-server/src/config.rs
crates/weaver-appview/src/db.rs crates/weaver-app-server/src/db.rs
crates/weaver-appview/src/main.rs crates/weaver-app-server/src/main.rs
crates/weaver-appview/src/middleware.rs crates/weaver-app-server/src/middleware.rs
crates/weaver-appview/src/models.rs crates/weaver-app-server/src/models.rs
crates/weaver-appview/src/oauth.rs crates/weaver-app-server/src/oauth.rs
crates/weaver-appview/src/routes/health_check.rs crates/weaver-app-server/src/routes/health_check.rs
crates/weaver-appview/src/routes/login.rs crates/weaver-app-server/src/routes/login.rs
crates/weaver-appview/src/routes/logout.rs crates/weaver-app-server/src/routes/logout.rs
crates/weaver-appview/src/routes/mod.rs crates/weaver-app-server/src/routes/mod.rs
crates/weaver-appview/src/routes/oauth.rs crates/weaver-app-server/src/routes/oauth.rs
crates/weaver-appview/src/schema.rs crates/weaver-app-server/src/schema.rs
crates/weaver-appview/src/state.rs crates/weaver-app-server/src/state.rs
crates/weaver-appview/src/telemetry.rs crates/weaver-app-server/src/telemetry.rs
+1
crates/weaver-common/Cargo.toml
··· 19 19 http = "1.3.1" 20 20 21 21 jacquard = { workspace = true } 22 + jacquard-common = { workspace = true } 22 23 trait-variant = "0.1" 23 24 24 25 serde = { workspace = true }
+71
crates/weaver-common/src/constellation.rs
··· 1 + use jacquard::{ 2 + CowStr, IntoStatic, XrpcRequest, 3 + types::{ 4 + did::Did, 5 + nsid::Nsid, 6 + string::{RecordKey, Rkey}, 7 + }, 8 + }; 9 + use serde::{Deserialize, Serialize}; 10 + 11 + const DEFAULT_CURSOR_LIMIT: u64 = 16; 12 + const DEFAULT_CURSOR_LIMIT_MAX: u64 = 100; 13 + 14 + fn get_default_cursor_limit() -> u64 { 15 + DEFAULT_CURSOR_LIMIT 16 + } 17 + 18 + #[derive(Clone, Deserialize, Serialize, XrpcRequest, IntoStatic)] 19 + #[xrpc( 20 + nsid = "blue.microcosm.links.getBacklinks", 21 + method = Query, 22 + output = GetBacklinksResponse, 23 + )] 24 + pub struct GetBacklinksQuery<'a> { 25 + /// The link target 26 + /// 27 + /// can be an AT-URI, plain DID, or regular URI 28 + subject: jacquard::types::uri::Uri<'a>, 29 + /// Filter links only from this link source 30 + /// 31 + /// eg.: `app.bsky.feed.like:subject.uri` 32 + source: CowStr<'a>, 33 + #[serde(borrow)] 34 + cursor: Option<CowStr<'a>>, 35 + /// Filter links only from these DIDs 36 + /// 37 + /// include multiple times to filter by multiple source DIDs 38 + #[serde(default)] 39 + did: Vec<Did<'a>>, 40 + /// Set the max number of links to return per page of results 41 + #[serde(default = "get_default_cursor_limit")] 42 + limit: u64, 43 + // TODO: allow reverse (er, forward) order as well 44 + } 45 + #[derive(Deserialize, Serialize, IntoStatic)] 46 + pub struct GetBacklinksResponse<'a> { 47 + total: u64, 48 + #[serde(borrow)] 49 + records: Vec<RecordId<'a>>, 50 + cursor: Option<CowStr<'a>>, 51 + } 52 + 53 + #[derive(Debug, PartialEq, Serialize, Deserialize, IntoStatic)] 54 + pub struct RecordId<'a> { 55 + #[serde(borrow)] 56 + pub did: Did<'a>, 57 + pub collection: Nsid<'a>, 58 + pub rkey: RecordKey<Rkey<'a>>, 59 + } 60 + 61 + impl RecordId<'_> { 62 + pub fn did(&self) -> Did<'_> { 63 + self.did.clone() 64 + } 65 + pub fn collection(&self) -> Nsid<'_> { 66 + self.collection.clone() 67 + } 68 + pub fn rkey(&self) -> RecordKey<Rkey<'_>> { 69 + self.rkey.clone() 70 + } 71 + }
+1
crates/weaver-common/src/lib.rs
··· 1 1 //! Weaver common library - thin wrapper around jacquard with notebook-specific conveniences 2 2 3 + pub mod constellation; 3 4 pub mod error; 4 5 pub mod view; 5 6
crates/weaver-server/.gitignore crates/weaver-app/.gitignore
+1 -1
crates/weaver-server/Cargo.toml crates/weaver-app/Cargo.toml
··· 1 1 [package] 2 - name = "weaver-server" 2 + name = "weaver-app" 3 3 version = "0.1.0" 4 4 authors = ["Orual <orual@nonbinary.computer>"] 5 5 edition = "2021"
crates/weaver-server/Dioxus.toml crates/weaver-app/Dioxus.toml
crates/weaver-server/README.md crates/weaver-app/README.md
crates/weaver-server/assets/dx-components-theme.css crates/weaver-app/assets/dx-components-theme.css
crates/weaver-server/assets/fonts/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf crates/weaver-app/assets/fonts/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf
crates/weaver-server/assets/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf crates/weaver-app/assets/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf
crates/weaver-server/assets/styling/entry-card.css crates/weaver-app/assets/styling/entry-card.css
crates/weaver-server/assets/styling/entry.css crates/weaver-app/assets/styling/entry.css
crates/weaver-server/assets/styling/main.css crates/weaver-app/assets/styling/main.css
crates/weaver-server/assets/styling/navbar.css crates/weaver-app/assets/styling/navbar.css
crates/weaver-server/assets/styling/notebook-card.css crates/weaver-app/assets/styling/notebook-card.css
crates/weaver-server/assets/styling/theme-defaults.css crates/weaver-app/assets/styling/theme-defaults.css
crates/weaver-server/assets/weaver_photo_sm.jpg crates/weaver-app/assets/weaver_photo_sm.jpg
crates/weaver-server/src/blobcache.rs crates/weaver-app/src/blobcache.rs
crates/weaver-server/src/cache_impl.rs crates/weaver-app/src/cache_impl.rs
crates/weaver-server/src/components/avatar/component.rs crates/weaver-app/src/components/avatar/component.rs
crates/weaver-server/src/components/avatar/mod.rs crates/weaver-app/src/components/avatar/mod.rs
crates/weaver-server/src/components/avatar/style.css crates/weaver-app/src/components/avatar/style.css
+3 -3
crates/weaver-server/src/components/css.rs crates/weaver-app/src/components/css.rs
··· 15 15 #[allow(unused_imports)] 16 16 use std::sync::Arc; 17 17 #[allow(unused_imports)] 18 - use weaver_renderer::theme::{Theme, ResolvedTheme}; 18 + use weaver_renderer::theme::{ResolvedTheme, Theme}; 19 19 20 20 #[cfg(feature = "server")] 21 21 use axum::{extract::Extension, response::IntoResponse}; ··· 24 24 pub fn NotebookCss(ident: SmolStr, notebook: SmolStr) -> Element { 25 25 rsx! { 26 26 document::Stylesheet { 27 - href: "{get_server_url()}/css/{ident}/{notebook}" 27 + href: "{get_server_url()}/{ident}/{notebook}/css" 28 28 } 29 29 } 30 30 } 31 31 32 - #[get("/css/{ident}/{notebook}", fetcher: Extension<Arc<fetch::CachedFetcher>>)] 32 + #[get("/{ident}/{notebook}/css", fetcher: Extension<Arc<fetch::CachedFetcher>>)] 33 33 pub async fn css(ident: SmolStr, notebook: SmolStr) -> Result<Response> { 34 34 use jacquard::client::AgentSessionExt; 35 35 use jacquard::types::ident::AtIdentifier;
crates/weaver-server/src/components/entry.rs crates/weaver-app/src/components/entry.rs
crates/weaver-server/src/components/identity.rs crates/weaver-app/src/components/identity.rs
crates/weaver-server/src/components/mod.rs crates/weaver-app/src/components/mod.rs
crates/weaver-server/src/fetch.rs crates/weaver-app/src/fetch.rs
crates/weaver-server/src/main.rs crates/weaver-app/src/main.rs
crates/weaver-server/src/views/home.rs crates/weaver-app/src/views/home.rs
crates/weaver-server/src/views/mod.rs crates/weaver-app/src/views/mod.rs
crates/weaver-server/src/views/navbar.rs crates/weaver-app/src/views/navbar.rs
crates/weaver-server/src/views/notebook.rs crates/weaver-app/src/views/notebook.rs
crates/weaver-server/src/views/notebookpage.rs crates/weaver-app/src/views/notebookpage.rs
+8 -8
flake.nix
··· 120 120 cargoExtraArgs = "-p ${name}-cli"; 121 121 src = fileSetForCrate ./crates/weaver-cli; 122 122 }); 123 - weaver-server = craneLib.buildPackage (individualCrateArgs 123 + weaver-app = craneLib.buildPackage (individualCrateArgs 124 124 // { 125 - pname = "${name}-server"; 126 - cargoExtraArgs = "-p ${name}-server"; 125 + pname = "${name}-app"; 126 + cargoExtraArgs = "-p ${name}-app"; 127 127 src = fileSetForCrate ./crates/weaver-server; 128 128 }); 129 129 weaver-renderer = craneLib.buildPackage (individualCrateArgs ··· 135 135 in { 136 136 checks = { 137 137 # Build the crates as part of `nix flake check` for convenience 138 - inherit weaver-cli weaver-server weaver-renderer; 138 + inherit weaver-cli weaver-app weaver-renderer; 139 139 140 140 # Run clippy (and deny all warnings) on the workspace source, 141 141 # again, reusing the dependency artifacts from above. ··· 189 189 190 190 packages = 191 191 { 192 - inherit weaver-cli weaver-server; 192 + inherit weaver-cli weaver-app; 193 193 } 194 194 // lib.optionalAttrs (!pkgs.stdenv.isDarwin) { 195 195 # weaver-workspace-llvm-coverage = craneLibLLvmTools.cargoLlvmCov (commonArgs // { ··· 202 202 drv = weaver-cli; 203 203 }; 204 204 weaver-server = flake-utils.lib.mkApp { 205 - drv = weaver-server; 205 + drv = weaver-app; 206 206 }; 207 207 }; 208 208 ··· 210 210 # dioxus-cli = pkgs.dioxus-cli.overrideAttrs (_: { 211 211 # postPatch = '' 212 212 # rm Cargo.lock 213 - # cp ${./crates/weaver-server/Dioxus.lock} Cargo.lock 213 + # cp ${./crates/weaver-app/Dioxus.lock} Cargo.lock 214 214 # ''; 215 215 # cargoDeps = pkgs.rustPlatform.importCargoLock { 216 - # lockFile = ./crates/weaver-server/Dioxus.lock; 216 + # lockFile = ./crates/weaver-app/Dioxus.lock; 217 217 # }; 218 218 # }); 219 219 cargoLock = builtins.fromTOML (builtins.readFile ./Cargo.lock);
+3 -5
lexicons/actor/defs.json
··· 111 111 "required": ["did"], 112 112 "properties": { 113 113 "did": { "type": "string", "format": "did" }, 114 - "handle": { "type": "string", "format": "handle" }, 115 - "displayName": { 116 - "type": "string", 117 - "maxGraphemes": 64, 118 - "maxLength": 640 114 + "signature": { 115 + "type": "bytes" 116 + "description": "signed bytes of the corresponding notebook record in the author's repo" 119 117 } 120 118 } 121 119 },
+1
lexicons/notebook/book.json
··· 11 11 "required": ["authors", "entryList"], 12 12 "properties": { 13 13 "title": { "type": "ref", "ref": "sh.weaver.notebook.defs#title" }, 14 + "path": { "type": "ref", "ref": "sh.weaver.notebook.defs#path" }, 14 15 "tags": { "type": "ref", "ref": "sh.weaver.notebook.defs#tags" }, 15 16 "authors": { 16 17 "type": "array",
+5
lexicons/notebook/defs.json
··· 104 104 "maxLength": 300, 105 105 "description": "The title of the notebook entry." 106 106 }, 107 + "path": { 108 + "type": "string", 109 + "maxLength": 100, 110 + "description": "The path of the notebook." 111 + }, 107 112 "tags": { 108 113 "type": "array", 109 114 "items": {
+6 -5
weaver_notes/.obsidian/workspace.json
··· 13 13 "state": { 14 14 "type": "markdown", 15 15 "state": { 16 - "file": "Weaver - Long-form writing.md", 16 + "file": "Arch.md", 17 17 "mode": "source", 18 18 "source": false 19 19 }, 20 20 "icon": "lucide-file", 21 - "title": "Weaver - Long-form writing" 21 + "title": "Arch" 22 22 } 23 23 } 24 24 ] ··· 94 94 "state": { 95 95 "type": "backlink", 96 96 "state": { 97 - "file": "Weaver - Long-form writing.md", 97 + "file": "Arch.md", 98 98 "collapseAll": false, 99 99 "extraContext": false, 100 100 "sortOrder": "alphabetical", ··· 104 104 "unlinkedCollapsed": true 105 105 }, 106 106 "icon": "links-coming-in", 107 - "title": "Backlinks for Weaver - Long-form writing" 107 + "title": "Backlinks for Arch" 108 108 } 109 109 }, 110 110 { ··· 170 170 }, 171 171 "active": "f41bdf1f327c8668", 172 172 "lastOpenFiles": [ 173 + "Weaver - Long-form writing.md", 174 + "Arch.md", 173 175 "weaver_photo_med.jpg", 174 176 "xkcd_345_excerpt.png", 175 - "Weaver - Long-form writing.md", 176 177 "light_mode_excerpt.png", 177 178 "notebook_entry_preview.png" 178 179 ]
+22
weaver_notes/Arch.md
··· 1 + ## Viewer/minimal app 2 + 3 + #### Routes - names can be title/name or rkey, ident can be did or handle 4 + /{ident}/{notebook}/{entry} - entry 5 + /{ident}/{notebook}/{page} - page of entries 6 + /{ident}/{notebook}/{chapter}/{entry|page} - entry/page in chapter 7 + /{ident}/{notebook} - index/"cover page" 8 + /{ident} - profile page 9 + 10 + / - discover (later, home) 11 + 12 + 13 + /record/{at-uri} - fallback viewer? 14 + /post/{at-uri} - bsky post, anything similarly shaped 15 + /leaflet/{pub}/{rkey} - leaflet 16 + /blog/{at-uri} - whitewind, etc. 17 + /feed/{at-uri} 18 + 19 + 20 + /{notebook}/image/{name|cid} 21 + /{notebook}/blob/{cid} 22 + /{ident}/{notebook}/css