atproto blogging
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Removed the lazy submodules

Also some new lexicons related to loro CRDT format

Orual 5955cd94 9333b794

+1060 -311
-5
.zed/settings.json
··· 12 12 } 13 13 } 14 14 } 15 - }, 16 - "rust-analyzer": { 17 - "binary": { 18 - "path_lookup": true 19 - } 20 15 } 21 16 }
+161 -194
Cargo.lock
··· 429 429 430 430 [[package]] 431 431 name = "bitflags" 432 - version = "2.9.0" 432 + version = "2.9.1" 433 433 source = "registry+https://github.com/rust-lang/crates.io-index" 434 - checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 434 + checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 435 435 436 436 [[package]] 437 437 name = "block-buffer" ··· 498 498 checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 499 499 500 500 [[package]] 501 - name = "camino" 502 - version = "1.1.9" 503 - source = "registry+https://github.com/rust-lang/crates.io-index" 504 - checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" 505 - 506 - [[package]] 507 501 name = "castaway" 508 502 version = "0.2.3" 509 503 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 523 517 524 518 [[package]] 525 519 name = "cc" 526 - version = "1.2.22" 520 + version = "1.2.23" 527 521 source = "registry+https://github.com/rust-lang/crates.io-index" 528 - checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" 522 + checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" 529 523 dependencies = [ 530 524 "shlex", 531 525 ] ··· 968 962 source = "registry+https://github.com/rust-lang/crates.io-index" 969 963 checksum = "ff3e1edb1f37b4953dd5176916347289ed43d7119cc2e6c7c3f7849ff44ea506" 970 964 dependencies = [ 971 - "bitflags 2.9.0", 965 + "bitflags 2.9.1", 972 966 "byteorder", 973 967 "chrono", 974 968 "diesel_derives", ··· 1040 1034 ] 1041 1035 1042 1036 [[package]] 1037 + name = "dirs" 1038 + version = "6.0.0" 1039 + source = "registry+https://github.com/rust-lang/crates.io-index" 1040 + checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" 1041 + dependencies = [ 1042 + "dirs-sys", 1043 + ] 1044 + 1045 + [[package]] 1046 + name = "dirs-sys" 1047 + version = "0.5.0" 1048 + source = "registry+https://github.com/rust-lang/crates.io-index" 1049 + checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" 1050 + dependencies = [ 1051 + "libc", 1052 + "option-ext", 1053 + "redox_users", 1054 + "windows-sys 0.59.0", 1055 + ] 1056 + 1057 + [[package]] 1043 1058 name = "displaydoc" 1044 1059 version = "0.2.5" 1045 1060 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1165 1180 1166 1181 [[package]] 1167 1182 name = "errno" 1168 - version = "0.3.11" 1183 + version = "0.3.12" 1169 1184 source = "registry+https://github.com/rust-lang/crates.io-index" 1170 - checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" 1185 + checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" 1171 1186 dependencies = [ 1172 1187 "libc", 1173 1188 "windows-sys 0.59.0", ··· 1217 1232 checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 1218 1233 1219 1234 [[package]] 1220 - name = "fallible-iterator" 1221 - version = "0.3.0" 1222 - source = "registry+https://github.com/rust-lang/crates.io-index" 1223 - checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" 1224 - 1225 - [[package]] 1226 - name = "fallible-streaming-iterator" 1227 - version = "0.1.9" 1228 - source = "registry+https://github.com/rust-lang/crates.io-index" 1229 - checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" 1230 - 1231 - [[package]] 1232 1235 name = "fastrand" 1233 1236 version = "2.3.0" 1234 1237 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1415 1418 1416 1419 [[package]] 1417 1420 name = "generator" 1418 - version = "0.8.4" 1421 + version = "0.8.5" 1419 1422 source = "registry+https://github.com/rust-lang/crates.io-index" 1420 - checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" 1423 + checksum = "d18470a76cb7f8ff746cf1f7470914f900252ec36bbc40b569d74b1258446827" 1421 1424 dependencies = [ 1425 + "cc", 1422 1426 "cfg-if", 1423 1427 "libc", 1424 1428 "log", ··· 1467 1471 checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 1468 1472 dependencies = [ 1469 1473 "cfg-if", 1474 + "js-sys", 1470 1475 "libc", 1471 1476 "r-efi", 1472 1477 "wasi 0.14.2+wasi-0.2.4", 1478 + "wasm-bindgen", 1473 1479 ] 1474 1480 1475 1481 [[package]] ··· 1561 1567 ] 1562 1568 1563 1569 [[package]] 1564 - name = "hashlink" 1565 - version = "0.9.1" 1566 - source = "registry+https://github.com/rust-lang/crates.io-index" 1567 - checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" 1568 - dependencies = [ 1569 - "hashbrown 0.14.5", 1570 - ] 1571 - 1572 - [[package]] 1573 1570 name = "heck" 1574 1571 version = "0.4.1" 1575 1572 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1938 1935 source = "registry+https://github.com/rust-lang/crates.io-index" 1939 1936 checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" 1940 1937 dependencies = [ 1941 - "bitflags 2.9.0", 1938 + "bitflags 2.9.1", 1942 1939 "inotify-sys", 1943 1940 "libc", 1944 1941 ] ··· 2138 2135 ] 2139 2136 2140 2137 [[package]] 2141 - name = "lexical-parse-float" 2142 - version = "0.8.5" 2143 - source = "registry+https://github.com/rust-lang/crates.io-index" 2144 - checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" 2145 - dependencies = [ 2146 - "lexical-parse-integer", 2147 - "lexical-util", 2148 - "static_assertions", 2149 - ] 2150 - 2151 - [[package]] 2152 - name = "lexical-parse-integer" 2153 - version = "0.8.6" 2154 - source = "registry+https://github.com/rust-lang/crates.io-index" 2155 - checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" 2156 - dependencies = [ 2157 - "lexical-util", 2158 - "static_assertions", 2159 - ] 2160 - 2161 - [[package]] 2162 - name = "lexical-util" 2163 - version = "0.8.5" 2164 - source = "registry+https://github.com/rust-lang/crates.io-index" 2165 - checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" 2166 - dependencies = [ 2167 - "static_assertions", 2168 - ] 2169 - 2170 - [[package]] 2171 2138 name = "libc" 2172 2139 version = "0.2.172" 2173 2140 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2185 2152 source = "registry+https://github.com/rust-lang/crates.io-index" 2186 2153 checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 2187 2154 dependencies = [ 2188 - "bitflags 2.9.0", 2155 + "bitflags 2.9.1", 2189 2156 "libc", 2190 2157 "redox_syscall", 2191 2158 ] ··· 2196 2163 source = "registry+https://github.com/rust-lang/crates.io-index" 2197 2164 checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" 2198 2165 dependencies = [ 2199 - "cc", 2200 2166 "pkg-config", 2201 2167 "vcpkg", 2202 2168 ] ··· 2267 2233 ] 2268 2234 2269 2235 [[package]] 2236 + name = "lru-slab" 2237 + version = "0.1.2" 2238 + source = "registry+https://github.com/rust-lang/crates.io-index" 2239 + checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" 2240 + 2241 + [[package]] 2270 2242 name = "markdown-weaver" 2271 2243 version = "0.13.0" 2272 - source = "git+https://github.com/rsform/markdown-weaver#34bc7ad2d7e6e9b9604ba61602b68589f271404e" 2244 + source = "git+https://github.com/rsform/markdown-weaver#593f968ec3c4515c23273715eaeb33801342439b" 2273 2245 dependencies = [ 2274 - "bitflags 2.9.0", 2246 + "bitflags 2.9.1", 2275 2247 "getopts", 2276 2248 "markdown-weaver-escape", 2277 2249 "memchr", 2278 - "serde", 2279 2250 "unicase", 2280 2251 ] 2281 2252 2282 2253 [[package]] 2283 2254 name = "markdown-weaver-escape" 2284 2255 version = "0.11.0" 2285 - source = "git+https://github.com/rsform/markdown-weaver#34bc7ad2d7e6e9b9604ba61602b68589f271404e" 2256 + source = "git+https://github.com/rsform/markdown-weaver#593f968ec3c4515c23273715eaeb33801342439b" 2286 2257 2287 2258 [[package]] 2288 2259 name = "matchers" ··· 2326 2297 2327 2298 [[package]] 2328 2299 name = "merde" 2329 - version = "10.0.6" 2300 + version = "10.0.7" 2330 2301 source = "registry+https://github.com/rust-lang/crates.io-index" 2331 - checksum = "5ec14139b169a3bb101da2dd8c0c2e47ddaf63000075662635c64c985bb5ae7b" 2302 + checksum = "edd8dc7668eb89ede52dc09d4b21a8c2f7c9cd47168ea1f82550f705615d9b99" 2332 2303 dependencies = [ 2333 2304 "merde_core", 2334 - "merde_json", 2335 - "merde_msgpack", 2336 2305 "merde_yaml", 2337 2306 ] 2338 2307 2339 2308 [[package]] 2340 2309 name = "merde_core" 2341 - version = "10.0.5" 2310 + version = "10.0.6" 2342 2311 source = "registry+https://github.com/rust-lang/crates.io-index" 2343 - checksum = "714d8f25279d095f8d23392476e2e82427e8689348e34f90ddc0712497e157de" 2312 + checksum = "e937026f22a5a3567bc402f1edf871ecab0e0222cd6f829ea58abae0185e759c" 2344 2313 dependencies = [ 2345 - "camino", 2346 2314 "compact_bytes", 2347 2315 "compact_str", 2348 - "ordered-float 4.6.0", 2349 - "rusqlite", 2316 + "ordered-float 5.0.0", 2350 2317 "serde", 2351 - "time", 2352 - ] 2353 - 2354 - [[package]] 2355 - name = "merde_json" 2356 - version = "10.0.5" 2357 - source = "registry+https://github.com/rust-lang/crates.io-index" 2358 - checksum = "d354c179fe95a0568c8ffb95c276f73556ecb95edca76f742505320e7545cea9" 2359 - dependencies = [ 2360 - "itoa", 2361 - "lexical-parse-float", 2362 - "merde_core", 2363 - "ryu", 2364 - ] 2365 - 2366 - [[package]] 2367 - name = "merde_msgpack" 2368 - version = "10.0.5" 2369 - source = "registry+https://github.com/rust-lang/crates.io-index" 2370 - checksum = "f2b710370fee77ca3cb8e6666a2586f26f3a653d7b2e338ede77a13c99108c5e" 2371 - dependencies = [ 2372 - "merde_core", 2373 - "rmp", 2374 2318 ] 2375 2319 2376 2320 [[package]] 2377 2321 name = "merde_yaml" 2378 - version = "10.0.5" 2322 + version = "10.0.6" 2379 2323 source = "registry+https://github.com/rust-lang/crates.io-index" 2380 - checksum = "cb581c31249876b3b385a2cc50fafc666adc9c316874819b7aac7266b3c26c17" 2324 + checksum = "7c36f61da594ecad0ed986ceeb5061eba47a36fcf839576ce525c7e4ff08f3fa" 2381 2325 dependencies = [ 2382 2326 "merde_core", 2383 2327 "yaml-rust2", ··· 2597 2541 source = "registry+https://github.com/rust-lang/crates.io-index" 2598 2542 checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" 2599 2543 dependencies = [ 2600 - "bitflags 2.9.0", 2544 + "bitflags 2.9.1", 2601 2545 "filetime", 2602 2546 "fsevent-sys", 2603 2547 "inotify", ··· 2741 2685 source = "registry+https://github.com/rust-lang/crates.io-index" 2742 2686 checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" 2743 2687 dependencies = [ 2744 - "bitflags 2.9.0", 2688 + "bitflags 2.9.1", 2745 2689 "cfg-if", 2746 2690 "foreign-types", 2747 2691 "libc", ··· 2780 2724 ] 2781 2725 2782 2726 [[package]] 2727 + name = "option-ext" 2728 + version = "0.2.0" 2729 + source = "registry+https://github.com/rust-lang/crates.io-index" 2730 + checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 2731 + 2732 + [[package]] 2783 2733 name = "ordered-float" 2784 2734 version = "2.10.1" 2785 2735 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2790 2740 2791 2741 [[package]] 2792 2742 name = "ordered-float" 2793 - version = "4.6.0" 2743 + version = "5.0.0" 2794 2744 source = "registry+https://github.com/rust-lang/crates.io-index" 2795 - checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" 2745 + checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01" 2796 2746 dependencies = [ 2797 2747 "num-traits", 2798 2748 ] ··· 2805 2755 2806 2756 [[package]] 2807 2757 name = "owo-colors" 2808 - version = "4.2.0" 2758 + version = "4.2.1" 2809 2759 source = "registry+https://github.com/rust-lang/crates.io-index" 2810 - checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" 2760 + checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" 2811 2761 2812 2762 [[package]] 2813 2763 name = "p256" ··· 2863 2813 ] 2864 2814 2865 2815 [[package]] 2866 - name = "paste" 2867 - version = "1.0.15" 2868 - source = "registry+https://github.com/rust-lang/crates.io-index" 2869 - checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 2870 - 2871 - [[package]] 2872 2816 name = "pem-rfc7468" 2873 2817 version = "0.7.0" 2874 2818 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2988 2932 "base64 0.22.1", 2989 2933 "byteorder", 2990 2934 "bytes", 2991 - "fallible-iterator 0.2.0", 2935 + "fallible-iterator", 2992 2936 "hmac", 2993 2937 "md-5", 2994 2938 "memchr", ··· 3004 2948 checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" 3005 2949 dependencies = [ 3006 2950 "bytes", 3007 - "fallible-iterator 0.2.0", 2951 + "fallible-iterator", 3008 2952 "postgres-protocol", 3009 2953 ] 3010 2954 ··· 3087 3031 3088 3032 [[package]] 3089 3033 name = "quinn" 3090 - version = "0.11.6" 3034 + version = "0.11.8" 3091 3035 source = "registry+https://github.com/rust-lang/crates.io-index" 3092 - checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" 3036 + checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" 3093 3037 dependencies = [ 3094 3038 "bytes", 3039 + "cfg_aliases", 3095 3040 "pin-project-lite", 3096 3041 "quinn-proto", 3097 3042 "quinn-udp", ··· 3101 3046 "thiserror 2.0.12", 3102 3047 "tokio", 3103 3048 "tracing", 3049 + "web-time", 3104 3050 ] 3105 3051 3106 3052 [[package]] 3107 3053 name = "quinn-proto" 3108 - version = "0.11.9" 3054 + version = "0.11.12" 3109 3055 source = "registry+https://github.com/rust-lang/crates.io-index" 3110 - checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" 3056 + checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" 3111 3057 dependencies = [ 3112 3058 "bytes", 3113 - "getrandom 0.2.16", 3114 - "rand 0.8.5", 3059 + "getrandom 0.3.3", 3060 + "lru-slab", 3061 + "rand 0.9.1", 3115 3062 "ring 0.17.14", 3116 3063 "rustc-hash", 3117 3064 "rustls 0.23.27", ··· 3125 3072 3126 3073 [[package]] 3127 3074 name = "quinn-udp" 3128 - version = "0.5.9" 3075 + version = "0.5.12" 3129 3076 source = "registry+https://github.com/rust-lang/crates.io-index" 3130 - checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" 3077 + checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" 3131 3078 dependencies = [ 3132 3079 "cfg_aliases", 3133 3080 "libc", ··· 3217 3164 source = "registry+https://github.com/rust-lang/crates.io-index" 3218 3165 checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" 3219 3166 dependencies = [ 3220 - "bitflags 2.9.0", 3167 + "bitflags 2.9.1", 3168 + ] 3169 + 3170 + [[package]] 3171 + name = "redox_users" 3172 + version = "0.5.0" 3173 + source = "registry+https://github.com/rust-lang/crates.io-index" 3174 + checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" 3175 + dependencies = [ 3176 + "getrandom 0.2.16", 3177 + "libredox", 3178 + "thiserror 2.0.12", 3221 3179 ] 3222 3180 3223 3181 [[package]] ··· 3381 3339 ] 3382 3340 3383 3341 [[package]] 3384 - name = "rmp" 3385 - version = "0.8.14" 3386 - source = "registry+https://github.com/rust-lang/crates.io-index" 3387 - checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" 3388 - dependencies = [ 3389 - "byteorder", 3390 - "num-traits", 3391 - "paste", 3392 - ] 3393 - 3394 - [[package]] 3395 3342 name = "rouille" 3396 3343 version = "3.6.2" 3397 3344 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3436 3383 ] 3437 3384 3438 3385 [[package]] 3439 - name = "rusqlite" 3440 - version = "0.32.1" 3441 - source = "registry+https://github.com/rust-lang/crates.io-index" 3442 - checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" 3443 - dependencies = [ 3444 - "bitflags 2.9.0", 3445 - "fallible-iterator 0.3.0", 3446 - "fallible-streaming-iterator", 3447 - "hashlink 0.9.1", 3448 - "libsqlite3-sys", 3449 - "smallvec", 3450 - ] 3451 - 3452 - [[package]] 3453 3386 name = "rustc-demangle" 3454 3387 version = "0.1.24" 3455 3388 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3476 3409 source = "registry+https://github.com/rust-lang/crates.io-index" 3477 3410 checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" 3478 3411 dependencies = [ 3479 - "bitflags 2.9.0", 3412 + "bitflags 2.9.1", 3480 3413 "errno", 3481 3414 "libc", 3482 3415 "linux-raw-sys", ··· 3646 3579 source = "registry+https://github.com/rust-lang/crates.io-index" 3647 3580 checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 3648 3581 dependencies = [ 3649 - "bitflags 2.9.0", 3582 + "bitflags 2.9.1", 3650 3583 "core-foundation", 3651 3584 "core-foundation-sys", 3652 3585 "libc", ··· 4061 3994 source = "registry+https://github.com/rust-lang/crates.io-index" 4062 3995 checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 4063 3996 dependencies = [ 4064 - "bitflags 2.9.0", 3997 + "bitflags 2.9.1", 4065 3998 "core-foundation", 4066 3999 "system-configuration-sys", 4067 4000 ] ··· 4295 4228 "async-trait", 4296 4229 "byteorder", 4297 4230 "bytes", 4298 - "fallible-iterator 0.2.0", 4231 + "fallible-iterator", 4299 4232 "futures-channel", 4300 4233 "futures-util", 4301 4234 "log", ··· 4417 4350 source = "registry+https://github.com/rust-lang/crates.io-index" 4418 4351 checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" 4419 4352 dependencies = [ 4420 - "bitflags 2.9.0", 4353 + "bitflags 2.9.1", 4421 4354 "bytes", 4422 4355 "futures-util", 4423 4356 "http", ··· 4858 4791 "atrium-oauth", 4859 4792 "atrium-xrpc-client", 4860 4793 "clap", 4794 + "dirs", 4861 4795 "esquema-codegen", 4862 4796 "hickory-resolver", 4863 4797 "miette", ··· 4878 4812 "atrium-identity", 4879 4813 "atrium-oauth", 4880 4814 "atrium-xrpc", 4815 + "dirs", 4881 4816 "esquema-codegen", 4882 4817 "hickory-resolver", 4883 4818 "http", 4884 4819 "jose-jwk", 4885 - "libsqlite3-sys", 4886 4820 "markdown-weaver", 4887 4821 "merde", 4888 4822 "miette", ··· 4912 4846 dependencies = [ 4913 4847 "atrium-api", 4914 4848 "compact_string", 4849 + "http", 4915 4850 "n0-future", 4851 + "url", 4916 4852 "weaver-common", 4917 4853 "weaver-workspace-hack", 4918 4854 ] ··· 4951 4887 "group", 4952 4888 "hashbrown 0.15.3", 4953 4889 "idna", 4954 - "libsqlite3-sys", 4955 4890 "log", 4956 4891 "memchr", 4957 4892 "miette", ··· 5081 5016 5082 5017 [[package]] 5083 5018 name = "windows" 5084 - version = "0.58.0" 5019 + version = "0.61.1" 5020 + source = "registry+https://github.com/rust-lang/crates.io-index" 5021 + checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" 5022 + dependencies = [ 5023 + "windows-collections", 5024 + "windows-core", 5025 + "windows-future", 5026 + "windows-link", 5027 + "windows-numerics", 5028 + ] 5029 + 5030 + [[package]] 5031 + name = "windows-collections" 5032 + version = "0.2.0" 5085 5033 source = "registry+https://github.com/rust-lang/crates.io-index" 5086 - checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" 5034 + checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" 5087 5035 dependencies = [ 5088 5036 "windows-core", 5089 - "windows-targets 0.52.6", 5090 5037 ] 5091 5038 5092 5039 [[package]] 5093 5040 name = "windows-core" 5094 - version = "0.58.0" 5041 + version = "0.61.1" 5095 5042 source = "registry+https://github.com/rust-lang/crates.io-index" 5096 - checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" 5043 + checksum = "46ec44dc15085cea82cf9c78f85a9114c463a369786585ad2882d1ff0b0acf40" 5097 5044 dependencies = [ 5098 5045 "windows-implement", 5099 5046 "windows-interface", 5100 - "windows-result 0.2.0", 5101 - "windows-strings 0.1.0", 5102 - "windows-targets 0.52.6", 5047 + "windows-link", 5048 + "windows-result", 5049 + "windows-strings 0.4.1", 5050 + ] 5051 + 5052 + [[package]] 5053 + name = "windows-future" 5054 + version = "0.2.1" 5055 + source = "registry+https://github.com/rust-lang/crates.io-index" 5056 + checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" 5057 + dependencies = [ 5058 + "windows-core", 5059 + "windows-link", 5060 + "windows-threading", 5103 5061 ] 5104 5062 5105 5063 [[package]] 5106 5064 name = "windows-implement" 5107 - version = "0.58.0" 5065 + version = "0.60.0" 5108 5066 source = "registry+https://github.com/rust-lang/crates.io-index" 5109 - checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" 5067 + checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" 5110 5068 dependencies = [ 5111 5069 "proc-macro2", 5112 5070 "quote", ··· 5115 5073 5116 5074 [[package]] 5117 5075 name = "windows-interface" 5118 - version = "0.58.0" 5076 + version = "0.59.1" 5119 5077 source = "registry+https://github.com/rust-lang/crates.io-index" 5120 - checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" 5078 + checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" 5121 5079 dependencies = [ 5122 5080 "proc-macro2", 5123 5081 "quote", ··· 5131 5089 checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" 5132 5090 5133 5091 [[package]] 5134 - name = "windows-registry" 5135 - version = "0.4.0" 5092 + name = "windows-numerics" 5093 + version = "0.2.0" 5136 5094 source = "registry+https://github.com/rust-lang/crates.io-index" 5137 - checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" 5095 + checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" 5138 5096 dependencies = [ 5139 - "windows-result 0.3.2", 5140 - "windows-strings 0.3.1", 5141 - "windows-targets 0.53.0", 5097 + "windows-core", 5098 + "windows-link", 5142 5099 ] 5143 5100 5144 5101 [[package]] 5145 - name = "windows-result" 5146 - version = "0.2.0" 5102 + name = "windows-registry" 5103 + version = "0.4.0" 5147 5104 source = "registry+https://github.com/rust-lang/crates.io-index" 5148 - checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 5105 + checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" 5149 5106 dependencies = [ 5150 - "windows-targets 0.52.6", 5107 + "windows-result", 5108 + "windows-strings 0.3.1", 5109 + "windows-targets 0.53.0", 5151 5110 ] 5152 5111 5153 5112 [[package]] 5154 5113 name = "windows-result" 5155 - version = "0.3.2" 5114 + version = "0.3.3" 5156 5115 source = "registry+https://github.com/rust-lang/crates.io-index" 5157 - checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" 5116 + checksum = "4b895b5356fc36103d0f64dd1e94dfa7ac5633f1c9dd6e80fe9ec4adef69e09d" 5158 5117 dependencies = [ 5159 5118 "windows-link", 5160 5119 ] 5161 5120 5162 5121 [[package]] 5163 5122 name = "windows-strings" 5164 - version = "0.1.0" 5123 + version = "0.3.1" 5165 5124 source = "registry+https://github.com/rust-lang/crates.io-index" 5166 - checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 5125 + checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" 5167 5126 dependencies = [ 5168 - "windows-result 0.2.0", 5169 - "windows-targets 0.52.6", 5127 + "windows-link", 5170 5128 ] 5171 5129 5172 5130 [[package]] 5173 5131 name = "windows-strings" 5174 - version = "0.3.1" 5132 + version = "0.4.1" 5175 5133 source = "registry+https://github.com/rust-lang/crates.io-index" 5176 - checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" 5134 + checksum = "2a7ab927b2637c19b3dbe0965e75d8f2d30bdd697a1516191cad2ec4df8fb28a" 5177 5135 dependencies = [ 5178 5136 "windows-link", 5179 5137 ] ··· 5250 5208 "windows_x86_64_gnu 0.53.0", 5251 5209 "windows_x86_64_gnullvm 0.53.0", 5252 5210 "windows_x86_64_msvc 0.53.0", 5211 + ] 5212 + 5213 + [[package]] 5214 + name = "windows-threading" 5215 + version = "0.1.0" 5216 + source = "registry+https://github.com/rust-lang/crates.io-index" 5217 + checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" 5218 + dependencies = [ 5219 + "windows-link", 5253 5220 ] 5254 5221 5255 5222 [[package]] ··· 5415 5382 source = "registry+https://github.com/rust-lang/crates.io-index" 5416 5383 checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 5417 5384 dependencies = [ 5418 - "bitflags 2.9.0", 5385 + "bitflags 2.9.1", 5419 5386 ] 5420 5387 5421 5388 [[package]] ··· 5440 5407 checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" 5441 5408 dependencies = [ 5442 5409 "arraydeque", 5443 - "hashlink 0.8.4", 5410 + "hashlink", 5444 5411 ] 5445 5412 5446 5413 [[package]]
+1 -1
Cargo.toml
··· 23 23 [workspace.dependencies] 24 24 25 25 serde = { version = "1.0", features = ["derive"] } 26 - merde = { version = "10.0.6", features = ["full"] } 26 + merde = { version = "10.0.6" } 27 27 28 28 minijinja = { version = "2.9.0", default-features = false } 29 29 minijinja-contrib = { version = "2.9.0", default-features = false }
+2 -1
crates/weaver-cli/Cargo.toml
··· 8 8 [dependencies] 9 9 clap = { version = "4.5", features = ["derive", "env", "cargo", "unicode"] } 10 10 n0-future = { workspace = true } 11 - weaver-common = { path = "../weaver-common" } 11 + weaver-common = { path = "../weaver-common", features = ["native"] } 12 12 weaver-workspace-hack = { version = "0.1", path = "../weaver-workspace-hack" } 13 13 miette = { workspace = true, features = ["fancy"] } 14 14 ··· 27 27 # temp for testing 28 28 tokio = { version = "1.45.0", features = ["full"] } 29 29 rouille = { version = "3.6.2", features = ["rustls"] } 30 + dirs = "6.0.0"
+114 -50
crates/weaver-cli/src/main.rs
··· 1 - use atrium_api::agent::Agent; 1 + use atrium_api::types::string::Did; 2 2 use atrium_oauth::AuthorizeOptions; 3 3 use atrium_oauth::CallbackParams; 4 4 use atrium_oauth::KnownScope; 5 5 use atrium_oauth::Scope; 6 + use miette::miette; 7 + use miette::{IntoDiagnostic, Result}; 6 8 use rouille::Server; 7 - use std::error; 9 + use std::path::Path; 10 + use std::path::PathBuf; 8 11 use tokio::sync::mpsc; 9 12 use weaver_common::agent::WeaverAgent; 10 13 14 + use clap::{Args, Parser, Subcommand}; 15 + 16 + #[derive(Parser)] 17 + #[command(version, about, long_about = None)] 18 + #[command(propagate_version = true)] 19 + struct Cli { 20 + #[command(subcommand)] 21 + command: Option<Commands>, 22 + } 23 + 24 + #[derive(Subcommand)] 25 + enum Commands { 26 + /// Authenticate with your atproto PDS, using your handle or the URL of the PDS. You can also set the HANDLE environment variable. 27 + Auth(AuthArgs), 28 + /// Test the native oauth client 29 + Run, 30 + } 31 + 32 + #[derive(Args)] 33 + struct AuthArgs { 34 + handle: Option<String>, 35 + } 36 + 11 37 #[tokio::main] 12 - async fn main() -> Result<(), Box<dyn error::Error>> { 13 - let (tx, mut rx) = mpsc::channel(5); 14 - let server = Server::new("0.0.0.0:4000", move |request| { 15 - create_callback_router(request, tx.clone()) 16 - }) 17 - .expect("Could not start server"); 18 - let (server_handle, server_stop) = server.stoppable(); 19 - let client = weaver_common::oauth::default_native_oauth_client()?; 20 - println!( 21 - "To authenticate with your PDS, visit:\r\n\t {}", 22 - client 23 - .authorize( 24 - std::env::var("HANDLE").unwrap_or(String::from("https://atproto.systems")), 25 - AuthorizeOptions { 26 - scopes: vec![ 27 - Scope::Known(KnownScope::Atproto), 28 - Scope::Known(KnownScope::TransitionGeneric) 29 - ], 30 - ..Default::default() 31 - } 32 - ) 33 - .await? 34 - ); 38 + async fn main() -> Result<()> { 39 + init_miette(); 40 + let args = Cli::parse(); 41 + let base_dir = weaver_common::filestore::config_dir(); 42 + tokio::fs::create_dir_all(&base_dir) 43 + .await 44 + .into_diagnostic()?; 45 + let client = weaver_common::oauth::test_native_oauth_client().into_diagnostic()?; 46 + let (session, server_handle) = if let Some(Commands::Auth(AuthArgs { handle })) = args.command { 47 + let handle = handle.unwrap_or(String::from("https://atproto.systems")); 48 + let (tx, mut rx) = mpsc::channel(5); 49 + let server = Server::new("0.0.0.0:4000", move |request| { 50 + create_callback_router(request, tx.clone()) 51 + }) 52 + .expect("Could not start server"); 53 + let (server_handle, server_stop) = server.stoppable(); 35 54 36 - let params = rx.recv().await.unwrap(); 37 - let (session, _) = client.callback(params).await?; 38 - server_stop 39 - .send(()) 40 - .expect("Failed to stop callback server"); 55 + println!( 56 + "To authenticate with your PDS, visit:\r\n\t {}", 57 + client 58 + .authorize( 59 + handle, 60 + AuthorizeOptions { 61 + scopes: vec![ 62 + Scope::Known(KnownScope::Atproto), 63 + Scope::Known(KnownScope::TransitionGeneric) 64 + ], 65 + ..Default::default() 66 + } 67 + ) 68 + .await 69 + .into_diagnostic()? 70 + ); 71 + 72 + let params = rx.recv().await.unwrap(); 73 + let (session, _) = client.callback(params).await.into_diagnostic()?; 74 + server_stop 75 + .send(()) 76 + .expect("Failed to stop callback server"); 77 + Ok::<_, weaver_common::Error>((session, Some(server_handle))) 78 + } else { 79 + let did = find_session_did(base_dir).await?; 80 + let session = client.restore(&did).await.into_diagnostic()?; 81 + Ok((session, None)) 82 + }?; 83 + 41 84 let agent = WeaverAgent::new(session); 42 85 let output = agent 43 86 .get_profile_pds(agent.did().await.unwrap().into()) 44 87 .await?; 45 88 println!("{output:?}"); 46 - 47 - // let agent = Agent::new(session); 48 - // let output = agent 49 - // .api 50 - // .app 51 - // .bsky 52 - // .feed 53 - // .get_timeline( 54 - // weaver_common::app::bsky::feed::get_timeline::ParametersData { 55 - // algorithm: None, 56 - // cursor: None, 57 - // limit: 3.try_into().ok(), 58 - // } 59 - // .into(), 60 - // ) 61 - // .await?; 62 - // for feed in &output.feed { 63 - // println!("{feed:?}"); 64 - // } 65 - server_handle.join().unwrap(); 89 + if let Some(server_handle) = server_handle { 90 + server_handle.join().unwrap(); 91 + } 66 92 Ok(()) 67 93 } 68 94 ··· 86 112 _ => rouille::Response::empty_404() 87 113 ) 88 114 } 115 + 116 + pub async fn find_session_did(path: impl AsRef<Path>) -> Result<Did> { 117 + let path = path.as_ref(); 118 + let mut dir = tokio::fs::read_dir(path).await.into_diagnostic()?; 119 + while let Some(entry) = dir.next_entry().await.into_diagnostic()? { 120 + let file_name = entry.file_name(); 121 + if let Some(file_name) = file_name.to_str() { 122 + if file_name.ends_with("_session.json") { 123 + let did_string = file_name 124 + .strip_suffix("_session.json") 125 + .expect("we JUST checked the suffix lol") 126 + .to_string(); 127 + let did = Did::new(did_string).expect("we should only be writing valid dids"); 128 + return Ok(did); 129 + } 130 + } 131 + } 132 + Err(miette!("couldn't find any existing sessions!")) 133 + } 134 + 135 + fn init_miette() { 136 + miette::set_hook(Box::new(|_| { 137 + Box::new( 138 + miette::MietteHandlerOpts::new() 139 + .terminal_links(true) 140 + //.rgb_colors(miette::RgbColors::) 141 + .with_cause_chain() 142 + .with_syntax_highlighting(miette::highlighters::SyntectHighlighter::default()) 143 + .color(true) 144 + .context_lines(5) 145 + .tab_width(2) 146 + .break_words(true) 147 + .build(), 148 + ) 149 + })) 150 + .expect("couldn't set the miette hook"); 151 + miette::set_panic_hook(); 152 + }
+4 -2
crates/weaver-common/Cargo.toml
··· 8 8 [features] 9 9 default = ["dev"] 10 10 dev = [] 11 + native = ["tokio"] 11 12 12 13 [dependencies] 13 14 n0-future = { workspace = true } 14 15 weaver-workspace-hack = { version = "0.1", path = "../weaver-workspace-hack" } 15 16 markdown-weaver = { workspace = true } 16 - libsqlite3-sys = { version = "0.30.1", features = ["bundled"] } 17 + #libsqlite3-sys = { version = "0.30.1", features = ["bundled"] } 17 18 18 19 http = "1.3.1" 19 20 ··· 53 54 #jose = { version = "0.0.2", features = ["crypto-rustcrypto"] } 54 55 jose-jwk = "0.1.2" 55 56 reqwest = "0.12.15" 56 - 57 + tokio = { version = "1.44", features = ["full"], optional = true } 57 58 58 59 tower-service = "0.3.3" 59 60 tower-layer = "0.3.3" 60 61 multibase = "0.9.1" 62 + dirs = "6.0.0" 61 63 62 64 63 65
+3
crates/weaver-common/src/error.rs
··· 75 75 #[error("HTTP client error: {0}")] 76 76 #[diagnostic_source] 77 77 HttpClient(Box<dyn std::error::Error + Send + Sync + 'static>), 78 + #[error("DNS TXT resolver error: {0}")] 79 + #[diagnostic_source] 80 + DnsTxtResolver(#[from] hickory_resolver::error::ResolveError), 78 81 } 79 82 80 83 /// Generic error type for XRPC errors.
+187
crates/weaver-common/src/filestore.rs
··· 1 + use crate::Error; 2 + use crate::error::WeaverErrorKind; 3 + use crate::error::{IoError, SerDeError}; 4 + use atrium_api::types::string::Did; 5 + use atrium_common::store::Store; 6 + use atrium_oauth::store::session::Session; 7 + use atrium_oauth::store::state::InternalStateData; 8 + use std::path::{Path, PathBuf}; 9 + 10 + pub struct SimpleJsonFileSessionStore<T = PathBuf> 11 + where 12 + T: AsRef<Path>, 13 + { 14 + path: T, 15 + } 16 + 17 + impl<T> SimpleJsonFileSessionStore<T> 18 + where 19 + T: AsRef<Path>, 20 + { 21 + pub fn new(path: T) -> Self { 22 + Self { path } 23 + } 24 + 25 + pub async fn get_session(&self, did: &Did) -> Result<Option<Session>, Error> { 26 + let path = self 27 + .path 28 + .as_ref() 29 + .join(format!("{}_session.json", did.as_str())); 30 + let file = tokio::fs::read_to_string(path) 31 + .await 32 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))])); 33 + let file = if let Err(e) = &file { 34 + println!("Failed to read session file: {e}"); 35 + return Ok(None); 36 + } else { 37 + file? 38 + }; 39 + 40 + let session = serde_json::from_str(&file) 41 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(SerDeError::from(e))]))?; 42 + Ok(Some(session)) 43 + } 44 + 45 + pub async fn set_session(&self, did: Did, session: Session) -> Result<(), Error> { 46 + let path = self 47 + .path 48 + .as_ref() 49 + .join(format!("{}_session.json", did.as_str())); 50 + let file = serde_json::to_string(&session) 51 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(SerDeError::from(e))]))?; 52 + 53 + tokio::fs::write(path, file) 54 + .await 55 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))]))?; 56 + 57 + Ok(()) 58 + } 59 + 60 + pub async fn get_state(&self, key: &str) -> Result<Option<InternalStateData>, Error> { 61 + let path = self.path.as_ref().join(format!("{}_state.json", key)); 62 + let file = tokio::fs::read_to_string(path) 63 + .await 64 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))])); 65 + let file = if let Err(e) = &file { 66 + println!("Failed to read state file: {e}"); 67 + return Ok(None); 68 + } else { 69 + file? 70 + }; 71 + let state = serde_json::from_str(&file) 72 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(SerDeError::from(e))]))?; 73 + Ok(Some(state)) 74 + } 75 + 76 + pub async fn set_state(&self, key: String, state: InternalStateData) -> Result<(), Error> { 77 + let path = self.path.as_ref().join(format!("{}_state.json", key)); 78 + 79 + let file = serde_json::to_string(&state) 80 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(SerDeError::from(e))]))?; 81 + 82 + tokio::fs::write(path, file) 83 + .await 84 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))]))?; 85 + 86 + Ok(()) 87 + } 88 + } 89 + 90 + impl Store<Did, Session> for SimpleJsonFileSessionStore<PathBuf> { 91 + type Error = crate::Error; 92 + 93 + async fn get(&self, key: &Did) -> Result<Option<Session>, Self::Error> { 94 + self.get_session(key).await 95 + } 96 + 97 + async fn set(&self, key: Did, value: Session) -> Result<(), Self::Error> { 98 + self.set_session(key, value).await 99 + } 100 + 101 + async fn del(&self, key: &Did) -> Result<(), Self::Error> { 102 + let path = self.path.join(format!("{}_session.json", key.as_str())); 103 + tokio::fs::remove_file(path) 104 + .await 105 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))])) 106 + } 107 + 108 + async fn clear(&self) -> Result<(), Self::Error> { 109 + let mut files = tokio::fs::read_dir(&self.path) 110 + .await 111 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))]))?; 112 + while let Some(entry) = files 113 + .next_entry() 114 + .await 115 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))]))? 116 + { 117 + let file_name = entry.file_name(); 118 + if let Some(file_name) = file_name.to_str() { 119 + if file_name.ends_with("_session.json") { 120 + tokio::fs::remove_file(entry.path()) 121 + .await 122 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))]))?; 123 + } 124 + } 125 + } 126 + Ok(()) 127 + } 128 + } 129 + 130 + impl Store<String, InternalStateData> for SimpleJsonFileSessionStore<PathBuf> { 131 + type Error = crate::Error; 132 + 133 + async fn get(&self, key: &String) -> Result<Option<InternalStateData>, Self::Error> { 134 + self.get_state(key.as_str()).await 135 + } 136 + 137 + async fn set(&self, key: String, value: InternalStateData) -> Result<(), Self::Error> { 138 + self.set_state(key, value).await 139 + } 140 + 141 + async fn del(&self, key: &String) -> Result<(), Self::Error> { 142 + let path = self.path.join(format!("{}_state.json", key.as_str())); 143 + tokio::fs::remove_file(path) 144 + .await 145 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))])) 146 + } 147 + 148 + async fn clear(&self) -> Result<(), Self::Error> { 149 + let mut files = tokio::fs::read_dir(&self.path) 150 + .await 151 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))]))?; 152 + while let Some(entry) = files 153 + .next_entry() 154 + .await 155 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))]))? 156 + { 157 + let file_name = &entry.file_name(); 158 + if let Some(file_name) = file_name.to_str() { 159 + if file_name.ends_with("_state.json") { 160 + tokio::fs::remove_file(entry.path()) 161 + .await 162 + .map_err(|e| Error::new(vec![WeaverErrorKind::from(IoError::from(e))]))?; 163 + } 164 + } 165 + } 166 + Ok(()) 167 + } 168 + } 169 + 170 + impl atrium_oauth::store::session::SessionStore for SimpleJsonFileSessionStore<PathBuf> {} 171 + 172 + impl atrium_oauth::store::state::StateStore for SimpleJsonFileSessionStore<PathBuf> {} 173 + 174 + impl Default for SimpleJsonFileSessionStore<PathBuf> { 175 + fn default() -> Self { 176 + let path = dirs::config_dir() 177 + .unwrap_or_else(|| PathBuf::from("./")) 178 + .join("weaver/sessions"); 179 + Self { path } 180 + } 181 + } 182 + 183 + pub fn config_dir() -> PathBuf { 184 + dirs::config_dir() 185 + .unwrap_or_else(|| PathBuf::from("./")) 186 + .join("weaver/sessions") 187 + }
+9
crates/weaver-common/src/lexicons/app/bsky/unspecced/get_config.rs
··· 6 6 pub struct OutputData { 7 7 #[serde(skip_serializing_if = "core::option::Option::is_none")] 8 8 pub check_email_confirmed: core::option::Option<bool>, 9 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 10 + pub live_now: core::option::Option<Vec<LiveNowConfig>>, 9 11 } 10 12 pub type Output = atrium_api::types::Object<OutputData>; 11 13 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] ··· 16 18 Ok(()) 17 19 } 18 20 } 21 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 22 + #[serde(rename_all = "camelCase")] 23 + pub struct LiveNowConfigData { 24 + pub did: atrium_api::types::string::Did, 25 + pub domains: Vec<String>, 26 + } 27 + pub type LiveNowConfig = atrium_api::types::Object<LiveNowConfigData>;
+36
crates/weaver-common/src/lexicons/record.rs
··· 65 65 LexiconsShWeaverActorProfile( 66 66 Box<crate::lexicons::sh::weaver::actor::profile::Record>, 67 67 ), 68 + #[serde(rename = "sh.weaver.edit.cursor")] 69 + LexiconsShWeaverEditCursor(Box<crate::lexicons::sh::weaver::edit::cursor::Record>), 70 + #[serde(rename = "sh.weaver.edit.diff")] 71 + LexiconsShWeaverEditDiff(Box<crate::lexicons::sh::weaver::edit::diff::Record>), 72 + #[serde(rename = "sh.weaver.edit.root")] 73 + LexiconsShWeaverEditRoot(Box<crate::lexicons::sh::weaver::edit::root::Record>), 68 74 #[serde(rename = "sh.weaver.notebook.authors")] 69 75 LexiconsShWeaverNotebookAuthors( 70 76 Box<crate::lexicons::sh::weaver::notebook::authors::Record>, ··· 302 308 record_data: crate::lexicons::sh::weaver::actor::profile::RecordData, 303 309 ) -> Self { 304 310 KnownRecord::LexiconsShWeaverActorProfile(Box::new(record_data.into())) 311 + } 312 + } 313 + impl From<crate::lexicons::sh::weaver::edit::cursor::Record> for KnownRecord { 314 + fn from(record: crate::lexicons::sh::weaver::edit::cursor::Record) -> Self { 315 + KnownRecord::LexiconsShWeaverEditCursor(Box::new(record)) 316 + } 317 + } 318 + impl From<crate::lexicons::sh::weaver::edit::cursor::RecordData> for KnownRecord { 319 + fn from(record_data: crate::lexicons::sh::weaver::edit::cursor::RecordData) -> Self { 320 + KnownRecord::LexiconsShWeaverEditCursor(Box::new(record_data.into())) 321 + } 322 + } 323 + impl From<crate::lexicons::sh::weaver::edit::diff::Record> for KnownRecord { 324 + fn from(record: crate::lexicons::sh::weaver::edit::diff::Record) -> Self { 325 + KnownRecord::LexiconsShWeaverEditDiff(Box::new(record)) 326 + } 327 + } 328 + impl From<crate::lexicons::sh::weaver::edit::diff::RecordData> for KnownRecord { 329 + fn from(record_data: crate::lexicons::sh::weaver::edit::diff::RecordData) -> Self { 330 + KnownRecord::LexiconsShWeaverEditDiff(Box::new(record_data.into())) 331 + } 332 + } 333 + impl From<crate::lexicons::sh::weaver::edit::root::Record> for KnownRecord { 334 + fn from(record: crate::lexicons::sh::weaver::edit::root::Record) -> Self { 335 + KnownRecord::LexiconsShWeaverEditRoot(Box::new(record)) 336 + } 337 + } 338 + impl From<crate::lexicons::sh::weaver::edit::root::RecordData> for KnownRecord { 339 + fn from(record_data: crate::lexicons::sh::weaver::edit::root::RecordData) -> Self { 340 + KnownRecord::LexiconsShWeaverEditRoot(Box::new(record_data.into())) 305 341 } 306 342 } 307 343 impl From<crate::lexicons::sh::weaver::notebook::authors::Record> for KnownRecord {
+1
crates/weaver-common/src/lexicons/sh/weaver.rs
··· 1 1 // @generated - This file is generated by esquema-codegen (forked from atrium-codegen). DO NOT EDIT. 2 2 //!Definitions for the `sh.weaver` namespace. 3 3 pub mod actor; 4 + pub mod edit; 4 5 pub mod embed; 5 6 pub mod notebook;
+24
crates/weaver-common/src/lexicons/sh/weaver/edit.rs
··· 1 + // @generated - This file is generated by esquema-codegen (forked from atrium-codegen). DO NOT EDIT. 2 + //!Definitions for the `sh.weaver.edit` namespace. 3 + pub mod cursor; 4 + pub mod defs; 5 + pub mod diff; 6 + pub mod root; 7 + #[derive(Debug)] 8 + pub struct Cursor; 9 + impl atrium_api::types::Collection for Cursor { 10 + const NSID: &'static str = "sh.weaver.edit.cursor"; 11 + type Record = cursor::Record; 12 + } 13 + #[derive(Debug)] 14 + pub struct Diff; 15 + impl atrium_api::types::Collection for Diff { 16 + const NSID: &'static str = "sh.weaver.edit.diff"; 17 + type Record = diff::Record; 18 + } 19 + #[derive(Debug)] 20 + pub struct Root; 21 + impl atrium_api::types::Collection for Root { 22 + const NSID: &'static str = "sh.weaver.edit.root"; 23 + type Record = root::Record; 24 + }
+61
crates/weaver-common/src/lexicons/sh/weaver/edit/cursor.rs
··· 1 + // @generated - This file is generated by esquema-codegen (forked from atrium-codegen). DO NOT EDIT. 2 + //!Definitions for the `sh.weaver.edit.cursor` namespace. 3 + use atrium_api::types::TryFromUnknown; 4 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 5 + #[serde(rename_all = "camelCase")] 6 + pub struct RecordData { 7 + pub container: ContainerId, 8 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 9 + pub id: core::option::Option<Id>, 10 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 11 + pub side: core::option::Option<CursorSide>, 12 + } 13 + pub type Record = atrium_api::types::Object<RecordData>; 14 + impl From<atrium_api::types::Unknown> for RecordData { 15 + fn from(value: atrium_api::types::Unknown) -> Self { 16 + Self::try_from_unknown(value).unwrap() 17 + } 18 + } 19 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 20 + #[serde(rename_all = "camelCase")] 21 + pub struct ContainerIdData { 22 + pub value: atrium_api::types::Union<ContainerIdValueRefs>, 23 + } 24 + pub type ContainerId = atrium_api::types::Object<ContainerIdData>; 25 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 26 + #[serde(rename_all = "camelCase")] 27 + pub struct CursorSideData { 28 + ///The side of an item the cursor is on (left = -1, right = 1, middle = 0) 29 + pub value: i64, 30 + } 31 + pub type CursorSide = atrium_api::types::Object<CursorSideData>; 32 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 33 + #[serde(rename_all = "camelCase")] 34 + pub struct IdData { 35 + pub counter: i64, 36 + pub peer: i64, 37 + } 38 + pub type Id = atrium_api::types::Object<IdData>; 39 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 40 + #[serde(rename_all = "camelCase")] 41 + pub struct NormalContainerIdData { 42 + pub container_type: String, 43 + pub counter: i64, 44 + pub peer: i64, 45 + } 46 + pub type NormalContainerId = atrium_api::types::Object<NormalContainerIdData>; 47 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 48 + #[serde(rename_all = "camelCase")] 49 + pub struct RootContainerIdData { 50 + pub container_type: String, 51 + pub name: String, 52 + } 53 + pub type RootContainerId = atrium_api::types::Object<RootContainerIdData>; 54 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 55 + #[serde(tag = "$type")] 56 + pub enum ContainerIdValueRefs { 57 + #[serde(rename = "sh.weaver.edit.cursor#normalContainerId")] 58 + NormalContainerId(Box<NormalContainerId>), 59 + #[serde(rename = "sh.weaver.edit.cursor#rootContainerId")] 60 + RootContainerId(Box<RootContainerId>), 61 + }
+28
crates/weaver-common/src/lexicons/sh/weaver/edit/defs.rs
··· 1 + // @generated - This file is generated by esquema-codegen (forked from atrium-codegen). DO NOT EDIT. 2 + //!Definitions for the `sh.weaver.edit.defs` namespace. 3 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 4 + #[serde(rename_all = "camelCase")] 5 + pub struct DocRefData { 6 + pub value: atrium_api::types::Union<DocRefValueRefs>, 7 + } 8 + pub type DocRef = atrium_api::types::Object<DocRefData>; 9 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 + #[serde(rename_all = "camelCase")] 11 + pub struct EntryRefData { 12 + pub notebook: crate::com::atproto::repo::strong_ref::Main, 13 + } 14 + pub type EntryRef = atrium_api::types::Object<EntryRefData>; 15 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 16 + #[serde(rename_all = "camelCase")] 17 + pub struct NotebookRefData { 18 + pub notebook: crate::com::atproto::repo::strong_ref::Main, 19 + } 20 + pub type NotebookRef = atrium_api::types::Object<NotebookRefData>; 21 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 22 + #[serde(tag = "$type")] 23 + pub enum DocRefValueRefs { 24 + #[serde(rename = "sh.weaver.edit.defs#notebookRef")] 25 + NotebookRef(Box<NotebookRef>), 26 + #[serde(rename = "sh.weaver.edit.defs#entryRef")] 27 + EntryRef(Box<EntryRef>), 28 + }
+16
crates/weaver-common/src/lexicons/sh/weaver/edit/diff.rs
··· 1 + // @generated - This file is generated by esquema-codegen (forked from atrium-codegen). DO NOT EDIT. 2 + //!Definitions for the `sh.weaver.edit.diff` namespace. 3 + use atrium_api::types::TryFromUnknown; 4 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 5 + #[serde(rename_all = "camelCase")] 6 + pub struct RecordData { 7 + pub doc: crate::sh::weaver::edit::defs::DocRef, 8 + pub root: crate::com::atproto::repo::strong_ref::Main, 9 + pub snapshot: atrium_api::types::BlobRef, 10 + } 11 + pub type Record = atrium_api::types::Object<RecordData>; 12 + impl From<atrium_api::types::Unknown> for RecordData { 13 + fn from(value: atrium_api::types::Unknown) -> Self { 14 + Self::try_from_unknown(value).unwrap() 15 + } 16 + }
+17
crates/weaver-common/src/lexicons/sh/weaver/edit/root.rs
··· 1 + // @generated - This file is generated by esquema-codegen (forked from atrium-codegen). DO NOT EDIT. 2 + //!Definitions for the `sh.weaver.edit.root` namespace. 3 + use atrium_api::types::TryFromUnknown; 4 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 5 + #[serde(rename_all = "camelCase")] 6 + pub struct RecordData { 7 + pub cid: atrium_api::types::string::Cid, 8 + pub doc: crate::sh::weaver::edit::defs::DocRef, 9 + pub snapshot: atrium_api::types::BlobRef, 10 + pub uri: String, 11 + } 12 + pub type Record = atrium_api::types::Object<RecordData>; 13 + impl From<atrium_api::types::Unknown> for RecordData { 14 + fn from(value: atrium_api::types::Unknown) -> Self { 15 + Self::try_from_unknown(value).unwrap() 16 + } 17 + }
+5 -2
crates/weaver-common/src/lexicons/sh/weaver/notebook/book.rs
··· 5 5 #[serde(rename_all = "camelCase")] 6 6 pub struct RecordData { 7 7 pub authors: crate::sh::weaver::notebook::defs::AuthorListView, 8 - pub cid: atrium_api::types::string::Cid, 8 + ///Client-declared timestamp when this was originally created. 9 9 #[serde(skip_serializing_if = "core::option::Option::is_none")] 10 10 pub created_at: core::option::Option<atrium_api::types::string::Datetime>, 11 11 pub entry_list: Vec<crate::sh::weaver::notebook::defs::BookEntryView>, 12 - pub uri: String, 12 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 13 + pub tags: core::option::Option<crate::sh::weaver::notebook::defs::Tags>, 14 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 15 + pub title: core::option::Option<crate::sh::weaver::notebook::defs::Title>, 13 16 } 14 17 pub type Record = atrium_api::types::Object<RecordData>; 15 18 impl From<atrium_api::types::Unknown> for RecordData {
+23
crates/weaver-common/src/lexicons/sh/weaver/notebook/defs.rs
··· 40 40 pub record: atrium_api::types::Unknown, 41 41 #[serde(skip_serializing_if = "core::option::Option::is_none")] 42 42 pub rendered_view: core::option::Option<RenderedView>, 43 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 44 + pub tags: core::option::Option<Tags>, 45 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 46 + pub title: core::option::Option<Title>, 43 47 pub uri: String, 44 48 } 45 49 pub type EntryView = atrium_api::types::Object<EntryViewData>; 50 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 51 + #[serde(rename_all = "camelCase")] 52 + pub struct NotebookViewData { 53 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 54 + pub authors: core::option::Option<AuthorListView>, 55 + pub cid: atrium_api::types::string::Cid, 56 + pub indexed_at: atrium_api::types::string::Datetime, 57 + pub record: atrium_api::types::Unknown, 58 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 59 + pub tags: core::option::Option<Tags>, 60 + #[serde(skip_serializing_if = "core::option::Option::is_none")] 61 + pub title: core::option::Option<Title>, 62 + pub uri: String, 63 + } 64 + pub type NotebookView = atrium_api::types::Object<NotebookViewData>; 46 65 ///View of a rendered and cached notebook entry 47 66 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 48 67 #[serde(rename_all = "camelCase")] ··· 52 71 pub html: atrium_api::types::BlobRef, 53 72 } 54 73 pub type RenderedView = atrium_api::types::Object<RenderedViewData>; 74 + ///An array of tags associated with the notebook entry. Tags can help categorize and organize entries. 75 + pub type Tags = Vec<String>; 76 + ///The title of the notebook entry. 77 + pub type Title = String;
+4 -9
crates/weaver-common/src/lexicons/sh/weaver/notebook/entry.rs
··· 6 6 pub struct RecordData { 7 7 ///The content of the notebook entry. This should be some flavor of Markdown. 8 8 pub content: String, 9 - pub created_at: CreatedAt, 9 + ///Client-declared timestamp when this was originally created. 10 + pub created_at: atrium_api::types::string::Datetime, 10 11 ///The set of images, if any, embedded in the notebook entry. 11 12 #[serde(skip_serializing_if = "core::option::Option::is_none")] 12 13 pub images: core::option::Option<crate::sh::weaver::embed::images::Main>, 13 14 #[serde(skip_serializing_if = "core::option::Option::is_none")] 14 - pub tags: core::option::Option<Tags>, 15 - pub title: Title, 15 + pub tags: core::option::Option<crate::sh::weaver::notebook::defs::Tags>, 16 + pub title: crate::sh::weaver::notebook::defs::Title, 16 17 } 17 18 pub type Record = atrium_api::types::Object<RecordData>; 18 19 impl From<atrium_api::types::Unknown> for RecordData { ··· 20 21 Self::try_from_unknown(value).unwrap() 21 22 } 22 23 } 23 - ///The date and time when the notebook entry was created. This is used for sorting and displaying the entry's creation date. 24 - pub type CreatedAt = String; 25 - ///An array of tags associated with the notebook entry. Tags can help categorize and organize entries. 26 - pub type Tags = Vec<String>; 27 - ///The title of the notebook entry. 28 - pub type Title = String;
+3
crates/weaver-common/src/lib.rs
··· 1 1 pub mod agent; 2 2 pub mod config; 3 3 pub mod error; 4 + /// This filestore is very much not production ready 5 + #[cfg(all(feature = "native", feature = "dev"))] 6 + pub mod filestore; 4 7 pub mod lexicons; 5 8 pub mod oauth; 6 9 pub mod resolver;
+83 -2
crates/weaver-common/src/oauth.rs
··· 28 28 pub http_client: Arc<WeaverHttpClient>, 29 29 } 30 30 31 + pub type NativeBasicOAuthSession = OAuthSession< 32 + DefaultHttpClient, 33 + CommonDidResolver<WeaverHttpClient>, 34 + AtprotoHandleResolver<HickoryDnsTxtResolver, WeaverHttpClient>, 35 + MemoryStore<Did, Session>, 36 + >; 37 + 38 + pub struct NativeWeaverOAuthClient<STATE, SESS> 39 + where 40 + STATE: StateStore + Send + Sync + 'static, 41 + SESS: SessionStore + Send + Sync + 'static, 42 + STATE::Error: std::error::Error + Send + Sync + 'static, 43 + SESS::Error: std::error::Error + Send + Sync + 'static, 44 + { 45 + oauth: WeaverOAuthClient<STATE, SESS>, 46 + pub http_client: Arc<WeaverHttpClient>, 47 + } 31 48 impl NativeOAuthClient { 32 49 pub async fn authorize( 33 50 &self, ··· 45 62 } 46 63 } 47 64 48 - pub type NativeBasicOAuthSession = OAuthSession< 65 + #[cfg(all(feature = "native", feature = "dev"))] 66 + impl 67 + NativeWeaverOAuthClient< 68 + crate::filestore::SimpleJsonFileSessionStore<std::path::PathBuf>, 69 + crate::filestore::SimpleJsonFileSessionStore<std::path::PathBuf>, 70 + > 71 + { 72 + pub async fn authorize( 73 + &self, 74 + input: impl AsRef<str>, 75 + options: AuthorizeOptions, 76 + ) -> Result<String, atrium_oauth::Error> { 77 + self.oauth.authorize(input, options).await 78 + } 79 + 80 + pub async fn callback( 81 + &self, 82 + params: CallbackParams, 83 + ) -> Result<(WeaverOAuthSession, Option<String>), atrium_oauth::Error> { 84 + self.oauth.callback(params).await 85 + } 86 + 87 + pub async fn restore(&self, did: &Did) -> Result<WeaverOAuthSession, atrium_oauth::Error> { 88 + self.oauth.restore(did).await 89 + } 90 + } 91 + 92 + #[cfg(all(feature = "native", feature = "dev"))] 93 + pub type WeaverOAuthSession = OAuthSession< 49 94 DefaultHttpClient, 50 95 CommonDidResolver<WeaverHttpClient>, 51 96 AtprotoHandleResolver<HickoryDnsTxtResolver, WeaverHttpClient>, 52 - MemoryStore<Did, Session>, 97 + crate::filestore::SimpleJsonFileSessionStore<std::path::PathBuf>, 53 98 >; 54 99 55 100 pub type NativeBasicOAuthClient = atrium_oauth::OAuthClient< ··· 135 180 session_store: MemorySessionStore::default(), 136 181 }; 137 182 let client = OAuthClient::new(config)?; 183 + Ok(client) 184 + } 185 + 186 + #[cfg(all(feature = "native", feature = "dev"))] 187 + pub fn test_native_oauth_client() -> Result< 188 + NativeWeaverOAuthClient< 189 + crate::filestore::SimpleJsonFileSessionStore<std::path::PathBuf>, 190 + crate::filestore::SimpleJsonFileSessionStore<std::path::PathBuf>, 191 + >, 192 + atrium_oauth::Error, 193 + > { 194 + use crate::filestore::SimpleJsonFileSessionStore; 195 + 196 + let http_client = Arc::new(WeaverHttpClient::default()); 197 + let config = OAuthClientConfig { 198 + client_metadata: default_native_client_metadata(), 199 + keys: None, 200 + resolver: OAuthResolverConfig { 201 + did_resolver: CommonDidResolver::new(CommonDidResolverConfig { 202 + plc_directory_url: DEFAULT_PLC_DIRECTORY_URL.to_string(), 203 + http_client: Arc::clone(&http_client), 204 + }), 205 + handle_resolver: AtprotoHandleResolver::new(AtprotoHandleResolverConfig { 206 + dns_txt_resolver: HickoryDnsTxtResolver::default(), 207 + http_client: Arc::clone(&http_client), 208 + }), 209 + authorization_server_metadata: Default::default(), 210 + protected_resource_metadata: Default::default(), 211 + }, 212 + state_store: SimpleJsonFileSessionStore::default(), 213 + session_store: SimpleJsonFileSessionStore::default(), 214 + }; 215 + let client = NativeWeaverOAuthClient { 216 + oauth: OAuthClient::new(config)?, 217 + http_client: Arc::clone(&http_client), 218 + }; 138 219 Ok(client) 139 220 } 140 221
+3 -2
crates/weaver-common/src/resolver.rs
··· 18 18 async fn resolve( 19 19 &self, 20 20 query: &str, 21 - ) -> core::result::Result<Vec<String>, Box<dyn std::error::Error + Send + Sync + 'static>> { 21 + ) -> core::result::Result<Vec<String>, Box<dyn std::error::Error + Send + Sync>> { 22 22 Ok(self 23 23 .resolver 24 24 .txt_lookup(query) 25 - .await? 25 + .await 26 + .map_err(crate::error::NetworkError::from)? 26 27 .iter() 27 28 .map(|txt| txt.to_string()) 28 29 .collect())
+2
crates/weaver-renderer/Cargo.toml
··· 13 13 14 14 weaver-workspace-hack = { version = "0.1", path = "../weaver-workspace-hack" } 15 15 compact_string = "0.1.0" 16 + http = "1.3.1" 17 + url = "2.5.4"
+1 -1
crates/weaver-renderer/src/lib.rs
··· 1 1 //! Weaver renderer 2 2 //! 3 - //! This crate works with the weaver-markdown crate to render and optionally upload markdown notebooks to your ATProto PDS. 3 + //! This crate works with the weaver-markdown crate to render and optionally upload markdown notebooks to your Atproto PDS. 4 4 //! 5 5 6 6 pub mod types;
+30 -8
crates/weaver-renderer/src/types.rs
··· 1 1 use atrium_api::types::string::{Cid, Did}; 2 2 use compact_string::CompactString; 3 + use http::Uri; 4 + 5 + pub struct Link { 6 + pub uri: Uri, 7 + pub blob: BlobLink, 8 + } 3 9 4 10 pub type MimeType = CompactString; 5 11 ··· 24 30 25 31 impl std::fmt::Display for BlobLink { 26 32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 27 - write!( 28 - f, 29 - "{}{}/{}@{}", 30 - self.url_prefix(), 31 - self.did().as_str(), 32 - self.cid().as_ref(), 33 - self.mime_type().rsplit('/').next().unwrap() 34 - ) 33 + match self { 34 + BlobLink::PDS { 35 + pds_host, 36 + did, 37 + cid, 38 + mime_type: _, 39 + } => { 40 + write!( 41 + f, 42 + "{}/xrpc/com.atproto.sync.getBlob?did={}&cid={}", 43 + pds_host, 44 + did.as_str(), 45 + cid.as_ref() 46 + ) 47 + } 48 + _ => write!( 49 + f, 50 + "{}{}/{}@{}", 51 + self.url_prefix(), 52 + self.did().as_str(), 53 + self.cid().as_ref(), 54 + self.mime_type().rsplit('/').next().unwrap() 55 + ), 56 + } 35 57 } 36 58 } 37 59
+2 -3
crates/weaver-workspace-hack/Cargo.toml
··· 33 33 group = { version = "0.13", default-features = false, features = ["alloc"] } 34 34 hashbrown = { version = "0.15", features = ["serde"] } 35 35 idna = { version = "1" } 36 - libsqlite3-sys = { version = "0.30", features = ["bundled"] } 37 36 log = { version = "0.4", default-features = false, features = ["std"] } 38 37 memchr = { version = "2", features = ["use_std"] } 39 38 miette = { version = "7", features = ["fancy", "syntect-highlighter"] } ··· 43 42 p384 = { version = "0.13", default-features = false, features = ["ecdsa"] } 44 43 percent-encoding = { version = "2" } 45 44 pkcs8 = { version = "0.10", default-features = false, features = ["pem"] } 46 - proc-macro2 = { version = "1", features = ["span-locations"] } 45 + proc-macro2 = { version = "1" } 47 46 quote = { version = "1" } 48 47 rand_core = { version = "0.6", default-features = false, features = ["std"] } 49 48 reqwest = { version = "0.12", features = ["gzip", "json", "rustls-tls"] } ··· 69 68 diesel_derives = { version = "2", features = ["32-column-tables", "chrono", "postgres", "sqlite", "with-deprecated"] } 70 69 either = { version = "1", features = ["use_std"] } 71 70 hashbrown = { version = "0.15", features = ["serde"] } 72 - proc-macro2 = { version = "1", features = ["span-locations"] } 71 + proc-macro2 = { version = "1" } 73 72 quote = { version = "1" } 74 73 serde = { version = "1", features = ["alloc", "derive"] } 75 74 syn = { version = "2", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] }
+11 -3
lexicon-codegen.sh
··· 2 2 3 3 4 4 #cargo install esquema-cli --locked --git https://github.com/fatfingers23/esquema.git 5 + 5 6 rm -rf ./target/lexicons 6 7 mkdir -p ./target/lexicons 8 + cd target 9 + git clone -n --depth=1 --filter=tree:0 \ 10 + https://github.com/bluesky-social/atproto.git 11 + cd atproto 12 + git sparse-checkout set --no-cone /lexicons 13 + git checkout 14 + cd .. 7 15 8 - cp -r ./lexicons ./target/lexicons 9 - cp -r ./atproto/lexicons ./target/lexicons 16 + cp -r ../lexicons ./ 17 + cp -r ./atproto/lexicons ./ 10 18 11 19 12 - ~/.cargo/bin/esquema-cli generate local --lexdir ./target/lexicons/ --outdir ./crates/weaver-common/src/ --module lexicons 20 + ~/.cargo/bin/esquema-cli generate local --lexdir ./lexicons/ --outdir ../crates/weaver-common/src/ --module lexicons
+81
lexicons/sh/weaver/edit/cursor.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "sh.weaver.edit.cursor", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "An edit record for a notebook.", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["container", "die"], 12 + "properties": { 13 + "id": { 14 + "type": "ref", 15 + "ref": "#id" 16 + }, 17 + "container": { 18 + "type": "ref", 19 + "ref": "#containerId" 20 + }, 21 + "side": { 22 + "type": "ref", 23 + "ref": "#cursorSide" 24 + } 25 + } 26 + } 27 + }, 28 + "id": { 29 + "type": "object", 30 + "required": ["peer", "counter"], 31 + "properties": { 32 + "peer": { "type": "integer" }, 33 + "counter": { "type": "integer" } 34 + } 35 + }, 36 + "cursorSide": { 37 + "type": "object", 38 + "required": ["value"], 39 + "properties": { 40 + "value": { 41 + "type": "integer", 42 + "description": "The side of an item the cursor is on (left = -1, right = 1, middle = 0)", 43 + "enum": [-1, 0, 1] 44 + } 45 + } 46 + }, 47 + "containerId": { 48 + "type": "object", 49 + "required": ["value"], 50 + "properties": { 51 + "value": { 52 + "type": "union", 53 + "refs": ["#normalContainerId", "#rootContainerId"] 54 + } 55 + } 56 + }, 57 + "normalContainerId": { 58 + "type": "object", 59 + "required": ["peer", "counter", "container_type"], 60 + "properties": { 61 + "peer": { "type": "integer" }, 62 + "counter": { "type": "integer" }, 63 + "container_type": { 64 + "type": "string", 65 + "enum": ["Map", "List", "Text", "Tree", "MovableList", "Counter"] 66 + } 67 + } 68 + }, 69 + "rootContainerId": { 70 + "type": "object", 71 + "required": ["name", "container_type"], 72 + "properties": { 73 + "name": { "type": "string" }, 74 + "container_type": { 75 + "type": "string", 76 + "enum": ["Map", "List", "Text", "Tree", "MovableList", "Counter"] 77 + } 78 + } 79 + } 80 + } 81 + }
+36
lexicons/sh/weaver/edit/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "sh.weaver.edit.defs", 4 + "defs": { 5 + "docRef": { 6 + "type": "object", 7 + "required": ["value"], 8 + "properties": { 9 + "value": { 10 + "type": "union", 11 + "refs": ["#notebookRef", "#entryRef"] 12 + } 13 + } 14 + }, 15 + "notebookRef": { 16 + "type": "object", 17 + "required": ["notebook"], 18 + "properties": { 19 + "notebook": { 20 + "type": "ref", 21 + "ref": "com.atproto.repo.strongRef" 22 + } 23 + } 24 + }, 25 + "entryRef": { 26 + "type": "object", 27 + "required": ["notebook"], 28 + "properties": { 29 + "notebook": { 30 + "type": "ref", 31 + "ref": "com.atproto.repo.strongRef" 32 + } 33 + } 34 + } 35 + } 36 + }
+30
lexicons/sh/weaver/edit/diff.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "sh.weaver.edit.diff", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "An edit record for a notebook.", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["snapshot", "root", "doc"], 12 + "properties": { 13 + "snapshot": { 14 + "type": "blob", 15 + "accept": ["*/*"], 16 + "maxSize": 3000000 17 + }, 18 + "root": { 19 + "type": "ref", 20 + "ref": "com.atproto.repo.strongRef" 21 + }, 22 + "doc": { 23 + "type": "ref", 24 + "ref": "sh.weaver.edit.defs#docRef" 25 + } 26 + } 27 + } 28 + } 29 + } 30 + }
+28
lexicons/sh/weaver/edit/root.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "sh.weaver.edit.root", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "The starting point for edit history on a notebook.", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["cid", "uri", "doc", "snapshot"], 12 + "properties": { 13 + "uri": { "type": "string", "format": "at-uri" }, 14 + "cid": { "type": "string", "format": "cid" }, 15 + "snapshot": { 16 + "type": "blob", 17 + "accept": ["*/*"], 18 + "maxSize": 30000000 19 + }, 20 + "doc": { 21 + "type": "ref", 22 + "ref": "sh.weaver.edit.defs#docRef" 23 + } 24 + } 25 + } 26 + } 27 + } 28 + }
+8 -4
lexicons/sh/weaver/notebook/book.json
··· 8 8 "key": "tid", 9 9 "record": { 10 10 "type": "object", 11 - "required": ["cid", "uri", "authors", "entryList"], 11 + "required": ["authors", "entryList"], 12 12 "properties": { 13 - "uri": { "type": "string", "format": "at-uri" }, 14 - "cid": { "type": "string", "format": "cid" }, 13 + "title": { "type": "ref", "ref": "sh.weaver.notebook.defs#title" }, 14 + "tags": { "type": "ref", "ref": "sh.weaver.notebook.defs#tags" }, 15 15 "authors": { 16 16 "type": "ref", 17 17 "ref": "sh.weaver.notebook.defs#authorListView" ··· 23 23 "ref": "sh.weaver.notebook.defs#bookEntryView" 24 24 } 25 25 }, 26 - "createdAt": { "type": "string", "format": "datetime" } 26 + "createdAt": { 27 + "type": "string", 28 + "format": "datetime", 29 + "description": "Client-declared timestamp when this was originally created." 30 + } 27 31 } 28 32 } 29 33 }
+33
lexicons/sh/weaver/notebook/defs.json
··· 2 2 "lexicon": 1, 3 3 "id": "sh.weaver.notebook.defs", 4 4 "defs": { 5 + "notebookView": { 6 + "type": "object", 7 + "required": ["uri", "cid", "author", "record", "indexedAt"], 8 + 9 + "properties": { 10 + "title": { "type": "ref", "ref": "#title" }, 11 + "tags": { "type": "ref", "ref": "#tags" }, 12 + "uri": { "type": "string", "format": "at-uri" }, 13 + "cid": { "type": "string", "format": "cid" }, 14 + "authors": { 15 + "type": "ref", 16 + "ref": "#authorListView" 17 + }, 18 + "record": { "type": "unknown" }, 19 + "indexedAt": { "type": "string", "format": "datetime" } 20 + } 21 + }, 5 22 "entryView": { 6 23 "type": "object", 7 24 "required": ["uri", "cid", "author", "record", "indexedAt"], 8 25 9 26 "properties": { 27 + "title": { "type": "ref", "ref": "#title" }, 28 + "tags": { "type": "ref", "ref": "#tags" }, 10 29 "uri": { "type": "string", "format": "at-uri" }, 11 30 "cid": { "type": "string", "format": "cid" }, 12 31 "authors": { ··· 79 98 "ref": "#entryView" 80 99 } 81 100 } 101 + }, 102 + "title": { 103 + "type": "string", 104 + "maxLength": 420, 105 + "description": "The title of the notebook entry." 106 + }, 107 + "tags": { 108 + "type": "array", 109 + "items": { 110 + "type": "string", 111 + "maxLength": 64 112 + }, 113 + "maxLength": 10, 114 + "description": "An array of tags associated with the notebook entry. Tags can help categorize and organize entries." 82 115 } 83 116 } 84 117 }
+5 -24
lexicons/sh/weaver/notebook/entry.json
··· 10 10 "type": "object", 11 11 "required": ["content", "title", "createdAt"], 12 12 "properties": { 13 - "title": { "type": "ref", "ref": "#title" }, 14 - "tags": { "type": "ref", "ref": "#tags" }, 13 + "title": { "type": "ref", "ref": "sh.weaver.notebook.defs#title" }, 14 + "tags": { "type": "ref", "ref": "sh.weaver.notebook.defs#tags" }, 15 15 16 16 "content": { 17 17 "type": "string", ··· 20 20 }, 21 21 22 22 "createdAt": { 23 - "type": "ref", 24 - "ref": "#createdAt" 23 + "type": "string", 24 + "format": "datetime", 25 + "description": "Client-declared timestamp when this was originally created." 25 26 }, 26 27 "images": { 27 28 "type": "ref", ··· 30 31 } 31 32 } 32 33 } 33 - }, 34 - 35 - "createdAt": { 36 - "type": "string", 37 - "format": "datetime", 38 - "description": "The date and time when the notebook entry was created. This is used for sorting and displaying the entry's creation date." 39 - }, 40 - "title": { 41 - "type": "string", 42 - "maxLength": 420, 43 - "description": "The title of the notebook entry." 44 - }, 45 - "tags": { 46 - "type": "array", 47 - "items": { 48 - "type": "string", 49 - "maxLength": 64 50 - }, 51 - "maxLength": 10, 52 - "description": "An array of tags associated with the notebook entry. Tags can help categorize and organize entries." 53 34 } 54 35 } 55 36 }
+8
test.html
··· 3 3 <head> 4 4 <meta charset="utf-8"> 5 5 </head> 6 + <script> 7 + console.log( window.location.href ); // whatever your current location href is 8 + window.history.replaceState( {} , 'foo', './LICENSE' ); 9 + console.log( window.location.href ); // oh, hey, it replaced the path with /foo 10 + 11 + 12 + </script> 6 13 <body> 7 14 <h1>Main Title &amp; &quot;Special Chars&quot;</h1> 8 15 <p>This is a paragraph with <em>emphasis</em>, <strong>strong emphasis</strong>, <del>strikethrough</del>, and <code>inline code</code>. ··· 15 22 </blockquote> 16 23 </blockquote> 17 24 <hr /> 25 + 18 26 <h2>Lists and Links</h2> 19 27 <ul> 20 28 <li><p>Unordered item 1</p>