learn and share notes on atproto (wip) 🦉 malfestio.stormlightlabs.org/
readability solid axum atproto srs
5
fork

Configure Feed

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

feat:iImplement user authentication and deck management APIs with ui

+1727 -45
+1
.gitignore
··· 19 19 # and can be added to the global gitignore or merged into this file. For a more nuclear 20 20 # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 21 #.idea/ 22 + .env
+1182 -9
Cargo.lock
··· 120 120 ] 121 121 122 122 [[package]] 123 + name = "base64" 124 + version = "0.22.1" 125 + source = "registry+https://github.com/rust-lang/crates.io-index" 126 + checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 127 + 128 + [[package]] 123 129 name = "bitflags" 124 130 version = "2.10.0" 125 131 source = "registry+https://github.com/rust-lang/crates.io-index" 126 132 checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" 127 133 128 134 [[package]] 135 + name = "bumpalo" 136 + version = "3.19.1" 137 + source = "registry+https://github.com/rust-lang/crates.io-index" 138 + checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" 139 + 140 + [[package]] 129 141 name = "bytes" 130 142 version = "1.11.0" 131 143 source = "registry+https://github.com/rust-lang/crates.io-index" 132 144 checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" 145 + 146 + [[package]] 147 + name = "cc" 148 + version = "1.2.51" 149 + source = "registry+https://github.com/rust-lang/crates.io-index" 150 + checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" 151 + dependencies = [ 152 + "find-msvc-tools", 153 + "shlex", 154 + ] 133 155 134 156 [[package]] 135 157 name = "cfg-if" ··· 184 206 checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 185 207 186 208 [[package]] 209 + name = "cookie" 210 + version = "0.18.1" 211 + source = "registry+https://github.com/rust-lang/crates.io-index" 212 + checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" 213 + dependencies = [ 214 + "percent-encoding", 215 + "time", 216 + "version_check", 217 + ] 218 + 219 + [[package]] 220 + name = "core-foundation" 221 + version = "0.9.4" 222 + source = "registry+https://github.com/rust-lang/crates.io-index" 223 + checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 224 + dependencies = [ 225 + "core-foundation-sys", 226 + "libc", 227 + ] 228 + 229 + [[package]] 230 + name = "core-foundation-sys" 231 + version = "0.8.7" 232 + source = "registry+https://github.com/rust-lang/crates.io-index" 233 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 234 + 235 + [[package]] 236 + name = "deranged" 237 + version = "0.5.5" 238 + source = "registry+https://github.com/rust-lang/crates.io-index" 239 + checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" 240 + dependencies = [ 241 + "powerfmt", 242 + ] 243 + 244 + [[package]] 245 + name = "displaydoc" 246 + version = "0.2.5" 247 + source = "registry+https://github.com/rust-lang/crates.io-index" 248 + checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 249 + dependencies = [ 250 + "proc-macro2", 251 + "quote", 252 + "syn", 253 + ] 254 + 255 + [[package]] 256 + name = "encoding_rs" 257 + version = "0.8.35" 258 + source = "registry+https://github.com/rust-lang/crates.io-index" 259 + checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 260 + dependencies = [ 261 + "cfg-if", 262 + ] 263 + 264 + [[package]] 265 + name = "equivalent" 266 + version = "1.0.2" 267 + source = "registry+https://github.com/rust-lang/crates.io-index" 268 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 269 + 270 + [[package]] 187 271 name = "errno" 188 272 version = "0.3.14" 189 273 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 194 278 ] 195 279 196 280 [[package]] 281 + name = "fastrand" 282 + version = "2.3.0" 283 + source = "registry+https://github.com/rust-lang/crates.io-index" 284 + checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 285 + 286 + [[package]] 287 + name = "find-msvc-tools" 288 + version = "0.1.6" 289 + source = "registry+https://github.com/rust-lang/crates.io-index" 290 + checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" 291 + 292 + [[package]] 293 + name = "fnv" 294 + version = "1.0.7" 295 + source = "registry+https://github.com/rust-lang/crates.io-index" 296 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 297 + 298 + [[package]] 299 + name = "foreign-types" 300 + version = "0.3.2" 301 + source = "registry+https://github.com/rust-lang/crates.io-index" 302 + checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 303 + dependencies = [ 304 + "foreign-types-shared", 305 + ] 306 + 307 + [[package]] 308 + name = "foreign-types-shared" 309 + version = "0.1.1" 310 + source = "registry+https://github.com/rust-lang/crates.io-index" 311 + checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 312 + 313 + [[package]] 197 314 name = "form_urlencoded" 198 315 version = "1.2.2" 199 316 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 218 335 checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 219 336 220 337 [[package]] 338 + name = "futures-macro" 339 + version = "0.3.31" 340 + source = "registry+https://github.com/rust-lang/crates.io-index" 341 + checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 342 + dependencies = [ 343 + "proc-macro2", 344 + "quote", 345 + "syn", 346 + ] 347 + 348 + [[package]] 349 + name = "futures-sink" 350 + version = "0.3.31" 351 + source = "registry+https://github.com/rust-lang/crates.io-index" 352 + checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 353 + 354 + [[package]] 221 355 name = "futures-task" 222 356 version = "0.3.31" 223 357 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 230 364 checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 231 365 dependencies = [ 232 366 "futures-core", 367 + "futures-macro", 233 368 "futures-task", 234 369 "pin-project-lite", 235 370 "pin-utils", 371 + "slab", 236 372 ] 237 373 238 374 [[package]] 375 + name = "getrandom" 376 + version = "0.2.16" 377 + source = "registry+https://github.com/rust-lang/crates.io-index" 378 + checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 379 + dependencies = [ 380 + "cfg-if", 381 + "libc", 382 + "wasi", 383 + ] 384 + 385 + [[package]] 386 + name = "getrandom" 387 + version = "0.3.4" 388 + source = "registry+https://github.com/rust-lang/crates.io-index" 389 + checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" 390 + dependencies = [ 391 + "cfg-if", 392 + "libc", 393 + "r-efi", 394 + "wasip2", 395 + ] 396 + 397 + [[package]] 398 + name = "h2" 399 + version = "0.4.12" 400 + source = "registry+https://github.com/rust-lang/crates.io-index" 401 + checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" 402 + dependencies = [ 403 + "atomic-waker", 404 + "bytes", 405 + "fnv", 406 + "futures-core", 407 + "futures-sink", 408 + "http", 409 + "indexmap", 410 + "slab", 411 + "tokio", 412 + "tokio-util", 413 + "tracing", 414 + ] 415 + 416 + [[package]] 417 + name = "hashbrown" 418 + version = "0.16.1" 419 + source = "registry+https://github.com/rust-lang/crates.io-index" 420 + checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 421 + 422 + [[package]] 239 423 name = "heck" 240 424 version = "0.5.0" 241 425 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 296 480 "bytes", 297 481 "futures-channel", 298 482 "futures-core", 483 + "h2", 299 484 "http", 300 485 "http-body", 301 486 "httparse", ··· 305 490 "pin-utils", 306 491 "smallvec", 307 492 "tokio", 493 + "want", 494 + ] 495 + 496 + [[package]] 497 + name = "hyper-rustls" 498 + version = "0.27.7" 499 + source = "registry+https://github.com/rust-lang/crates.io-index" 500 + checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" 501 + dependencies = [ 502 + "http", 503 + "hyper", 504 + "hyper-util", 505 + "rustls", 506 + "rustls-pki-types", 507 + "tokio", 508 + "tokio-rustls", 509 + "tower-service", 510 + ] 511 + 512 + [[package]] 513 + name = "hyper-tls" 514 + version = "0.6.0" 515 + source = "registry+https://github.com/rust-lang/crates.io-index" 516 + checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 517 + dependencies = [ 518 + "bytes", 519 + "http-body-util", 520 + "hyper", 521 + "hyper-util", 522 + "native-tls", 523 + "tokio", 524 + "tokio-native-tls", 525 + "tower-service", 308 526 ] 309 527 310 528 [[package]] ··· 313 531 source = "registry+https://github.com/rust-lang/crates.io-index" 314 532 checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" 315 533 dependencies = [ 534 + "base64", 316 535 "bytes", 536 + "futures-channel", 317 537 "futures-core", 538 + "futures-util", 318 539 "http", 319 540 "http-body", 320 541 "hyper", 542 + "ipnet", 543 + "libc", 544 + "percent-encoding", 321 545 "pin-project-lite", 546 + "socket2", 547 + "system-configuration", 322 548 "tokio", 323 549 "tower-service", 550 + "tracing", 551 + "windows-registry", 552 + ] 553 + 554 + [[package]] 555 + name = "icu_collections" 556 + version = "2.1.1" 557 + source = "registry+https://github.com/rust-lang/crates.io-index" 558 + checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" 559 + dependencies = [ 560 + "displaydoc", 561 + "potential_utf", 562 + "yoke", 563 + "zerofrom", 564 + "zerovec", 565 + ] 566 + 567 + [[package]] 568 + name = "icu_locale_core" 569 + version = "2.1.1" 570 + source = "registry+https://github.com/rust-lang/crates.io-index" 571 + checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" 572 + dependencies = [ 573 + "displaydoc", 574 + "litemap", 575 + "tinystr", 576 + "writeable", 577 + "zerovec", 578 + ] 579 + 580 + [[package]] 581 + name = "icu_normalizer" 582 + version = "2.1.1" 583 + source = "registry+https://github.com/rust-lang/crates.io-index" 584 + checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" 585 + dependencies = [ 586 + "icu_collections", 587 + "icu_normalizer_data", 588 + "icu_properties", 589 + "icu_provider", 590 + "smallvec", 591 + "zerovec", 592 + ] 593 + 594 + [[package]] 595 + name = "icu_normalizer_data" 596 + version = "2.1.1" 597 + source = "registry+https://github.com/rust-lang/crates.io-index" 598 + checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" 599 + 600 + [[package]] 601 + name = "icu_properties" 602 + version = "2.1.2" 603 + source = "registry+https://github.com/rust-lang/crates.io-index" 604 + checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" 605 + dependencies = [ 606 + "icu_collections", 607 + "icu_locale_core", 608 + "icu_properties_data", 609 + "icu_provider", 610 + "zerotrie", 611 + "zerovec", 612 + ] 613 + 614 + [[package]] 615 + name = "icu_properties_data" 616 + version = "2.1.2" 617 + source = "registry+https://github.com/rust-lang/crates.io-index" 618 + checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" 619 + 620 + [[package]] 621 + name = "icu_provider" 622 + version = "2.1.1" 623 + source = "registry+https://github.com/rust-lang/crates.io-index" 624 + checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" 625 + dependencies = [ 626 + "displaydoc", 627 + "icu_locale_core", 628 + "writeable", 629 + "yoke", 630 + "zerofrom", 631 + "zerotrie", 632 + "zerovec", 633 + ] 634 + 635 + [[package]] 636 + name = "idna" 637 + version = "1.1.0" 638 + source = "registry+https://github.com/rust-lang/crates.io-index" 639 + checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 640 + dependencies = [ 641 + "idna_adapter", 642 + "smallvec", 643 + "utf8_iter", 644 + ] 645 + 646 + [[package]] 647 + name = "idna_adapter" 648 + version = "1.2.1" 649 + source = "registry+https://github.com/rust-lang/crates.io-index" 650 + checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 651 + dependencies = [ 652 + "icu_normalizer", 653 + "icu_properties", 654 + ] 655 + 656 + [[package]] 657 + name = "indexmap" 658 + version = "2.12.1" 659 + source = "registry+https://github.com/rust-lang/crates.io-index" 660 + checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" 661 + dependencies = [ 662 + "equivalent", 663 + "hashbrown", 664 + ] 665 + 666 + [[package]] 667 + name = "ipnet" 668 + version = "2.11.0" 669 + source = "registry+https://github.com/rust-lang/crates.io-index" 670 + checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 671 + 672 + [[package]] 673 + name = "iri-string" 674 + version = "0.7.9" 675 + source = "registry+https://github.com/rust-lang/crates.io-index" 676 + checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" 677 + dependencies = [ 678 + "memchr", 679 + "serde", 324 680 ] 325 681 326 682 [[package]] ··· 336 692 checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" 337 693 338 694 [[package]] 695 + name = "js-sys" 696 + version = "0.3.83" 697 + source = "registry+https://github.com/rust-lang/crates.io-index" 698 + checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" 699 + dependencies = [ 700 + "once_cell", 701 + "wasm-bindgen", 702 + ] 703 + 704 + [[package]] 339 705 name = "lazy_static" 340 706 version = "1.5.0" 341 707 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 348 714 checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" 349 715 350 716 [[package]] 717 + name = "linux-raw-sys" 718 + version = "0.11.0" 719 + source = "registry+https://github.com/rust-lang/crates.io-index" 720 + checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 721 + 722 + [[package]] 723 + name = "litemap" 724 + version = "0.8.1" 725 + source = "registry+https://github.com/rust-lang/crates.io-index" 726 + checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 727 + 728 + [[package]] 351 729 name = "lock_api" 352 730 version = "0.4.14" 353 731 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 387 765 dependencies = [ 388 766 "axum", 389 767 "malfestio-core", 768 + "reqwest", 390 769 "serde", 391 770 "serde_json", 392 771 "tokio", 393 772 "tower", 773 + "tower-cookies", 394 774 "tower-http", 395 775 "tracing", 396 776 "tracing-subscriber", 777 + "uuid", 397 778 ] 398 779 399 780 [[package]] ··· 435 816 ] 436 817 437 818 [[package]] 819 + name = "native-tls" 820 + version = "0.2.14" 821 + source = "registry+https://github.com/rust-lang/crates.io-index" 822 + checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" 823 + dependencies = [ 824 + "libc", 825 + "log", 826 + "openssl", 827 + "openssl-probe", 828 + "openssl-sys", 829 + "schannel", 830 + "security-framework", 831 + "security-framework-sys", 832 + "tempfile", 833 + ] 834 + 835 + [[package]] 438 836 name = "nu-ansi-term" 439 837 version = "0.50.3" 440 838 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 444 842 ] 445 843 446 844 [[package]] 845 + name = "num-conv" 846 + version = "0.1.0" 847 + source = "registry+https://github.com/rust-lang/crates.io-index" 848 + checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 849 + 850 + [[package]] 447 851 name = "once_cell" 448 852 version = "1.21.3" 449 853 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 456 860 checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" 457 861 458 862 [[package]] 863 + name = "openssl" 864 + version = "0.10.75" 865 + source = "registry+https://github.com/rust-lang/crates.io-index" 866 + checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" 867 + dependencies = [ 868 + "bitflags", 869 + "cfg-if", 870 + "foreign-types", 871 + "libc", 872 + "once_cell", 873 + "openssl-macros", 874 + "openssl-sys", 875 + ] 876 + 877 + [[package]] 878 + name = "openssl-macros" 879 + version = "0.1.1" 880 + source = "registry+https://github.com/rust-lang/crates.io-index" 881 + checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 882 + dependencies = [ 883 + "proc-macro2", 884 + "quote", 885 + "syn", 886 + ] 887 + 888 + [[package]] 889 + name = "openssl-probe" 890 + version = "0.1.6" 891 + source = "registry+https://github.com/rust-lang/crates.io-index" 892 + checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 893 + 894 + [[package]] 895 + name = "openssl-sys" 896 + version = "0.9.111" 897 + source = "registry+https://github.com/rust-lang/crates.io-index" 898 + checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" 899 + dependencies = [ 900 + "cc", 901 + "libc", 902 + "pkg-config", 903 + "vcpkg", 904 + ] 905 + 906 + [[package]] 459 907 name = "parking_lot" 460 908 version = "0.12.5" 461 909 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 497 945 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 498 946 499 947 [[package]] 948 + name = "pkg-config" 949 + version = "0.3.32" 950 + source = "registry+https://github.com/rust-lang/crates.io-index" 951 + checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 952 + 953 + [[package]] 954 + name = "potential_utf" 955 + version = "0.1.4" 956 + source = "registry+https://github.com/rust-lang/crates.io-index" 957 + checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" 958 + dependencies = [ 959 + "zerovec", 960 + ] 961 + 962 + [[package]] 963 + name = "powerfmt" 964 + version = "0.2.0" 965 + source = "registry+https://github.com/rust-lang/crates.io-index" 966 + checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 967 + 968 + [[package]] 969 + name = "ppv-lite86" 970 + version = "0.2.21" 971 + source = "registry+https://github.com/rust-lang/crates.io-index" 972 + checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 973 + dependencies = [ 974 + "zerocopy", 975 + ] 976 + 977 + [[package]] 500 978 name = "proc-macro2" 501 979 version = "1.0.104" 502 980 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 515 993 ] 516 994 517 995 [[package]] 996 + name = "r-efi" 997 + version = "5.3.0" 998 + source = "registry+https://github.com/rust-lang/crates.io-index" 999 + checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 1000 + 1001 + [[package]] 1002 + name = "rand" 1003 + version = "0.9.2" 1004 + source = "registry+https://github.com/rust-lang/crates.io-index" 1005 + checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 1006 + dependencies = [ 1007 + "rand_chacha", 1008 + "rand_core", 1009 + ] 1010 + 1011 + [[package]] 1012 + name = "rand_chacha" 1013 + version = "0.9.0" 1014 + source = "registry+https://github.com/rust-lang/crates.io-index" 1015 + checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1016 + dependencies = [ 1017 + "ppv-lite86", 1018 + "rand_core", 1019 + ] 1020 + 1021 + [[package]] 1022 + name = "rand_core" 1023 + version = "0.9.3" 1024 + source = "registry+https://github.com/rust-lang/crates.io-index" 1025 + checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1026 + dependencies = [ 1027 + "getrandom 0.3.4", 1028 + ] 1029 + 1030 + [[package]] 518 1031 name = "redox_syscall" 519 1032 version = "0.5.18" 520 1033 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 541 1054 checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" 542 1055 543 1056 [[package]] 1057 + name = "reqwest" 1058 + version = "0.12.28" 1059 + source = "registry+https://github.com/rust-lang/crates.io-index" 1060 + checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" 1061 + dependencies = [ 1062 + "base64", 1063 + "bytes", 1064 + "encoding_rs", 1065 + "futures-core", 1066 + "h2", 1067 + "http", 1068 + "http-body", 1069 + "http-body-util", 1070 + "hyper", 1071 + "hyper-rustls", 1072 + "hyper-tls", 1073 + "hyper-util", 1074 + "js-sys", 1075 + "log", 1076 + "mime", 1077 + "native-tls", 1078 + "percent-encoding", 1079 + "pin-project-lite", 1080 + "rustls-pki-types", 1081 + "serde", 1082 + "serde_json", 1083 + "serde_urlencoded", 1084 + "sync_wrapper", 1085 + "tokio", 1086 + "tokio-native-tls", 1087 + "tower", 1088 + "tower-http", 1089 + "tower-service", 1090 + "url", 1091 + "wasm-bindgen", 1092 + "wasm-bindgen-futures", 1093 + "web-sys", 1094 + ] 1095 + 1096 + [[package]] 1097 + name = "ring" 1098 + version = "0.17.14" 1099 + source = "registry+https://github.com/rust-lang/crates.io-index" 1100 + checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1101 + dependencies = [ 1102 + "cc", 1103 + "cfg-if", 1104 + "getrandom 0.2.16", 1105 + "libc", 1106 + "untrusted", 1107 + "windows-sys 0.52.0", 1108 + ] 1109 + 1110 + [[package]] 1111 + name = "rustix" 1112 + version = "1.1.3" 1113 + source = "registry+https://github.com/rust-lang/crates.io-index" 1114 + checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" 1115 + dependencies = [ 1116 + "bitflags", 1117 + "errno", 1118 + "libc", 1119 + "linux-raw-sys", 1120 + "windows-sys 0.61.2", 1121 + ] 1122 + 1123 + [[package]] 1124 + name = "rustls" 1125 + version = "0.23.35" 1126 + source = "registry+https://github.com/rust-lang/crates.io-index" 1127 + checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" 1128 + dependencies = [ 1129 + "once_cell", 1130 + "rustls-pki-types", 1131 + "rustls-webpki", 1132 + "subtle", 1133 + "zeroize", 1134 + ] 1135 + 1136 + [[package]] 1137 + name = "rustls-pki-types" 1138 + version = "1.13.2" 1139 + source = "registry+https://github.com/rust-lang/crates.io-index" 1140 + checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" 1141 + dependencies = [ 1142 + "zeroize", 1143 + ] 1144 + 1145 + [[package]] 1146 + name = "rustls-webpki" 1147 + version = "0.103.8" 1148 + source = "registry+https://github.com/rust-lang/crates.io-index" 1149 + checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" 1150 + dependencies = [ 1151 + "ring", 1152 + "rustls-pki-types", 1153 + "untrusted", 1154 + ] 1155 + 1156 + [[package]] 1157 + name = "rustversion" 1158 + version = "1.0.22" 1159 + source = "registry+https://github.com/rust-lang/crates.io-index" 1160 + checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 1161 + 1162 + [[package]] 544 1163 name = "ryu" 545 1164 version = "1.0.22" 546 1165 source = "registry+https://github.com/rust-lang/crates.io-index" 547 1166 checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" 548 1167 549 1168 [[package]] 1169 + name = "schannel" 1170 + version = "0.1.28" 1171 + source = "registry+https://github.com/rust-lang/crates.io-index" 1172 + checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" 1173 + dependencies = [ 1174 + "windows-sys 0.61.2", 1175 + ] 1176 + 1177 + [[package]] 550 1178 name = "scopeguard" 551 1179 version = "1.2.0" 552 1180 source = "registry+https://github.com/rust-lang/crates.io-index" 553 1181 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 554 1182 555 1183 [[package]] 1184 + name = "security-framework" 1185 + version = "2.11.1" 1186 + source = "registry+https://github.com/rust-lang/crates.io-index" 1187 + checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1188 + dependencies = [ 1189 + "bitflags", 1190 + "core-foundation", 1191 + "core-foundation-sys", 1192 + "libc", 1193 + "security-framework-sys", 1194 + ] 1195 + 1196 + [[package]] 1197 + name = "security-framework-sys" 1198 + version = "2.15.0" 1199 + source = "registry+https://github.com/rust-lang/crates.io-index" 1200 + checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" 1201 + dependencies = [ 1202 + "core-foundation-sys", 1203 + "libc", 1204 + ] 1205 + 1206 + [[package]] 556 1207 name = "serde" 557 1208 version = "1.0.228" 558 1209 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 628 1279 ] 629 1280 630 1281 [[package]] 1282 + name = "shlex" 1283 + version = "1.3.0" 1284 + source = "registry+https://github.com/rust-lang/crates.io-index" 1285 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1286 + 1287 + [[package]] 631 1288 name = "signal-hook-registry" 632 1289 version = "1.4.8" 633 1290 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 638 1295 ] 639 1296 640 1297 [[package]] 1298 + name = "slab" 1299 + version = "0.4.11" 1300 + source = "registry+https://github.com/rust-lang/crates.io-index" 1301 + checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 1302 + 1303 + [[package]] 641 1304 name = "smallvec" 642 1305 version = "1.15.1" 643 1306 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 654 1317 ] 655 1318 656 1319 [[package]] 1320 + name = "stable_deref_trait" 1321 + version = "1.2.1" 1322 + source = "registry+https://github.com/rust-lang/crates.io-index" 1323 + checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 1324 + 1325 + [[package]] 657 1326 name = "strsim" 658 1327 version = "0.11.1" 659 1328 source = "registry+https://github.com/rust-lang/crates.io-index" 660 1329 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 661 1330 662 1331 [[package]] 1332 + name = "subtle" 1333 + version = "2.6.1" 1334 + source = "registry+https://github.com/rust-lang/crates.io-index" 1335 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1336 + 1337 + [[package]] 663 1338 name = "syn" 664 1339 version = "2.0.111" 665 1340 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 675 1350 version = "1.0.2" 676 1351 source = "registry+https://github.com/rust-lang/crates.io-index" 677 1352 checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1353 + dependencies = [ 1354 + "futures-core", 1355 + ] 1356 + 1357 + [[package]] 1358 + name = "synstructure" 1359 + version = "0.13.2" 1360 + source = "registry+https://github.com/rust-lang/crates.io-index" 1361 + checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1362 + dependencies = [ 1363 + "proc-macro2", 1364 + "quote", 1365 + "syn", 1366 + ] 1367 + 1368 + [[package]] 1369 + name = "system-configuration" 1370 + version = "0.6.1" 1371 + source = "registry+https://github.com/rust-lang/crates.io-index" 1372 + checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 1373 + dependencies = [ 1374 + "bitflags", 1375 + "core-foundation", 1376 + "system-configuration-sys", 1377 + ] 1378 + 1379 + [[package]] 1380 + name = "system-configuration-sys" 1381 + version = "0.6.0" 1382 + source = "registry+https://github.com/rust-lang/crates.io-index" 1383 + checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1384 + dependencies = [ 1385 + "core-foundation-sys", 1386 + "libc", 1387 + ] 1388 + 1389 + [[package]] 1390 + name = "tempfile" 1391 + version = "3.24.0" 1392 + source = "registry+https://github.com/rust-lang/crates.io-index" 1393 + checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" 1394 + dependencies = [ 1395 + "fastrand", 1396 + "getrandom 0.3.4", 1397 + "once_cell", 1398 + "rustix", 1399 + "windows-sys 0.61.2", 1400 + ] 678 1401 679 1402 [[package]] 680 1403 name = "thiserror" ··· 706 1429 ] 707 1430 708 1431 [[package]] 1432 + name = "time" 1433 + version = "0.3.44" 1434 + source = "registry+https://github.com/rust-lang/crates.io-index" 1435 + checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" 1436 + dependencies = [ 1437 + "deranged", 1438 + "itoa", 1439 + "num-conv", 1440 + "powerfmt", 1441 + "serde", 1442 + "time-core", 1443 + "time-macros", 1444 + ] 1445 + 1446 + [[package]] 1447 + name = "time-core" 1448 + version = "0.1.6" 1449 + source = "registry+https://github.com/rust-lang/crates.io-index" 1450 + checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" 1451 + 1452 + [[package]] 1453 + name = "time-macros" 1454 + version = "0.2.24" 1455 + source = "registry+https://github.com/rust-lang/crates.io-index" 1456 + checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" 1457 + dependencies = [ 1458 + "num-conv", 1459 + "time-core", 1460 + ] 1461 + 1462 + [[package]] 1463 + name = "tinystr" 1464 + version = "0.8.2" 1465 + source = "registry+https://github.com/rust-lang/crates.io-index" 1466 + checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" 1467 + dependencies = [ 1468 + "displaydoc", 1469 + "zerovec", 1470 + ] 1471 + 1472 + [[package]] 709 1473 name = "tokio" 710 1474 version = "1.48.0" 711 1475 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 734 1498 ] 735 1499 736 1500 [[package]] 1501 + name = "tokio-native-tls" 1502 + version = "0.3.1" 1503 + source = "registry+https://github.com/rust-lang/crates.io-index" 1504 + checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1505 + dependencies = [ 1506 + "native-tls", 1507 + "tokio", 1508 + ] 1509 + 1510 + [[package]] 1511 + name = "tokio-rustls" 1512 + version = "0.26.4" 1513 + source = "registry+https://github.com/rust-lang/crates.io-index" 1514 + checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" 1515 + dependencies = [ 1516 + "rustls", 1517 + "tokio", 1518 + ] 1519 + 1520 + [[package]] 1521 + name = "tokio-util" 1522 + version = "0.7.17" 1523 + source = "registry+https://github.com/rust-lang/crates.io-index" 1524 + checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" 1525 + dependencies = [ 1526 + "bytes", 1527 + "futures-core", 1528 + "futures-sink", 1529 + "pin-project-lite", 1530 + "tokio", 1531 + ] 1532 + 1533 + [[package]] 737 1534 name = "tower" 738 1535 version = "0.5.2" 739 1536 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 750 1547 ] 751 1548 752 1549 [[package]] 1550 + name = "tower-cookies" 1551 + version = "0.11.0" 1552 + source = "registry+https://github.com/rust-lang/crates.io-index" 1553 + checksum = "151b5a3e3c45df17466454bb74e9ecedecc955269bdedbf4d150dfa393b55a36" 1554 + dependencies = [ 1555 + "axum-core", 1556 + "cookie", 1557 + "futures-util", 1558 + "http", 1559 + "parking_lot", 1560 + "pin-project-lite", 1561 + "tower-layer", 1562 + "tower-service", 1563 + ] 1564 + 1565 + [[package]] 753 1566 name = "tower-http" 754 1567 version = "0.6.8" 755 1568 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 757 1570 dependencies = [ 758 1571 "bitflags", 759 1572 "bytes", 1573 + "futures-util", 760 1574 "http", 761 1575 "http-body", 1576 + "iri-string", 762 1577 "pin-project-lite", 1578 + "tower", 763 1579 "tower-layer", 764 1580 "tower-service", 765 1581 "tracing", ··· 840 1656 ] 841 1657 842 1658 [[package]] 1659 + name = "try-lock" 1660 + version = "0.2.5" 1661 + source = "registry+https://github.com/rust-lang/crates.io-index" 1662 + checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1663 + 1664 + [[package]] 843 1665 name = "unicode-ident" 844 1666 version = "1.0.22" 845 1667 source = "registry+https://github.com/rust-lang/crates.io-index" 846 1668 checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 847 1669 848 1670 [[package]] 1671 + name = "untrusted" 1672 + version = "0.9.0" 1673 + source = "registry+https://github.com/rust-lang/crates.io-index" 1674 + checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1675 + 1676 + [[package]] 1677 + name = "url" 1678 + version = "2.5.7" 1679 + source = "registry+https://github.com/rust-lang/crates.io-index" 1680 + checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 1681 + dependencies = [ 1682 + "form_urlencoded", 1683 + "idna", 1684 + "percent-encoding", 1685 + "serde", 1686 + ] 1687 + 1688 + [[package]] 1689 + name = "utf8_iter" 1690 + version = "1.0.4" 1691 + source = "registry+https://github.com/rust-lang/crates.io-index" 1692 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1693 + 1694 + [[package]] 849 1695 name = "utf8parse" 850 1696 version = "0.2.2" 851 1697 source = "registry+https://github.com/rust-lang/crates.io-index" 852 1698 checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 853 1699 854 1700 [[package]] 1701 + name = "uuid" 1702 + version = "1.19.0" 1703 + source = "registry+https://github.com/rust-lang/crates.io-index" 1704 + checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" 1705 + dependencies = [ 1706 + "getrandom 0.3.4", 1707 + "js-sys", 1708 + "rand", 1709 + "wasm-bindgen", 1710 + ] 1711 + 1712 + [[package]] 855 1713 name = "valuable" 856 1714 version = "0.1.1" 857 1715 source = "registry+https://github.com/rust-lang/crates.io-index" 858 1716 checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 859 1717 860 1718 [[package]] 1719 + name = "vcpkg" 1720 + version = "0.2.15" 1721 + source = "registry+https://github.com/rust-lang/crates.io-index" 1722 + checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1723 + 1724 + [[package]] 1725 + name = "version_check" 1726 + version = "0.9.5" 1727 + source = "registry+https://github.com/rust-lang/crates.io-index" 1728 + checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1729 + 1730 + [[package]] 1731 + name = "want" 1732 + version = "0.3.1" 1733 + source = "registry+https://github.com/rust-lang/crates.io-index" 1734 + checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1735 + dependencies = [ 1736 + "try-lock", 1737 + ] 1738 + 1739 + [[package]] 861 1740 name = "wasi" 862 1741 version = "0.11.1+wasi-snapshot-preview1" 863 1742 source = "registry+https://github.com/rust-lang/crates.io-index" 864 1743 checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 865 1744 866 1745 [[package]] 1746 + name = "wasip2" 1747 + version = "1.0.1+wasi-0.2.4" 1748 + source = "registry+https://github.com/rust-lang/crates.io-index" 1749 + checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" 1750 + dependencies = [ 1751 + "wit-bindgen", 1752 + ] 1753 + 1754 + [[package]] 1755 + name = "wasm-bindgen" 1756 + version = "0.2.106" 1757 + source = "registry+https://github.com/rust-lang/crates.io-index" 1758 + checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" 1759 + dependencies = [ 1760 + "cfg-if", 1761 + "once_cell", 1762 + "rustversion", 1763 + "wasm-bindgen-macro", 1764 + "wasm-bindgen-shared", 1765 + ] 1766 + 1767 + [[package]] 1768 + name = "wasm-bindgen-futures" 1769 + version = "0.4.56" 1770 + source = "registry+https://github.com/rust-lang/crates.io-index" 1771 + checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" 1772 + dependencies = [ 1773 + "cfg-if", 1774 + "js-sys", 1775 + "once_cell", 1776 + "wasm-bindgen", 1777 + "web-sys", 1778 + ] 1779 + 1780 + [[package]] 1781 + name = "wasm-bindgen-macro" 1782 + version = "0.2.106" 1783 + source = "registry+https://github.com/rust-lang/crates.io-index" 1784 + checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" 1785 + dependencies = [ 1786 + "quote", 1787 + "wasm-bindgen-macro-support", 1788 + ] 1789 + 1790 + [[package]] 1791 + name = "wasm-bindgen-macro-support" 1792 + version = "0.2.106" 1793 + source = "registry+https://github.com/rust-lang/crates.io-index" 1794 + checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" 1795 + dependencies = [ 1796 + "bumpalo", 1797 + "proc-macro2", 1798 + "quote", 1799 + "syn", 1800 + "wasm-bindgen-shared", 1801 + ] 1802 + 1803 + [[package]] 1804 + name = "wasm-bindgen-shared" 1805 + version = "0.2.106" 1806 + source = "registry+https://github.com/rust-lang/crates.io-index" 1807 + checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" 1808 + dependencies = [ 1809 + "unicode-ident", 1810 + ] 1811 + 1812 + [[package]] 1813 + name = "web-sys" 1814 + version = "0.3.83" 1815 + source = "registry+https://github.com/rust-lang/crates.io-index" 1816 + checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" 1817 + dependencies = [ 1818 + "js-sys", 1819 + "wasm-bindgen", 1820 + ] 1821 + 1822 + [[package]] 867 1823 name = "windows-link" 868 1824 version = "0.2.1" 869 1825 source = "registry+https://github.com/rust-lang/crates.io-index" 870 1826 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 871 1827 872 1828 [[package]] 1829 + name = "windows-registry" 1830 + version = "0.6.1" 1831 + source = "registry+https://github.com/rust-lang/crates.io-index" 1832 + checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 1833 + dependencies = [ 1834 + "windows-link", 1835 + "windows-result", 1836 + "windows-strings", 1837 + ] 1838 + 1839 + [[package]] 1840 + name = "windows-result" 1841 + version = "0.4.1" 1842 + source = "registry+https://github.com/rust-lang/crates.io-index" 1843 + checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 1844 + dependencies = [ 1845 + "windows-link", 1846 + ] 1847 + 1848 + [[package]] 1849 + name = "windows-strings" 1850 + version = "0.5.1" 1851 + source = "registry+https://github.com/rust-lang/crates.io-index" 1852 + checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 1853 + dependencies = [ 1854 + "windows-link", 1855 + ] 1856 + 1857 + [[package]] 1858 + name = "windows-sys" 1859 + version = "0.52.0" 1860 + source = "registry+https://github.com/rust-lang/crates.io-index" 1861 + checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1862 + dependencies = [ 1863 + "windows-targets 0.52.6", 1864 + ] 1865 + 1866 + [[package]] 873 1867 name = "windows-sys" 874 1868 version = "0.60.2" 875 1869 source = "registry+https://github.com/rust-lang/crates.io-index" 876 1870 checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 877 1871 dependencies = [ 878 - "windows-targets", 1872 + "windows-targets 0.53.5", 879 1873 ] 880 1874 881 1875 [[package]] ··· 889 1883 890 1884 [[package]] 891 1885 name = "windows-targets" 1886 + version = "0.52.6" 1887 + source = "registry+https://github.com/rust-lang/crates.io-index" 1888 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1889 + dependencies = [ 1890 + "windows_aarch64_gnullvm 0.52.6", 1891 + "windows_aarch64_msvc 0.52.6", 1892 + "windows_i686_gnu 0.52.6", 1893 + "windows_i686_gnullvm 0.52.6", 1894 + "windows_i686_msvc 0.52.6", 1895 + "windows_x86_64_gnu 0.52.6", 1896 + "windows_x86_64_gnullvm 0.52.6", 1897 + "windows_x86_64_msvc 0.52.6", 1898 + ] 1899 + 1900 + [[package]] 1901 + name = "windows-targets" 892 1902 version = "0.53.5" 893 1903 source = "registry+https://github.com/rust-lang/crates.io-index" 894 1904 checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 895 1905 dependencies = [ 896 1906 "windows-link", 897 - "windows_aarch64_gnullvm", 898 - "windows_aarch64_msvc", 899 - "windows_i686_gnu", 900 - "windows_i686_gnullvm", 901 - "windows_i686_msvc", 902 - "windows_x86_64_gnu", 903 - "windows_x86_64_gnullvm", 904 - "windows_x86_64_msvc", 1907 + "windows_aarch64_gnullvm 0.53.1", 1908 + "windows_aarch64_msvc 0.53.1", 1909 + "windows_i686_gnu 0.53.1", 1910 + "windows_i686_gnullvm 0.53.1", 1911 + "windows_i686_msvc 0.53.1", 1912 + "windows_x86_64_gnu 0.53.1", 1913 + "windows_x86_64_gnullvm 0.53.1", 1914 + "windows_x86_64_msvc 0.53.1", 905 1915 ] 1916 + 1917 + [[package]] 1918 + name = "windows_aarch64_gnullvm" 1919 + version = "0.52.6" 1920 + source = "registry+https://github.com/rust-lang/crates.io-index" 1921 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 906 1922 907 1923 [[package]] 908 1924 name = "windows_aarch64_gnullvm" ··· 912 1928 913 1929 [[package]] 914 1930 name = "windows_aarch64_msvc" 1931 + version = "0.52.6" 1932 + source = "registry+https://github.com/rust-lang/crates.io-index" 1933 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1934 + 1935 + [[package]] 1936 + name = "windows_aarch64_msvc" 915 1937 version = "0.53.1" 916 1938 source = "registry+https://github.com/rust-lang/crates.io-index" 917 1939 checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 918 1940 919 1941 [[package]] 920 1942 name = "windows_i686_gnu" 1943 + version = "0.52.6" 1944 + source = "registry+https://github.com/rust-lang/crates.io-index" 1945 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1946 + 1947 + [[package]] 1948 + name = "windows_i686_gnu" 921 1949 version = "0.53.1" 922 1950 source = "registry+https://github.com/rust-lang/crates.io-index" 923 1951 checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 924 1952 925 1953 [[package]] 926 1954 name = "windows_i686_gnullvm" 1955 + version = "0.52.6" 1956 + source = "registry+https://github.com/rust-lang/crates.io-index" 1957 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1958 + 1959 + [[package]] 1960 + name = "windows_i686_gnullvm" 927 1961 version = "0.53.1" 928 1962 source = "registry+https://github.com/rust-lang/crates.io-index" 929 1963 checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 930 1964 931 1965 [[package]] 932 1966 name = "windows_i686_msvc" 1967 + version = "0.52.6" 1968 + source = "registry+https://github.com/rust-lang/crates.io-index" 1969 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1970 + 1971 + [[package]] 1972 + name = "windows_i686_msvc" 933 1973 version = "0.53.1" 934 1974 source = "registry+https://github.com/rust-lang/crates.io-index" 935 1975 checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 936 1976 937 1977 [[package]] 938 1978 name = "windows_x86_64_gnu" 1979 + version = "0.52.6" 1980 + source = "registry+https://github.com/rust-lang/crates.io-index" 1981 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1982 + 1983 + [[package]] 1984 + name = "windows_x86_64_gnu" 939 1985 version = "0.53.1" 940 1986 source = "registry+https://github.com/rust-lang/crates.io-index" 941 1987 checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 942 1988 943 1989 [[package]] 944 1990 name = "windows_x86_64_gnullvm" 1991 + version = "0.52.6" 1992 + source = "registry+https://github.com/rust-lang/crates.io-index" 1993 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1994 + 1995 + [[package]] 1996 + name = "windows_x86_64_gnullvm" 945 1997 version = "0.53.1" 946 1998 source = "registry+https://github.com/rust-lang/crates.io-index" 947 1999 checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 948 2000 949 2001 [[package]] 950 2002 name = "windows_x86_64_msvc" 2003 + version = "0.52.6" 2004 + source = "registry+https://github.com/rust-lang/crates.io-index" 2005 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2006 + 2007 + [[package]] 2008 + name = "windows_x86_64_msvc" 951 2009 version = "0.53.1" 952 2010 source = "registry+https://github.com/rust-lang/crates.io-index" 953 2011 checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 2012 + 2013 + [[package]] 2014 + name = "wit-bindgen" 2015 + version = "0.46.0" 2016 + source = "registry+https://github.com/rust-lang/crates.io-index" 2017 + checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 2018 + 2019 + [[package]] 2020 + name = "writeable" 2021 + version = "0.6.2" 2022 + source = "registry+https://github.com/rust-lang/crates.io-index" 2023 + checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 2024 + 2025 + [[package]] 2026 + name = "yoke" 2027 + version = "0.8.1" 2028 + source = "registry+https://github.com/rust-lang/crates.io-index" 2029 + checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" 2030 + dependencies = [ 2031 + "stable_deref_trait", 2032 + "yoke-derive", 2033 + "zerofrom", 2034 + ] 2035 + 2036 + [[package]] 2037 + name = "yoke-derive" 2038 + version = "0.8.1" 2039 + source = "registry+https://github.com/rust-lang/crates.io-index" 2040 + checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" 2041 + dependencies = [ 2042 + "proc-macro2", 2043 + "quote", 2044 + "syn", 2045 + "synstructure", 2046 + ] 2047 + 2048 + [[package]] 2049 + name = "zerocopy" 2050 + version = "0.8.31" 2051 + source = "registry+https://github.com/rust-lang/crates.io-index" 2052 + checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" 2053 + dependencies = [ 2054 + "zerocopy-derive", 2055 + ] 2056 + 2057 + [[package]] 2058 + name = "zerocopy-derive" 2059 + version = "0.8.31" 2060 + source = "registry+https://github.com/rust-lang/crates.io-index" 2061 + checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" 2062 + dependencies = [ 2063 + "proc-macro2", 2064 + "quote", 2065 + "syn", 2066 + ] 2067 + 2068 + [[package]] 2069 + name = "zerofrom" 2070 + version = "0.1.6" 2071 + source = "registry+https://github.com/rust-lang/crates.io-index" 2072 + checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2073 + dependencies = [ 2074 + "zerofrom-derive", 2075 + ] 2076 + 2077 + [[package]] 2078 + name = "zerofrom-derive" 2079 + version = "0.1.6" 2080 + source = "registry+https://github.com/rust-lang/crates.io-index" 2081 + checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2082 + dependencies = [ 2083 + "proc-macro2", 2084 + "quote", 2085 + "syn", 2086 + "synstructure", 2087 + ] 2088 + 2089 + [[package]] 2090 + name = "zeroize" 2091 + version = "1.8.2" 2092 + source = "registry+https://github.com/rust-lang/crates.io-index" 2093 + checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" 2094 + 2095 + [[package]] 2096 + name = "zerotrie" 2097 + version = "0.2.3" 2098 + source = "registry+https://github.com/rust-lang/crates.io-index" 2099 + checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" 2100 + dependencies = [ 2101 + "displaydoc", 2102 + "yoke", 2103 + "zerofrom", 2104 + ] 2105 + 2106 + [[package]] 2107 + name = "zerovec" 2108 + version = "0.11.5" 2109 + source = "registry+https://github.com/rust-lang/crates.io-index" 2110 + checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" 2111 + dependencies = [ 2112 + "yoke", 2113 + "zerofrom", 2114 + "zerovec-derive", 2115 + ] 2116 + 2117 + [[package]] 2118 + name = "zerovec-derive" 2119 + version = "0.11.2" 2120 + source = "registry+https://github.com/rust-lang/crates.io-index" 2121 + checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" 2122 + dependencies = [ 2123 + "proc-macro2", 2124 + "quote", 2125 + "syn", 2126 + ] 954 2127 955 2128 [[package]] 956 2129 name = "zmij"
+10
crates/core/src/model.rs
··· 14 14 pub deck_ref: Option<String>, 15 15 } 16 16 17 + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 18 + pub enum Visibility { 19 + Private, 20 + Unlisted, 21 + Public, 22 + } 23 + 17 24 #[derive(Debug, Clone, Serialize, Deserialize)] 18 25 pub struct Deck { 26 + pub id: String, 27 + pub owner_did: String, 19 28 pub title: String, 20 29 pub description: String, 21 30 pub tags: Vec<String>, 31 + pub visibility: Visibility, 22 32 }
+3
crates/server/Cargo.toml
··· 6 6 [dependencies] 7 7 axum = "0.8.8" 8 8 malfestio-core = { version = "0.1.0", path = "../core" } 9 + reqwest = { version = "0.12.28", features = ["json"] } 9 10 serde = "1.0.228" 10 11 serde_json = "1.0.148" 11 12 tokio = { version = "1.48.0", features = ["full"] } 12 13 tower = "0.5.2" 14 + tower-cookies = "0.11.0" 13 15 tower-http = { version = "0.6.8", features = ["cors", "trace"] } 14 16 tracing = "0.1.44" 15 17 tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } 18 + uuid = { version = "1.19.0", features = ["v4", "fast-rng"] }
+67
crates/server/src/api/auth.rs
··· 1 + use axum::{Json, http::StatusCode, response::IntoResponse}; 2 + 3 + use serde::{Deserialize, Serialize}; 4 + use serde_json::json; 5 + 6 + #[derive(Deserialize)] 7 + pub struct LoginRequest { 8 + identifier: String, 9 + password: String, 10 + } 11 + 12 + #[derive(Serialize)] 13 + pub struct LoginResponse { 14 + access_jwt: String, 15 + refresh_jwt: String, 16 + did: String, 17 + handle: String, 18 + } 19 + 20 + /// TODO: Make PDS URL configurable 21 + pub async fn login(Json(payload): Json<LoginRequest>) -> impl IntoResponse { 22 + let client = reqwest::Client::new(); 23 + let pds_url = "https://bsky.social"; 24 + 25 + let resp = client 26 + .post(format!("{}/xrpc/com.atproto.server.createSession", pds_url)) 27 + .json(&json!({ 28 + "identifier": payload.identifier, 29 + "password": payload.password 30 + })) 31 + .send() 32 + .await; 33 + 34 + match resp { 35 + Ok(response) => { 36 + if response.status().is_success() { 37 + let body: serde_json::Value = response.json().await.unwrap_or_default(); 38 + let access_jwt = body["accessJwt"].as_str().unwrap_or("").to_string(); 39 + let refresh_jwt = body["refreshJwt"].as_str().unwrap_or("").to_string(); 40 + let did = body["did"].as_str().unwrap_or("").to_string(); 41 + let handle = body["handle"].as_str().unwrap_or("").to_string(); 42 + 43 + ( 44 + StatusCode::OK, 45 + Json(json!({ 46 + "accessJwt": access_jwt, 47 + "refreshJwt": refresh_jwt, 48 + "did": did, 49 + "handle": handle 50 + })), 51 + ) 52 + } else { 53 + let error_body: serde_json::Value = response.json().await.unwrap_or_default(); 54 + (StatusCode::UNAUTHORIZED, Json(error_body)) 55 + } 56 + } 57 + Err(e) => ( 58 + StatusCode::INTERNAL_SERVER_ERROR, 59 + Json(json!({ "error": e.to_string() })), 60 + ), 61 + } 62 + } 63 + 64 + /// TODO: replace with middleware 65 + pub async fn me() -> impl IntoResponse { 66 + Json(json!({ "status": "authenticated" })) 67 + }
+94
crates/server/src/api/deck.rs
··· 1 + use crate::middleware::auth::UserContext; 2 + 3 + use axum::{ 4 + Json, 5 + extract::{Extension, Path, State}, 6 + http::StatusCode, 7 + response::IntoResponse, 8 + }; 9 + use malfestio_core::model::{Deck, Visibility}; 10 + use serde::Deserialize; 11 + use serde_json::json; 12 + use std::sync::{Arc, RwLock}; 13 + 14 + type Db = Arc<RwLock<Vec<Deck>>>; 15 + 16 + #[derive(Deserialize)] 17 + pub struct CreateDeckRequest { 18 + title: String, 19 + description: String, 20 + tags: Vec<String>, 21 + visibility: Visibility, 22 + } 23 + 24 + pub fn init_db() -> Db { 25 + Arc::new(RwLock::new(Vec::new())) 26 + } 27 + 28 + pub async fn create_deck( 29 + State(db): State<Db>, ctx: Option<axum::Extension<UserContext>>, Json(payload): Json<CreateDeckRequest>, 30 + ) -> impl IntoResponse { 31 + let user = match ctx { 32 + Some(axum::Extension(user)) => user, 33 + None => return (StatusCode::UNAUTHORIZED, Json(json!({"error": "Unauthorized"}))).into_response(), 34 + }; 35 + 36 + let new_deck = Deck { 37 + id: uuid::Uuid::new_v4().to_string(), 38 + owner_did: user.did, 39 + title: payload.title, 40 + description: payload.description, 41 + tags: payload.tags, 42 + visibility: payload.visibility, 43 + }; 44 + 45 + db.write().unwrap().push(new_deck.clone()); 46 + 47 + (StatusCode::CREATED, Json(new_deck)).into_response() 48 + } 49 + 50 + pub async fn list_decks(State(db): State<Db>, ctx: Option<axum::Extension<UserContext>>) -> impl IntoResponse { 51 + let user_did = ctx.map(|Extension(u)| u.did); 52 + 53 + let decks = db.read().unwrap(); 54 + 55 + let visible_decks: Vec<Deck> = decks 56 + .iter() 57 + .filter(|d| { 58 + if let Some(did) = &user_did 59 + && &d.owner_did == did 60 + { 61 + return true; 62 + } 63 + if d.visibility == Visibility::Public { 64 + return true; 65 + } 66 + false 67 + }) 68 + .cloned() 69 + .collect(); 70 + 71 + Json(visible_decks).into_response() 72 + } 73 + 74 + pub async fn get_deck( 75 + State(db): State<Db>, ctx: Option<axum::Extension<UserContext>>, Path(id): Path<String>, 76 + ) -> impl IntoResponse { 77 + let user_did = ctx.map(|Extension(u)| u.did); 78 + let decks = db.read().unwrap(); 79 + 80 + if let Some(deck) = decks.iter().find(|d| d.id == id) { 81 + let is_owner = user_did.as_ref() == Some(&deck.owner_did); 82 + 83 + if deck.visibility == Visibility::Public || is_owner { 84 + return Json(deck).into_response(); 85 + } 86 + 87 + if deck.visibility == Visibility::Unlisted { 88 + return Json(deck).into_response(); 89 + } 90 + return (StatusCode::FORBIDDEN, Json(json!({"error": "Access denied"}))).into_response(); 91 + } 92 + 93 + (StatusCode::NOT_FOUND, Json(json!({"error": "Deck not found"}))).into_response() 94 + }
+2
crates/server/src/api/mod.rs
··· 1 + pub mod auth; 2 + pub mod deck;
+27 -2
crates/server/src/lib.rs
··· 1 + pub mod api; 2 + pub mod middleware; 3 + 4 + use axum::http::Method; 1 5 use axum::{ 2 6 Json, Router, 3 7 http::StatusCode, 8 + middleware as axum_middleware, 4 9 response::{IntoResponse, Response}, 5 - routing::get, 10 + routing::{get, post}, 6 11 }; 7 12 use serde_json::json; 8 13 use std::net::SocketAddr; 9 14 use tokio::net::TcpListener; 15 + use tower_http::cors::{Any, CorsLayer}; 10 16 use tower_http::trace::TraceLayer; 11 17 use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; 12 18 ··· 20 26 .init(); 21 27 22 28 tracing::info!("Starting Malfestio Server..."); 29 + 30 + let db = api::deck::init_db(); 31 + 32 + let auth_routes = Router::new() 33 + .route("/me", get(api::auth::me)) 34 + .route("/decks", post(api::deck::create_deck)) 35 + .layer(axum_middleware::from_fn(middleware::auth::auth_middleware)); 23 36 24 37 let app = Router::new() 25 38 .route("/health", get(health_check)) 26 - .layer(TraceLayer::new_for_http()); 39 + .route("/api/auth/login", post(api::auth::login)) 40 + .route("/api/decks", get(api::deck::list_decks)) 41 + .route("/api/decks/{id}", get(api::deck::get_deck)) 42 + .nest("/api", auth_routes) 43 + .layer(TraceLayer::new_for_http()) 44 + .layer( 45 + CorsLayer::new() 46 + .allow_origin(Any) 47 + .allow_methods([Method::GET, Method::POST, Method::OPTIONS]) 48 + .allow_headers(Any), 49 + ) 50 + .with_state(db); 51 + 27 52 let addr = SocketAddr::from(([127, 0, 0, 1], 8080)); 28 53 29 54 tracing::info!("Listening on {}", addr);
+55
crates/server/src/middleware/auth.rs
··· 1 + use axum::response::IntoResponse; 2 + use axum::{ 3 + extract::Request, 4 + http::{self, StatusCode}, 5 + middleware::Next, 6 + response::Response, 7 + }; 8 + use serde_json::json; 9 + 10 + #[derive(Clone, Debug)] 11 + pub struct UserContext { 12 + pub did: String, 13 + pub handle: String, 14 + } 15 + 16 + /// TODO: Cache this or use signature verification for performance 17 + pub async fn auth_middleware(mut req: Request, next: Next) -> Response { 18 + let auth_header = req.headers().get(http::header::AUTHORIZATION); 19 + 20 + let token = match auth_header.and_then(|h| h.to_str().ok()) { 21 + Some(header_val) if header_val.starts_with("Bearer ") => &header_val[7..], 22 + _ => { 23 + return ( 24 + StatusCode::UNAUTHORIZED, 25 + axum::Json(json!({ "error": "Missing or invalid Authorization header" })), 26 + ) 27 + .into_response(); 28 + } 29 + }; 30 + 31 + let client = reqwest::Client::new(); 32 + let pds_url = "https://bsky.social"; 33 + 34 + let resp = client 35 + .get(format!("{}/xrpc/com.atproto.server.getSession", pds_url)) 36 + .header("Authorization", format!("Bearer {}", token)) 37 + .send() 38 + .await; 39 + 40 + match resp { 41 + Ok(response) if response.status().is_success() => { 42 + let body: serde_json::Value = response.json().await.unwrap_or_default(); 43 + let did = body["did"].as_str().unwrap_or("").to_string(); 44 + let handle = body["handle"].as_str().unwrap_or("").to_string(); 45 + 46 + req.extensions_mut().insert(UserContext { did, handle }); 47 + next.run(req).await 48 + } 49 + _ => ( 50 + StatusCode::UNAUTHORIZED, 51 + axum::Json(json!({ "error": "Invalid session" })), 52 + ) 53 + .into_response(), 54 + } 55 + }
+1
crates/server/src/middleware/mod.rs
··· 1 + pub mod auth;
+1 -1
web/eslint.config.js
··· 5 5 export default [js.configs.recommended, { 6 6 files: ["**/*.{ts,tsx}"], 7 7 ...solid, 8 - languageOptions: { parser: tsParser, parserOptions: { project: "./tsconfig.app.json" } }, 8 + languageOptions: { parser: tsParser, parserOptions: { project: "./tsconfig.app.json" }, globals: globals.browser }, 9 9 }];
+1 -1
web/index.html
··· 3 3 4 4 <head> 5 5 <meta charset="UTF-8" /> 6 - <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 6 + <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> 7 7 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 8 8 <title>Malfestio</title> 9 9 </head>
+1
web/package.json
··· 25 25 "@typescript-eslint/parser": "^8.50.1", 26 26 "eslint": "^9.39.2", 27 27 "eslint-plugin-solid": "^0.14.5", 28 + "globals": "^16.5.0", 28 29 "jsdom": "^27.4.0", 29 30 "typescript": "~5.9.3", 30 31 "vite": "npm:rolldown-vite@7.2.5",
+9
web/pnpm-lock.yaml
··· 48 48 eslint-plugin-solid: 49 49 specifier: ^0.14.5 50 50 version: 0.14.5(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 51 + globals: 52 + specifier: ^16.5.0 53 + version: 16.5.0 51 54 jsdom: 52 55 specifier: ^27.4.0 53 56 version: 27.4.0 ··· 893 896 894 897 globals@14.0.0: 895 898 resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} 899 + engines: {node: '>=18'} 900 + 901 + globals@16.5.0: 902 + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} 896 903 engines: {node: '>=18'} 897 904 898 905 graceful-fs@4.2.11: ··· 2336 2343 is-glob: 4.0.3 2337 2344 2338 2345 globals@14.0.0: {} 2346 + 2347 + globals@16.5.0: {} 2339 2348 2340 2349 graceful-fs@4.2.11: {} 2341 2350
+3
web/public/favicon.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" viewBox="0 0 24 24"> 2 + <path fill="#2859c5" d="M12 14.327q2.394 0 4.197-1.445T18 9.173q0-.959-.348-1.795t-.975-1.474q-1.735.108-2.956 1.296Q12.5 8.389 12.5 10.116h-1q0-1.727-1.23-2.92Q9.038 6.004 7.294 5.93q-.599.638-.947 1.461T6 9.173q0 2.264 1.803 3.709T12 14.327M8.75 9.904q-.31 0-.52-.21t-.21-.52t.21-.521t.52-.21t.52.21t.21.52t-.21.52q-.209.21-.52.21m6.5 0q-.31 0-.52-.209q-.21-.21-.21-.52t.21-.521q.209-.21.52-.21t.52.21q.21.209.21.52q0 .31-.21.52q-.209.21-.52.21M12 21q-2.931 0-4.966-2.084Q5 16.83 5 13.885V9.173q0-2.69 2.092-4.431T12 3q2.68 0 4.84 1.696T19 9.173V20h-1q-1.558 0-2.664-1.106t-1.105-2.663v-1.212q-.25.074-.5.122l-.5.095v1q0 1.974 1.395 3.369T18 21z" /> 3 + </svg>
-1
web/public/vite.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
+2
web/src/App.tsx
··· 2 2 import type { Component } from "solid-js"; 3 3 import { AppLayout } from "./components/layout/AppLayout"; 4 4 import Home from "./pages/Home"; 5 + import Login from "./pages/Login"; 5 6 6 7 const App: Component = () => { 7 8 return ( 8 9 <Router root={AppLayout}> 9 10 <Route path="/" component={Home} /> 11 + <Route path="/login" component={Login} /> 10 12 </Router> 11 13 ); 12 14 };
+21 -3
web/src/components/layout/Header.tsx
··· 1 1 import { A } from "@solidjs/router"; 2 - import type { Component } from "solid-js"; 2 + import { type Component, Show } from "solid-js"; 3 + import { authStore } from "../../lib/store"; 4 + 5 + const Login: Component = () => ( 6 + <A href="/login" class="px-4 py-2 bg-white text-gray-900 text-sm font-medium hover:bg-gray-100 transition-colors"> 7 + Login 8 + </A> 9 + ); 3 10 4 11 export const Header: Component = () => { 5 12 return ( ··· 12 19 </nav> 13 20 </div> 14 21 <div class="flex items-center gap-4"> 15 - {/* Placeholder for Auth/User menu */} 16 - <div class="w-8 h-8 rounded-full bg-gray-700" /> 22 + <Show when={authStore.user()} fallback={<Login />}> 23 + <div class="flex items-center gap-3"> 24 + <span class="text-xs text-gray-400">{authStore.user()?.handle}</span> 25 + <button 26 + onClick={() => authStore.logout()} 27 + class="text-xs text-red-400 hover:text-red-300 transition-colors"> 28 + Logout 29 + </button> 30 + <div class="w-8 h-8 rounded-full bg-blue-900/50 border border-blue-500/30 flex items-center justify-center text-blue-400 text-xs font-bold"> 31 + {authStore.user()?.handle.slice(0, 2).toUpperCase()} 32 + </div> 33 + </div> 34 + </Show> 17 35 </div> 18 36 </header> 19 37 );
+30
web/src/lib/api.ts
··· 1 + import { authStore } from "./store"; 2 + 3 + const API_BASE = "http://localhost:8080/api"; 4 + 5 + export async function apiFetch(path: string, options: RequestInit = {}) { 6 + const token = authStore.accessJwt(); 7 + 8 + const headers = new Headers(options.headers); 9 + if (token) { 10 + headers.set("Authorization", `Bearer ${token}`); 11 + } 12 + 13 + if (options.body && typeof options.body === "string" && !headers.has("Content-Type")) { 14 + headers.set("Content-Type", "application/json"); 15 + } 16 + 17 + const response = await fetch(`${API_BASE}${path}`, { ...options, headers }); 18 + 19 + if (response.status === 401) { 20 + authStore.logout(); 21 + window.location.href = "/login"; 22 + } 23 + 24 + return response; 25 + } 26 + 27 + export const api = { 28 + get: (path: string) => apiFetch(path, { method: "GET" }), 29 + post: (path: string, body: any) => apiFetch(path, { method: "POST", body: JSON.stringify(body) }), 30 + };
+38
web/src/lib/store.ts
··· 1 + import { createRoot, createSignal } from "solid-js"; 2 + 3 + export type User = { did: string; handle: string }; 4 + 5 + export type AuthState = { 6 + user: User | null; 7 + accessJwt: string | null; 8 + refreshJwt: string | null; 9 + isAuthenticated: boolean; 10 + }; 11 + 12 + function createAuthStore() { 13 + const [user, setUser] = createSignal<User | null>(null); 14 + const [accessJwt, setAccessJwt] = createSignal<string | null>(localStorage.getItem("accessJwt")); 15 + const [_refreshJwt, setRefreshJwt] = createSignal<string | null>(localStorage.getItem("refreshJwt")); 16 + 17 + const login = (data: { accessJwt: string; refreshJwt: string; did: string; handle: string }) => { 18 + setAccessJwt(data.accessJwt); 19 + setRefreshJwt(data.refreshJwt); 20 + setUser({ did: data.did, handle: data.handle }); 21 + 22 + localStorage.setItem("accessJwt", data.accessJwt); 23 + localStorage.setItem("refreshJwt", data.refreshJwt); 24 + localStorage.setItem("did", data.did); 25 + localStorage.setItem("handle", data.handle); 26 + }; 27 + 28 + const logout = () => { 29 + setUser(null); 30 + setAccessJwt(null); 31 + setRefreshJwt(null); 32 + localStorage.clear(); 33 + }; 34 + 35 + return { user, accessJwt, isAuthenticated: () => !!accessJwt(), login, logout }; 36 + } 37 + 38 + export const authStore = createRoot(createAuthStore);
+89 -28
web/src/pages/Home.tsx
··· 1 + import { A } from "@solidjs/router"; 1 2 import type { Component } from "solid-js"; 2 - import { Button } from "../components/ui/Button"; 3 - import { Card } from "../components/ui/Card"; 3 + import { createResource, For, Show } from "solid-js"; 4 + import { api } from "../lib/api"; 5 + 6 + type DeckVisibility = "Private" | "Unlisted" | "Public"; 7 + 8 + type Deck = { 9 + id: string; 10 + title: string; 11 + description: string; 12 + tags: string[]; 13 + visibility: DeckVisibility; 14 + owner_did: string; 15 + }; 16 + 17 + const fetchDecks = async (): Promise<Deck[]> => { 18 + const res = await api.get("/decks"); 19 + if (!res.ok) return []; 20 + return res.json(); 21 + }; 22 + 23 + const DeckCard: Component<{ deck: Deck }> = (props) => { 24 + return ( 25 + <div class="bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 p-4 hover:border-blue-500 transition-colors group relative"> 26 + <div class="flex justify-between items-start mb-2"> 27 + <h3 class="text-lg font-normal text-neutral-900 dark:text-gray-100 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors"> 28 + {props.deck.title} 29 + </h3> 30 + <Show when={props.deck.visibility !== "Public"}> 31 + <span class="text-[10px] uppercase font-bold tracking-widest px-2 py-0.5 bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-400"> 32 + {props.deck.visibility} 33 + </span> 34 + </Show> 35 + </div> 36 + <p class="text-sm text-neutral-500 dark:text-neutral-400 mb-6 line-clamp-2 min-h-[2.5em] font-light"> 37 + {props.deck.description} 38 + </p> 39 + 40 + <div class="flex items-center gap-2 mb-4 flex-wrap"> 41 + <For each={props.deck.tags}> 42 + {(tag) => ( 43 + <span class="text-xs text-neutral-500 dark:text-neutral-400 bg-neutral-50 dark:bg-neutral-900/50 px-2 py-0.5 border border-neutral-100 dark:border-neutral-800"> 44 + #{tag} 45 + </span> 46 + )} 47 + </For> 48 + </div> 49 + 50 + <div class="flex justify-end pt-4 border-t border-neutral-100 dark:border-neutral-800"> 51 + <A 52 + href={`/decks/${props.deck.id}`} 53 + class="text-sm font-medium text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300"> 54 + View Deck → 55 + </A> 56 + </div> 57 + </div> 58 + ); 59 + }; 4 60 5 61 const Home: Component = () => { 62 + const [decks] = createResource(fetchDecks); 63 + 6 64 return ( 7 - <div class="space-y-8"> 8 - <section class="text-center py-16 space-y-6"> 9 - <h1 class="text-5xl font-extrabold tracking-tight text-white sm:text-6xl bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-emerald-400"> 10 - Learn Together 11 - </h1> 12 - <p class="text-xl text-gray-400 max-w-2xl mx-auto"> 13 - Malfestio is a social learning platform built on the AT Protocol. 14 - </p> 15 - <div class="flex items-center justify-center gap-4 pt-4"> 16 - <Button size="lg" variant="primary">Get Started</Button> 17 - <Button size="lg" variant="ghost">Learn More</Button> 65 + <div class="max-w-7xl mx-auto px-6 py-12"> 66 + <div class="flex justify-between items-end mb-12 border-b border-neutral-200 dark:border-neutral-800 pb-4"> 67 + <div> 68 + <h1 class="text-4xl font-light text-neutral-900 dark:text-white tracking-tight mb-2">Library</h1> 69 + <p class="text-neutral-500 dark:text-neutral-400 font-light"> 70 + Manage your study decks and discover new content. 71 + </p> 18 72 </div> 19 - </section> 73 + <button class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 font-medium text-sm transition-colors flex items-center gap-2 shadow-sm"> 74 + <span>+</span> Create Deck 75 + </button> 76 + </div> 20 77 21 - <section class="grid grid-cols-1 md:grid-cols-3 gap-6"> 22 - <Card title="Decks"> 23 - <p class="mb-4">Create and manage your flashcard decks. Import from articles and lectures.</p> 24 - <Button variant="secondary" size="sm">View Decks</Button> 25 - </Card> 26 - <Card title="Review"> 27 - <p class="mb-4">Daily review sessions optimized by the SM-2 algorithm to maximize retention.</p> 28 - <Button variant="secondary" size="sm">Start Review</Button> 29 - </Card> 30 - <Card title="Community"> 31 - <p class="mb-4">Discover shared decks and follow other learners in the network.</p> 32 - <Button variant="secondary" size="sm">Explore</Button> 33 - </Card> 34 - </section> 78 + <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> 79 + <Show when={decks.loading}> 80 + <div class="col-span-full h-32 flex items-center justify-center text-neutral-400 font-light"> 81 + Loading library... 82 + </div> 83 + </Show> 84 + 85 + <Show when={!decks.loading && decks()?.length === 0}> 86 + <div class="col-span-full py-16 text-center border border-dashed border-neutral-300 dark:border-neutral-700 bg-neutral-50 dark:bg-neutral-900/30"> 87 + <h3 class="text-lg font-medium text-neutral-900 dark:text-gray-100 mb-2">No decks found</h3> 88 + <p class="text-sm text-neutral-500 max-w-sm mx-auto font-light"> 89 + Create your first deck to get started with spaced repetition learning. 90 + </p> 91 + </div> 92 + </Show> 93 + 94 + <For each={decks()}>{(deck) => <DeckCard deck={deck} />}</For> 95 + </div> 35 96 </div> 36 97 ); 37 98 };
+90
web/src/pages/Login.tsx
··· 1 + import { useNavigate } from "@solidjs/router"; 2 + import type { Component } from "solid-js"; 3 + import { createSignal } from "solid-js"; 4 + import { api } from "../lib/api"; 5 + import { authStore } from "../lib/store"; 6 + 7 + const Login: Component = () => { 8 + const [identifier, setIdentifier] = createSignal(""); 9 + const [password, setPassword] = createSignal(""); 10 + const [error, setError] = createSignal(""); 11 + const [isLoading, setIsLoading] = createSignal(false); 12 + const navigate = useNavigate(); 13 + 14 + const handleLogin = async (e: Event) => { 15 + e.preventDefault(); 16 + setIsLoading(true); 17 + setError(""); 18 + 19 + try { 20 + const response = await api.post("/auth/login", { identifier: identifier(), password: password() }); 21 + 22 + if (response.ok) { 23 + const data = await response.json(); 24 + authStore.login(data); 25 + navigate("/"); 26 + } else { 27 + const err = await response.json(); 28 + setError(err.error || "Login failed"); 29 + } 30 + } catch { 31 + setError("Network error or server unreachable"); 32 + } finally { 33 + setIsLoading(false); 34 + } 35 + }; 36 + 37 + return ( 38 + <div class="min-h-[calc(100vh-4rem)] flex items-center justify-center bg-neutral-100 dark:bg-black p-4"> 39 + <div class="w-full max-w-md bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 p-8 shadow-sm"> 40 + <h1 class="text-3xl font-light text-neutral-900 dark:text-white mb-8 tracking-tight">Login</h1> 41 + 42 + <form onSubmit={handleLogin} class="space-y-6"> 43 + {error() && ( 44 + <div class="bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 text-sm p-4 border border-red-200 dark:border-red-900/50"> 45 + {error()} 46 + </div> 47 + )} 48 + 49 + <div class="space-y-2"> 50 + <label class="block text-xs font-semibold text-neutral-500 uppercase tracking-wider">Handle</label> 51 + <input 52 + type="text" 53 + value={identifier()} 54 + onInput={(e) => setIdentifier(e.currentTarget.value)} 55 + class="w-full bg-neutral-100 dark:bg-neutral-800 border-b border-neutral-400 dark:border-neutral-600 focus:border-blue-500 focus:outline-none p-3 transition-colors text-neutral-900 dark:text-white rounded-t-sm" 56 + placeholder="user.bsky.social" 57 + required /> 58 + </div> 59 + 60 + <div class="space-y-2"> 61 + <label class="block text-xs font-semibold text-neutral-500 uppercase tracking-wider">App Password</label> 62 + <input 63 + type="password" 64 + value={password()} 65 + onInput={(e) => setPassword(e.currentTarget.value)} 66 + class="w-full bg-neutral-100 dark:bg-neutral-800 border-b border-neutral-400 dark:border-neutral-600 focus:border-blue-500 focus:outline-none p-3 transition-colors text-neutral-900 dark:text-white rounded-t-sm" 67 + placeholder="••••••••" 68 + required /> 69 + </div> 70 + 71 + <div class="pt-4"> 72 + <button 73 + type="submit" 74 + disabled={isLoading()} 75 + class="w-full bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 hover:bg-neutral-800 dark:hover:bg-neutral-100 py-4 font-medium text-sm text-left px-6 flex justify-between items-center transition-colors disabled:opacity-50 disabled:cursor-not-allowed"> 76 + {isLoading() ? "Authenticating..." : "Continue"} 77 + <span class="text-lg">→</span> 78 + </button> 79 + </div> 80 + </form> 81 + 82 + <div class="mt-8 text-xs text-neutral-500 dark:text-neutral-400"> 83 + <p class="mt-2">Use your BlueSky App Password, not your main password.</p> 84 + </div> 85 + </div> 86 + </div> 87 + ); 88 + }; 89 + 90 + export default Login;