Parakeet is a Rust-based Bluesky AppServer aiming to implement most of the functionality required to support the Bluesky client
appview atproto bluesky rust appserver

feat: drop did-resolver for jacquard-identity

mia.omg.lol f425b837 e5c177d3

verified
+924 -415
+794 -55
Cargo.lock
··· 3 3 version = 4 4 4 5 5 [[package]] 6 + name = "abnf" 7 + version = "0.13.0" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "087113bd50d9adce24850eed5d0476c7d199d532fce8fab5173650331e09033a" 10 + dependencies = [ 11 + "abnf-core", 12 + "nom", 13 + ] 14 + 15 + [[package]] 16 + name = "abnf-core" 17 + version = "0.5.0" 18 + source = "registry+https://github.com/rust-lang/crates.io-index" 19 + checksum = "c44e09c43ae1c368fb91a03a566472d0087c26cf7e1b9e8e289c14ede681dd7d" 20 + dependencies = [ 21 + "nom", 22 + ] 23 + 24 + [[package]] 25 + name = "adler2" 26 + version = "2.0.1" 27 + source = "registry+https://github.com/rust-lang/crates.io-index" 28 + checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 29 + 30 + [[package]] 6 31 name = "ahash" 7 32 version = "0.8.12" 8 33 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 24 49 ] 25 50 26 51 [[package]] 52 + name = "aliasable" 53 + version = "0.1.3" 54 + source = "registry+https://github.com/rust-lang/crates.io-index" 55 + checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" 56 + 57 + [[package]] 27 58 name = "alloc-no-stdlib" 28 59 version = "2.0.4" 29 60 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 123 154 dependencies = [ 124 155 "proc-macro2", 125 156 "quote", 126 - "syn", 157 + "syn 2.0.114", 127 158 ] 128 159 129 160 [[package]] ··· 134 165 dependencies = [ 135 166 "proc-macro2", 136 167 "quote", 137 - "syn", 168 + "syn 2.0.114", 138 169 ] 139 170 140 171 [[package]] ··· 144 175 checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" 145 176 dependencies = [ 146 177 "bytemuck", 178 + ] 179 + 180 + [[package]] 181 + name = "atomic-polyfill" 182 + version = "1.0.3" 183 + source = "registry+https://github.com/rust-lang/crates.io-index" 184 + checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" 185 + dependencies = [ 186 + "critical-section", 147 187 ] 148 188 149 189 [[package]] ··· 326 366 "regex", 327 367 "rustc-hash", 328 368 "shlex", 329 - "syn", 369 + "syn 2.0.114", 330 370 ] 331 371 332 372 [[package]] ··· 351 391 ] 352 392 353 393 [[package]] 394 + name = "bon" 395 + version = "3.8.2" 396 + source = "registry+https://github.com/rust-lang/crates.io-index" 397 + checksum = "234655ec178edd82b891e262ea7cf71f6584bcd09eff94db786be23f1821825c" 398 + dependencies = [ 399 + "bon-macros", 400 + "rustversion", 401 + ] 402 + 403 + [[package]] 404 + name = "bon-macros" 405 + version = "3.8.2" 406 + source = "registry+https://github.com/rust-lang/crates.io-index" 407 + checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365" 408 + dependencies = [ 409 + "darling", 410 + "ident_case", 411 + "prettyplease", 412 + "proc-macro2", 413 + "quote", 414 + "rustversion", 415 + "syn 2.0.114", 416 + ] 417 + 418 + [[package]] 419 + name = "borsh" 420 + version = "1.6.0" 421 + source = "registry+https://github.com/rust-lang/crates.io-index" 422 + checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" 423 + dependencies = [ 424 + "cfg_aliases", 425 + ] 426 + 427 + [[package]] 354 428 name = "brotli" 355 429 version = "8.0.2" 356 430 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 372 446 ] 373 447 374 448 [[package]] 449 + name = "btree-range-map" 450 + version = "0.7.2" 451 + source = "registry+https://github.com/rust-lang/crates.io-index" 452 + checksum = "1be5c9672446d3800bcbcaabaeba121fe22f1fb25700c4562b22faf76d377c33" 453 + dependencies = [ 454 + "btree-slab", 455 + "cc-traits", 456 + "range-traits", 457 + "serde", 458 + "slab", 459 + ] 460 + 461 + [[package]] 462 + name = "btree-slab" 463 + version = "0.6.1" 464 + source = "registry+https://github.com/rust-lang/crates.io-index" 465 + checksum = "7a2b56d3029f075c4fa892428a098425b86cef5c89ae54073137ece416aef13c" 466 + dependencies = [ 467 + "cc-traits", 468 + "slab", 469 + "smallvec", 470 + ] 471 + 472 + [[package]] 375 473 name = "bumpalo" 376 474 version = "3.19.1" 377 475 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 394 492 version = "1.11.0" 395 493 source = "registry+https://github.com/rust-lang/crates.io-index" 396 494 checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" 495 + dependencies = [ 496 + "serde", 497 + ] 397 498 398 499 [[package]] 399 500 name = "bzip2-sys" ··· 427 528 ] 428 529 429 530 [[package]] 531 + name = "cc-traits" 532 + version = "2.0.0" 533 + source = "registry+https://github.com/rust-lang/crates.io-index" 534 + checksum = "060303ef31ef4a522737e1b1ab68c67916f2a787bb2f4f54f383279adba962b5" 535 + dependencies = [ 536 + "slab", 537 + ] 538 + 539 + [[package]] 430 540 name = "cexpr" 431 541 version = "0.6.0" 432 542 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 541 651 source = "registry+https://github.com/rust-lang/crates.io-index" 542 652 checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" 543 653 dependencies = [ 544 - "heck", 654 + "heck 0.5.0", 545 655 "proc-macro2", 546 656 "quote", 547 - "syn", 657 + "syn 2.0.114", 548 658 ] 549 659 550 660 [[package]] ··· 563 673 ] 564 674 565 675 [[package]] 676 + name = "cobs" 677 + version = "0.3.0" 678 + source = "registry+https://github.com/rust-lang/crates.io-index" 679 + checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" 680 + dependencies = [ 681 + "thiserror 2.0.18", 682 + ] 683 + 684 + [[package]] 566 685 name = "colorchoice" 567 686 version = "1.0.4" 568 687 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 590 709 dependencies = [ 591 710 "brotli", 592 711 "compression-core", 712 + "flate2", 713 + "memchr", 593 714 ] 594 715 595 716 [[package]] ··· 618 739 "ciborium", 619 740 "clap", 620 741 "deadpool-postgres", 621 - "did-resolver", 622 742 "eyre", 623 743 "figment", 624 744 "flume", ··· 626 746 "futures", 627 747 "ipld-core", 628 748 "iroh-car", 749 + "jacquard-common", 750 + "jacquard-identity", 629 751 "lexica", 630 752 "metrics", 631 753 "metrics-exporter-prometheus", ··· 650 772 ] 651 773 652 774 [[package]] 775 + name = "cordyceps" 776 + version = "0.3.4" 777 + source = "registry+https://github.com/rust-lang/crates.io-index" 778 + checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" 779 + dependencies = [ 780 + "loom", 781 + "tracing", 782 + ] 783 + 784 + [[package]] 653 785 name = "core-foundation" 654 786 version = "0.9.4" 655 787 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 703 835 ] 704 836 705 837 [[package]] 838 + name = "critical-section" 839 + version = "1.2.0" 840 + source = "registry+https://github.com/rust-lang/crates.io-index" 841 + checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 842 + 843 + [[package]] 844 + name = "crossbeam-channel" 845 + version = "0.5.15" 846 + source = "registry+https://github.com/rust-lang/crates.io-index" 847 + checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" 848 + dependencies = [ 849 + "crossbeam-utils", 850 + ] 851 + 852 + [[package]] 706 853 name = "crossbeam-epoch" 707 854 version = "0.9.18" 708 855 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 769 916 dependencies = [ 770 917 "proc-macro2", 771 918 "quote", 772 - "syn", 919 + "syn 2.0.114", 773 920 ] 774 921 775 922 [[package]] ··· 793 940 "proc-macro2", 794 941 "quote", 795 942 "strsim", 796 - "syn", 943 + "syn 2.0.114", 797 944 ] 798 945 799 946 [[package]] ··· 804 951 dependencies = [ 805 952 "darling_core", 806 953 "quote", 807 - "syn", 954 + "syn 2.0.114", 955 + ] 956 + 957 + [[package]] 958 + name = "dashmap" 959 + version = "6.1.0" 960 + source = "registry+https://github.com/rust-lang/crates.io-index" 961 + checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" 962 + dependencies = [ 963 + "cfg-if", 964 + "crossbeam-utils", 965 + "hashbrown 0.14.5", 966 + "lock_api", 967 + "once_cell", 968 + "parking_lot_core 0.9.12", 808 969 ] 809 970 810 971 [[package]] ··· 830 991 checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" 831 992 dependencies = [ 832 993 "data-encoding", 833 - "syn", 994 + "syn 2.0.114", 834 995 ] 835 996 836 997 [[package]] ··· 900 1061 ] 901 1062 902 1063 [[package]] 903 - name = "did-resolver" 904 - version = "0.1.0" 1064 + name = "derive_more" 1065 + version = "1.0.0" 1066 + source = "registry+https://github.com/rust-lang/crates.io-index" 1067 + checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" 1068 + dependencies = [ 1069 + "derive_more-impl", 1070 + ] 1071 + 1072 + [[package]] 1073 + name = "derive_more-impl" 1074 + version = "1.0.0" 1075 + source = "registry+https://github.com/rust-lang/crates.io-index" 1076 + checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" 905 1077 dependencies = [ 906 - "hickory-resolver", 907 - "reqwest", 908 - "serde", 909 - "serde_json", 910 - "thiserror 2.0.18", 911 - "tokio", 1078 + "proc-macro2", 1079 + "quote", 1080 + "syn 2.0.114", 1081 + "unicode-xid", 912 1082 ] 1083 + 1084 + [[package]] 1085 + name = "diatomic-waker" 1086 + version = "0.2.3" 1087 + source = "registry+https://github.com/rust-lang/crates.io-index" 1088 + checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c" 913 1089 914 1090 [[package]] 915 1091 name = "diesel" ··· 952 1128 "dsl_auto_type", 953 1129 "proc-macro2", 954 1130 "quote", 955 - "syn", 1131 + "syn 2.0.114", 956 1132 ] 957 1133 958 1134 [[package]] ··· 972 1148 source = "registry+https://github.com/rust-lang/crates.io-index" 973 1149 checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c" 974 1150 dependencies = [ 975 - "syn", 1151 + "syn 2.0.114", 976 1152 ] 977 1153 978 1154 [[package]] ··· 995 1171 dependencies = [ 996 1172 "proc-macro2", 997 1173 "quote", 998 - "syn", 1174 + "syn 2.0.114", 999 1175 ] 1000 1176 1001 1177 [[package]] ··· 1012 1188 dependencies = [ 1013 1189 "darling", 1014 1190 "either", 1015 - "heck", 1191 + "heck 0.5.0", 1016 1192 "proc-macro2", 1017 1193 "quote", 1018 - "syn", 1194 + "syn 2.0.114", 1019 1195 ] 1020 1196 1021 1197 [[package]] ··· 1096 1272 ] 1097 1273 1098 1274 [[package]] 1275 + name = "embedded-io" 1276 + version = "0.4.0" 1277 + source = "registry+https://github.com/rust-lang/crates.io-index" 1278 + checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" 1279 + 1280 + [[package]] 1281 + name = "embedded-io" 1282 + version = "0.6.1" 1283 + source = "registry+https://github.com/rust-lang/crates.io-index" 1284 + checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" 1285 + 1286 + [[package]] 1099 1287 name = "encoding_rs" 1100 1288 version = "0.8.35" 1101 1289 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1110 1298 source = "registry+https://github.com/rust-lang/crates.io-index" 1111 1299 checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" 1112 1300 dependencies = [ 1113 - "heck", 1301 + "heck 0.5.0", 1114 1302 "proc-macro2", 1115 1303 "quote", 1116 - "syn", 1304 + "syn 2.0.114", 1117 1305 ] 1118 1306 1119 1307 [[package]] ··· 1197 1385 checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" 1198 1386 1199 1387 [[package]] 1388 + name = "flate2" 1389 + version = "1.1.8" 1390 + source = "registry+https://github.com/rust-lang/crates.io-index" 1391 + checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" 1392 + dependencies = [ 1393 + "crc32fast", 1394 + "miniz_oxide", 1395 + ] 1396 + 1397 + [[package]] 1200 1398 name = "flume" 1201 1399 version = "0.11.1" 1202 1400 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1205 1403 "futures-core", 1206 1404 "futures-sink", 1207 1405 "nanorand", 1208 - "spin", 1406 + "spin 0.9.8", 1209 1407 ] 1210 1408 1211 1409 [[package]] ··· 1276 1474 ] 1277 1475 1278 1476 [[package]] 1477 + name = "futures-buffered" 1478 + version = "0.2.12" 1479 + source = "registry+https://github.com/rust-lang/crates.io-index" 1480 + checksum = "a8e0e1f38ec07ba4abbde21eed377082f17ccb988be9d988a5adbf4bafc118fd" 1481 + dependencies = [ 1482 + "cordyceps", 1483 + "diatomic-waker", 1484 + "futures-core", 1485 + "pin-project-lite", 1486 + "spin 0.10.0", 1487 + ] 1488 + 1489 + [[package]] 1279 1490 name = "futures-channel" 1280 1491 version = "0.3.31" 1281 1492 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1309 1520 checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 1310 1521 1311 1522 [[package]] 1523 + name = "futures-lite" 1524 + version = "2.6.1" 1525 + source = "registry+https://github.com/rust-lang/crates.io-index" 1526 + checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" 1527 + dependencies = [ 1528 + "fastrand", 1529 + "futures-core", 1530 + "futures-io", 1531 + "parking", 1532 + "pin-project-lite", 1533 + ] 1534 + 1535 + [[package]] 1312 1536 name = "futures-macro" 1313 1537 version = "0.3.31" 1314 1538 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1316 1540 dependencies = [ 1317 1541 "proc-macro2", 1318 1542 "quote", 1319 - "syn", 1543 + "syn 2.0.114", 1320 1544 ] 1321 1545 1322 1546 [[package]] ··· 1356 1580 checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 1357 1581 dependencies = [ 1358 1582 "byteorder", 1583 + ] 1584 + 1585 + [[package]] 1586 + name = "generator" 1587 + version = "0.8.8" 1588 + source = "registry+https://github.com/rust-lang/crates.io-index" 1589 + checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" 1590 + dependencies = [ 1591 + "cc", 1592 + "cfg-if", 1593 + "libc", 1594 + "log", 1595 + "rustversion", 1596 + "windows-link", 1597 + "windows-result", 1359 1598 ] 1360 1599 1361 1600 [[package]] ··· 1444 1683 ] 1445 1684 1446 1685 [[package]] 1686 + name = "hash32" 1687 + version = "0.2.1" 1688 + source = "registry+https://github.com/rust-lang/crates.io-index" 1689 + checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 1690 + dependencies = [ 1691 + "byteorder", 1692 + ] 1693 + 1694 + [[package]] 1447 1695 name = "hashbrown" 1448 1696 version = "0.12.3" 1449 1697 source = "registry+https://github.com/rust-lang/crates.io-index" 1450 1698 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 1699 + 1700 + [[package]] 1701 + name = "hashbrown" 1702 + version = "0.14.5" 1703 + source = "registry+https://github.com/rust-lang/crates.io-index" 1704 + checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 1451 1705 1452 1706 [[package]] 1453 1707 name = "hashbrown" ··· 1489 1743 ] 1490 1744 1491 1745 [[package]] 1746 + name = "heapless" 1747 + version = "0.7.17" 1748 + source = "registry+https://github.com/rust-lang/crates.io-index" 1749 + checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" 1750 + dependencies = [ 1751 + "atomic-polyfill", 1752 + "hash32", 1753 + "rustc_version", 1754 + "serde", 1755 + "spin 0.9.8", 1756 + "stable_deref_trait", 1757 + ] 1758 + 1759 + [[package]] 1760 + name = "heck" 1761 + version = "0.4.1" 1762 + source = "registry+https://github.com/rust-lang/crates.io-index" 1763 + checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 1764 + 1765 + [[package]] 1492 1766 name = "heck" 1493 1767 version = "0.5.0" 1494 1768 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1505 1779 version = "0.4.3" 1506 1780 source = "registry+https://github.com/rust-lang/crates.io-index" 1507 1781 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1782 + 1783 + [[package]] 1784 + name = "hex_fmt" 1785 + version = "0.3.0" 1786 + source = "registry+https://github.com/rust-lang/crates.io-index" 1787 + checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" 1508 1788 1509 1789 [[package]] 1510 1790 name = "hickory-proto" ··· 1652 1932 "tokio", 1653 1933 "tokio-rustls", 1654 1934 "tower-service", 1935 + "webpki-roots", 1655 1936 ] 1656 1937 1657 1938 [[package]] ··· 1871 2152 ] 1872 2153 1873 2154 [[package]] 2155 + name = "indoc" 2156 + version = "2.0.7" 2157 + source = "registry+https://github.com/rust-lang/crates.io-index" 2158 + checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" 2159 + dependencies = [ 2160 + "rustversion", 2161 + ] 2162 + 2163 + [[package]] 1874 2164 name = "inlinable_string" 1875 2165 version = "0.1.15" 1876 2166 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1886 2176 ] 1887 2177 1888 2178 [[package]] 2179 + name = "inventory" 2180 + version = "0.3.21" 2181 + source = "registry+https://github.com/rust-lang/crates.io-index" 2182 + checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" 2183 + dependencies = [ 2184 + "rustversion", 2185 + ] 2186 + 2187 + [[package]] 1889 2188 name = "ipconfig" 1890 2189 version = "0.3.2" 1891 2190 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1971 2270 checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" 1972 2271 1973 2272 [[package]] 2273 + name = "jacquard-api" 2274 + version = "0.9.5" 2275 + source = "registry+https://github.com/rust-lang/crates.io-index" 2276 + checksum = "4979fb1848c1dd7ac8fd12745bc71f56f6da61374407d5f9b06005467a954e5a" 2277 + dependencies = [ 2278 + "bon", 2279 + "bytes", 2280 + "jacquard-common", 2281 + "jacquard-derive", 2282 + "jacquard-lexicon", 2283 + "miette", 2284 + "rustversion", 2285 + "serde", 2286 + "serde_bytes", 2287 + "serde_ipld_dagcbor", 2288 + "thiserror 2.0.18", 2289 + "unicode-segmentation", 2290 + ] 2291 + 2292 + [[package]] 2293 + name = "jacquard-common" 2294 + version = "0.9.5" 2295 + source = "registry+https://github.com/rust-lang/crates.io-index" 2296 + checksum = "1751921e0bdae5e0077afade6161545e9ef7698306c868f800916e99ecbcaae9" 2297 + dependencies = [ 2298 + "base64", 2299 + "bon", 2300 + "bytes", 2301 + "chrono", 2302 + "cid", 2303 + "getrandom 0.2.17", 2304 + "getrandom 0.3.4", 2305 + "http", 2306 + "ipld-core", 2307 + "k256", 2308 + "langtag", 2309 + "miette", 2310 + "multibase", 2311 + "multihash", 2312 + "ouroboros", 2313 + "p256", 2314 + "postcard", 2315 + "rand 0.9.2", 2316 + "regex", 2317 + "regex-lite", 2318 + "reqwest", 2319 + "serde", 2320 + "serde_bytes", 2321 + "serde_html_form", 2322 + "serde_ipld_dagcbor", 2323 + "serde_json", 2324 + "signature", 2325 + "smol_str", 2326 + "thiserror 2.0.18", 2327 + "tokio", 2328 + "tokio-util", 2329 + "trait-variant", 2330 + "url", 2331 + ] 2332 + 2333 + [[package]] 2334 + name = "jacquard-derive" 2335 + version = "0.9.5" 2336 + source = "registry+https://github.com/rust-lang/crates.io-index" 2337 + checksum = "9c8d73dfee07943fdab93569ed1c28b06c6921ed891c08b415c4a323ff67e593" 2338 + dependencies = [ 2339 + "heck 0.5.0", 2340 + "jacquard-lexicon", 2341 + "proc-macro2", 2342 + "quote", 2343 + "syn 2.0.114", 2344 + ] 2345 + 2346 + [[package]] 2347 + name = "jacquard-identity" 2348 + version = "0.9.5" 2349 + source = "registry+https://github.com/rust-lang/crates.io-index" 2350 + checksum = "e7aaefa819fa4213cf59f180dba932f018a7cd0599582fd38474ee2a38c16cf2" 2351 + dependencies = [ 2352 + "bon", 2353 + "bytes", 2354 + "hickory-resolver", 2355 + "http", 2356 + "jacquard-api", 2357 + "jacquard-common", 2358 + "jacquard-lexicon", 2359 + "miette", 2360 + "mini-moka-wasm", 2361 + "n0-future", 2362 + "percent-encoding", 2363 + "reqwest", 2364 + "serde", 2365 + "serde_html_form", 2366 + "serde_json", 2367 + "thiserror 2.0.18", 2368 + "tokio", 2369 + "trait-variant", 2370 + "url", 2371 + "urlencoding", 2372 + ] 2373 + 2374 + [[package]] 2375 + name = "jacquard-lexicon" 2376 + version = "0.9.5" 2377 + source = "registry+https://github.com/rust-lang/crates.io-index" 2378 + checksum = "8411aff546569b0a1e0ef669bed2380cec1c00d48f02f3fcd57a71545321b3d8" 2379 + dependencies = [ 2380 + "cid", 2381 + "dashmap", 2382 + "heck 0.5.0", 2383 + "inventory", 2384 + "jacquard-common", 2385 + "miette", 2386 + "multihash", 2387 + "prettyplease", 2388 + "proc-macro2", 2389 + "quote", 2390 + "serde", 2391 + "serde_ipld_dagcbor", 2392 + "serde_json", 2393 + "serde_repr", 2394 + "serde_with", 2395 + "sha2", 2396 + "syn 2.0.114", 2397 + "thiserror 2.0.18", 2398 + "unicode-segmentation", 2399 + ] 2400 + 2401 + [[package]] 1974 2402 name = "jobserver" 1975 2403 version = "0.1.34" 1976 2404 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2028 2456 ] 2029 2457 2030 2458 [[package]] 2459 + name = "langtag" 2460 + version = "0.4.0" 2461 + source = "registry+https://github.com/rust-lang/crates.io-index" 2462 + checksum = "9ecb4c689a30e48ebeaa14237f34037e300dd072e6ad21a9ec72e810ff3c6600" 2463 + dependencies = [ 2464 + "serde", 2465 + "static-regular-grammar", 2466 + "thiserror 1.0.69", 2467 + ] 2468 + 2469 + [[package]] 2031 2470 name = "lazy_static" 2032 2471 version = "1.5.0" 2033 2472 source = "registry+https://github.com/rust-lang/crates.io-index" 2034 2473 checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 2035 2474 dependencies = [ 2036 - "spin", 2475 + "spin 0.9.8", 2037 2476 ] 2038 2477 2039 2478 [[package]] ··· 2137 2576 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 2138 2577 2139 2578 [[package]] 2579 + name = "loom" 2580 + version = "0.7.2" 2581 + source = "registry+https://github.com/rust-lang/crates.io-index" 2582 + checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" 2583 + dependencies = [ 2584 + "cfg-if", 2585 + "generator", 2586 + "scoped-tls", 2587 + "tracing", 2588 + "tracing-subscriber", 2589 + ] 2590 + 2591 + [[package]] 2140 2592 name = "lru-cache" 2141 2593 version = "0.1.2" 2142 2594 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2169 2621 dependencies = [ 2170 2622 "proc-macro2", 2171 2623 "quote", 2172 - "syn", 2624 + "syn 2.0.114", 2173 2625 ] 2174 2626 2175 2627 [[package]] ··· 2251 2703 ] 2252 2704 2253 2705 [[package]] 2706 + name = "miette" 2707 + version = "7.6.0" 2708 + source = "registry+https://github.com/rust-lang/crates.io-index" 2709 + checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" 2710 + dependencies = [ 2711 + "cfg-if", 2712 + "miette-derive", 2713 + "unicode-width", 2714 + ] 2715 + 2716 + [[package]] 2717 + name = "miette-derive" 2718 + version = "7.6.0" 2719 + source = "registry+https://github.com/rust-lang/crates.io-index" 2720 + checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" 2721 + dependencies = [ 2722 + "proc-macro2", 2723 + "quote", 2724 + "syn 2.0.114", 2725 + ] 2726 + 2727 + [[package]] 2254 2728 name = "migrations_internals" 2255 2729 version = "2.3.0" 2256 2730 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2278 2752 checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 2279 2753 2280 2754 [[package]] 2755 + name = "mini-moka-wasm" 2756 + version = "0.10.99" 2757 + source = "registry+https://github.com/rust-lang/crates.io-index" 2758 + checksum = "0102b9a2ad50fa47ca89eead2316c8222285ecfbd3f69ce99564fbe4253866e8" 2759 + dependencies = [ 2760 + "crossbeam-channel", 2761 + "crossbeam-utils", 2762 + "dashmap", 2763 + "smallvec", 2764 + "tagptr", 2765 + "triomphe", 2766 + "web-time", 2767 + ] 2768 + 2769 + [[package]] 2281 2770 name = "minimal-lexical" 2282 2771 version = "0.2.1" 2283 2772 source = "registry+https://github.com/rust-lang/crates.io-index" 2284 2773 checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 2774 + 2775 + [[package]] 2776 + name = "miniz_oxide" 2777 + version = "0.8.9" 2778 + source = "registry+https://github.com/rust-lang/crates.io-index" 2779 + checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 2780 + dependencies = [ 2781 + "adler2", 2782 + "simd-adler32", 2783 + ] 2285 2784 2286 2785 [[package]] 2287 2786 name = "mio" ··· 2324 2823 checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" 2325 2824 2326 2825 [[package]] 2826 + name = "n0-future" 2827 + version = "0.1.3" 2828 + source = "registry+https://github.com/rust-lang/crates.io-index" 2829 + checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794" 2830 + dependencies = [ 2831 + "cfg_aliases", 2832 + "derive_more", 2833 + "futures-buffered", 2834 + "futures-lite", 2835 + "futures-util", 2836 + "js-sys", 2837 + "pin-project", 2838 + "send_wrapper", 2839 + "tokio", 2840 + "tokio-util", 2841 + "wasm-bindgen", 2842 + "wasm-bindgen-futures", 2843 + "web-time", 2844 + ] 2845 + 2846 + [[package]] 2327 2847 name = "nanorand" 2328 2848 version = "0.7.0" 2329 2849 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2475 2995 dependencies = [ 2476 2996 "proc-macro2", 2477 2997 "quote", 2478 - "syn", 2998 + "syn 2.0.114", 2479 2999 ] 2480 3000 2481 3001 [[package]] ··· 2581 3101 ] 2582 3102 2583 3103 [[package]] 3104 + name = "ouroboros" 3105 + version = "0.18.5" 3106 + source = "registry+https://github.com/rust-lang/crates.io-index" 3107 + checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" 3108 + dependencies = [ 3109 + "aliasable", 3110 + "ouroboros_macro", 3111 + "static_assertions", 3112 + ] 3113 + 3114 + [[package]] 3115 + name = "ouroboros_macro" 3116 + version = "0.18.5" 3117 + source = "registry+https://github.com/rust-lang/crates.io-index" 3118 + checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" 3119 + dependencies = [ 3120 + "heck 0.4.1", 3121 + "proc-macro2", 3122 + "proc-macro2-diagnostics", 3123 + "quote", 3124 + "syn 2.0.114", 3125 + ] 3126 + 3127 + [[package]] 2584 3128 name = "p256" 2585 3129 version = "0.13.2" 2586 3130 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2616 3160 "chrono", 2617 3161 "dataloader", 2618 3162 "deadpool", 2619 - "did-resolver", 2620 3163 "diesel", 2621 3164 "diesel-async", 2622 3165 "diesel_migrations", 2623 3166 "eyre", 2624 3167 "figment", 2625 3168 "itertools 0.14.0", 3169 + "jacquard-common", 3170 + "jacquard-identity", 2626 3171 "jsonwebtoken", 2627 3172 "lexica", 2628 3173 "multibase", ··· 2681 3226 ] 2682 3227 2683 3228 [[package]] 3229 + name = "parking" 3230 + version = "2.2.1" 3231 + source = "registry+https://github.com/rust-lang/crates.io-index" 3232 + checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 3233 + 3234 + [[package]] 2684 3235 name = "parking_lot" 2685 3236 version = "0.11.2" 2686 3237 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2748 3299 "proc-macro2", 2749 3300 "proc-macro2-diagnostics", 2750 3301 "quote", 2751 - "syn", 3302 + "syn 2.0.114", 2752 3303 ] 2753 3304 2754 3305 [[package]] ··· 2823 3374 dependencies = [ 2824 3375 "proc-macro2", 2825 3376 "quote", 2826 - "syn", 3377 + "syn 2.0.114", 2827 3378 ] 2828 3379 2829 3380 [[package]] ··· 2872 3423 checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" 2873 3424 2874 3425 [[package]] 3426 + name = "postcard" 3427 + version = "1.1.3" 3428 + source = "registry+https://github.com/rust-lang/crates.io-index" 3429 + checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" 3430 + dependencies = [ 3431 + "cobs", 3432 + "embedded-io 0.4.0", 3433 + "embedded-io 0.6.1", 3434 + "heapless", 3435 + "serde", 3436 + ] 3437 + 3438 + [[package]] 2875 3439 name = "postgres-protocol" 2876 3440 version = "0.6.10" 2877 3441 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2934 3498 checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" 2935 3499 dependencies = [ 2936 3500 "proc-macro2", 2937 - "syn", 3501 + "syn 2.0.114", 2938 3502 ] 2939 3503 2940 3504 [[package]] ··· 2947 3511 ] 2948 3512 2949 3513 [[package]] 3514 + name = "proc-macro-error" 3515 + version = "1.0.4" 3516 + source = "registry+https://github.com/rust-lang/crates.io-index" 3517 + checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 3518 + dependencies = [ 3519 + "proc-macro-error-attr", 3520 + "proc-macro2", 3521 + "quote", 3522 + "syn 1.0.109", 3523 + "version_check", 3524 + ] 3525 + 3526 + [[package]] 3527 + name = "proc-macro-error-attr" 3528 + version = "1.0.4" 3529 + source = "registry+https://github.com/rust-lang/crates.io-index" 3530 + checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 3531 + dependencies = [ 3532 + "proc-macro2", 3533 + "quote", 3534 + "version_check", 3535 + ] 3536 + 3537 + [[package]] 2950 3538 name = "proc-macro2" 2951 3539 version = "1.0.106" 2952 3540 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2963 3551 dependencies = [ 2964 3552 "proc-macro2", 2965 3553 "quote", 2966 - "syn", 3554 + "syn 2.0.114", 2967 3555 "version_check", 2968 3556 "yansi", 2969 3557 ] ··· 2984 3572 source = "registry+https://github.com/rust-lang/crates.io-index" 2985 3573 checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" 2986 3574 dependencies = [ 2987 - "heck", 3575 + "heck 0.5.0", 2988 3576 "itertools 0.14.0", 2989 3577 "log", 2990 3578 "multimap", ··· 2995 3583 "pulldown-cmark", 2996 3584 "pulldown-cmark-to-cmark", 2997 3585 "regex", 2998 - "syn", 3586 + "syn 2.0.114", 2999 3587 "tempfile", 3000 3588 ] 3001 3589 ··· 3009 3597 "itertools 0.14.0", 3010 3598 "proc-macro2", 3011 3599 "quote", 3012 - "syn", 3600 + "syn 2.0.114", 3013 3601 ] 3014 3602 3015 3603 [[package]] ··· 3195 3783 ] 3196 3784 3197 3785 [[package]] 3786 + name = "range-traits" 3787 + version = "0.3.2" 3788 + source = "registry+https://github.com/rust-lang/crates.io-index" 3789 + checksum = "d20581732dd76fa913c7dff1a2412b714afe3573e94d41c34719de73337cc8ab" 3790 + 3791 + [[package]] 3198 3792 name = "raw-cpuid" 3199 3793 version = "11.6.0" 3200 3794 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3262 3856 dependencies = [ 3263 3857 "proc-macro2", 3264 3858 "quote", 3265 - "syn", 3859 + "syn 2.0.114", 3266 3860 ] 3267 3861 3268 3862 [[package]] ··· 3289 3883 ] 3290 3884 3291 3885 [[package]] 3886 + name = "regex-lite" 3887 + version = "0.1.8" 3888 + source = "registry+https://github.com/rust-lang/crates.io-index" 3889 + checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" 3890 + 3891 + [[package]] 3292 3892 name = "regex-syntax" 3293 3893 version = "0.8.8" 3294 3894 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3340 3940 "wasm-bindgen-futures", 3341 3941 "wasm-streams", 3342 3942 "web-sys", 3943 + "webpki-roots", 3343 3944 ] 3344 3945 3345 3946 [[package]] ··· 3534 4135 ] 3535 4136 3536 4137 [[package]] 4138 + name = "scoped-tls" 4139 + version = "1.0.1" 4140 + source = "registry+https://github.com/rust-lang/crates.io-index" 4141 + checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 4142 + 4143 + [[package]] 3537 4144 name = "scopeguard" 3538 4145 version = "1.2.0" 3539 4146 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3596 4203 checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" 3597 4204 3598 4205 [[package]] 4206 + name = "send_wrapper" 4207 + version = "0.6.0" 4208 + source = "registry+https://github.com/rust-lang/crates.io-index" 4209 + checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" 4210 + 4211 + [[package]] 3599 4212 name = "serde" 3600 4213 version = "1.0.228" 3601 4214 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3632 4245 dependencies = [ 3633 4246 "proc-macro2", 3634 4247 "quote", 3635 - "syn", 4248 + "syn 2.0.114", 3636 4249 ] 3637 4250 3638 4251 [[package]] ··· 3682 4295 "itoa", 3683 4296 "serde", 3684 4297 "serde_core", 4298 + ] 4299 + 4300 + [[package]] 4301 + name = "serde_repr" 4302 + version = "0.1.20" 4303 + source = "registry+https://github.com/rust-lang/crates.io-index" 4304 + checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" 4305 + dependencies = [ 4306 + "proc-macro2", 4307 + "quote", 4308 + "syn 2.0.114", 3685 4309 ] 3686 4310 3687 4311 [[package]] ··· 3742 4366 "darling", 3743 4367 "proc-macro2", 3744 4368 "quote", 3745 - "syn", 4369 + "syn 2.0.114", 3746 4370 ] 3747 4371 3748 4372 [[package]] ··· 3809 4433 ] 3810 4434 3811 4435 [[package]] 4436 + name = "simd-adler32" 4437 + version = "0.3.8" 4438 + source = "registry+https://github.com/rust-lang/crates.io-index" 4439 + checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" 4440 + 4441 + [[package]] 3812 4442 name = "simple_asn1" 3813 4443 version = "0.6.3" 3814 4444 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3861 4491 checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 3862 4492 3863 4493 [[package]] 4494 + name = "smol_str" 4495 + version = "0.3.5" 4496 + source = "registry+https://github.com/rust-lang/crates.io-index" 4497 + checksum = "0f7a918bd2a9951d18ee6e48f076843e8e73a9a5d22cf05bcd4b7a81bdd04e17" 4498 + dependencies = [ 4499 + "borsh", 4500 + "serde_core", 4501 + ] 4502 + 4503 + [[package]] 3864 4504 name = "socket2" 3865 4505 version = "0.5.10" 3866 4506 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3890 4530 ] 3891 4531 3892 4532 [[package]] 4533 + name = "spin" 4534 + version = "0.10.0" 4535 + source = "registry+https://github.com/rust-lang/crates.io-index" 4536 + checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" 4537 + 4538 + [[package]] 3893 4539 name = "spki" 3894 4540 version = "0.7.3" 3895 4541 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3906 4552 checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 3907 4553 3908 4554 [[package]] 4555 + name = "static-regular-grammar" 4556 + version = "2.0.2" 4557 + source = "registry+https://github.com/rust-lang/crates.io-index" 4558 + checksum = "4f4a6c40247579acfbb138c3cd7de3dab113ab4ac6227f1b7de7d626ee667957" 4559 + dependencies = [ 4560 + "abnf", 4561 + "btree-range-map", 4562 + "ciborium", 4563 + "hex_fmt", 4564 + "indoc", 4565 + "proc-macro-error", 4566 + "proc-macro2", 4567 + "quote", 4568 + "serde", 4569 + "sha2", 4570 + "syn 2.0.114", 4571 + "thiserror 1.0.69", 4572 + ] 4573 + 4574 + [[package]] 4575 + name = "static_assertions" 4576 + version = "1.1.0" 4577 + source = "registry+https://github.com/rust-lang/crates.io-index" 4578 + checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 4579 + 4580 + [[package]] 3909 4581 name = "stringprep" 3910 4582 version = "0.1.5" 3911 4583 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3930 4602 3931 4603 [[package]] 3932 4604 name = "syn" 4605 + version = "1.0.109" 4606 + source = "registry+https://github.com/rust-lang/crates.io-index" 4607 + checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 4608 + dependencies = [ 4609 + "proc-macro2", 4610 + "unicode-ident", 4611 + ] 4612 + 4613 + [[package]] 4614 + name = "syn" 3933 4615 version = "2.0.114" 3934 4616 source = "registry+https://github.com/rust-lang/crates.io-index" 3935 4617 checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" ··· 3956 4638 dependencies = [ 3957 4639 "proc-macro2", 3958 4640 "quote", 3959 - "syn", 4641 + "syn 2.0.114", 3960 4642 ] 3961 4643 3962 4644 [[package]] ··· 3981 4663 ] 3982 4664 3983 4665 [[package]] 4666 + name = "tagptr" 4667 + version = "0.2.0" 4668 + source = "registry+https://github.com/rust-lang/crates.io-index" 4669 + checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" 4670 + 4671 + [[package]] 3984 4672 name = "tempfile" 3985 4673 version = "3.24.0" 3986 4674 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4019 4707 dependencies = [ 4020 4708 "proc-macro2", 4021 4709 "quote", 4022 - "syn", 4710 + "syn 2.0.114", 4023 4711 ] 4024 4712 4025 4713 [[package]] ··· 4030 4718 dependencies = [ 4031 4719 "proc-macro2", 4032 4720 "quote", 4033 - "syn", 4721 + "syn 2.0.114", 4034 4722 ] 4035 4723 4036 4724 [[package]] ··· 4123 4811 dependencies = [ 4124 4812 "proc-macro2", 4125 4813 "quote", 4126 - "syn", 4814 + "syn 2.0.114", 4127 4815 ] 4128 4816 4129 4817 [[package]] ··· 4322 5010 "prettyplease", 4323 5011 "proc-macro2", 4324 5012 "quote", 4325 - "syn", 5013 + "syn 2.0.114", 4326 5014 ] 4327 5015 4328 5016 [[package]] ··· 4360 5048 "prost-build", 4361 5049 "prost-types", 4362 5050 "quote", 4363 - "syn", 5051 + "syn 2.0.114", 4364 5052 "tempfile", 4365 5053 "tonic-build", 4366 5054 ] ··· 4460 5148 dependencies = [ 4461 5149 "proc-macro2", 4462 5150 "quote", 4463 - "syn", 5151 + "syn 2.0.114", 4464 5152 ] 4465 5153 4466 5154 [[package]] ··· 4545 5233 ] 4546 5234 4547 5235 [[package]] 5236 + name = "trait-variant" 5237 + version = "0.1.2" 5238 + source = "registry+https://github.com/rust-lang/crates.io-index" 5239 + checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" 5240 + dependencies = [ 5241 + "proc-macro2", 5242 + "quote", 5243 + "syn 2.0.114", 5244 + ] 5245 + 5246 + [[package]] 5247 + name = "triomphe" 5248 + version = "0.1.15" 5249 + source = "registry+https://github.com/rust-lang/crates.io-index" 5250 + checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" 5251 + 5252 + [[package]] 4548 5253 name = "try-lock" 4549 5254 version = "0.2.5" 4550 5255 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4617 5322 checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" 4618 5323 4619 5324 [[package]] 5325 + name = "unicode-segmentation" 5326 + version = "1.12.0" 5327 + source = "registry+https://github.com/rust-lang/crates.io-index" 5328 + checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 5329 + 5330 + [[package]] 5331 + name = "unicode-width" 5332 + version = "0.1.14" 5333 + source = "registry+https://github.com/rust-lang/crates.io-index" 5334 + checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 5335 + 5336 + [[package]] 5337 + name = "unicode-xid" 5338 + version = "0.2.6" 5339 + source = "registry+https://github.com/rust-lang/crates.io-index" 5340 + checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 5341 + 5342 + [[package]] 4620 5343 name = "unsigned-varint" 4621 5344 version = "0.7.2" 4622 5345 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4644 5367 "idna", 4645 5368 "percent-encoding", 4646 5369 "serde", 5370 + "serde_derive", 4647 5371 ] 4648 5372 4649 5373 [[package]] 5374 + name = "urlencoding" 5375 + version = "2.1.3" 5376 + source = "registry+https://github.com/rust-lang/crates.io-index" 5377 + checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" 5378 + 5379 + [[package]] 4650 5380 name = "utf-8" 4651 5381 version = "0.7.6" 4652 5382 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4770 5500 "bumpalo", 4771 5501 "proc-macro2", 4772 5502 "quote", 4773 - "syn", 5503 + "syn 2.0.114", 4774 5504 "wasm-bindgen-shared", 4775 5505 ] 4776 5506 ··· 4817 5547 ] 4818 5548 4819 5549 [[package]] 5550 + name = "webpki-roots" 5551 + version = "1.0.5" 5552 + source = "registry+https://github.com/rust-lang/crates.io-index" 5553 + checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" 5554 + dependencies = [ 5555 + "rustls-pki-types", 5556 + ] 5557 + 5558 + [[package]] 4820 5559 name = "whoami" 4821 5560 version = "2.1.0" 4822 5561 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4876 5615 dependencies = [ 4877 5616 "proc-macro2", 4878 5617 "quote", 4879 - "syn", 5618 + "syn 2.0.114", 4880 5619 ] 4881 5620 4882 5621 [[package]] ··· 4887 5626 dependencies = [ 4888 5627 "proc-macro2", 4889 5628 "quote", 4890 - "syn", 5629 + "syn 2.0.114", 4891 5630 ] 4892 5631 4893 5632 [[package]] ··· 5203 5942 dependencies = [ 5204 5943 "proc-macro2", 5205 5944 "quote", 5206 - "syn", 5945 + "syn 2.0.114", 5207 5946 "synstructure", 5208 5947 ] 5209 5948 ··· 5224 5963 dependencies = [ 5225 5964 "proc-macro2", 5226 5965 "quote", 5227 - "syn", 5966 + "syn 2.0.114", 5228 5967 ] 5229 5968 5230 5969 [[package]] ··· 5244 5983 dependencies = [ 5245 5984 "proc-macro2", 5246 5985 "quote", 5247 - "syn", 5986 + "syn 2.0.114", 5248 5987 "synstructure", 5249 5988 ] 5250 5989 ··· 5284 6023 dependencies = [ 5285 6024 "proc-macro2", 5286 6025 "quote", 5287 - "syn", 6026 + "syn 2.0.114", 5288 6027 ] 5289 6028 5290 6029 [[package]]
+2 -1
crates/consumer/Cargo.toml
··· 8 8 ciborium = "0.2.2" 9 9 clap = { version = "4.5", features = ["derive"] } 10 10 deadpool-postgres = { version = "0.14", features = ["serde"] } 11 - did-resolver = { path = "../did-resolver" } 12 11 eyre = "0.6.12" 13 12 figment = { version = "0.10.19", features = ["env", "toml"] } 14 13 flume = { version = "0.11", features = ["async"] } ··· 16 15 futures = "0.3.31" 17 16 ipld-core = "0.4" 18 17 iroh-car = "0.5.1" 18 + jacquard-common = "0.9.5" 19 + jacquard-identity = { version = "0.9", features = ["cache", "dns"] } 19 20 lexica = { path = "../lexica" } 20 21 metrics = "0.24" 21 22 metrics-exporter-prometheus = "0.16.2"
+33 -35
crates/consumer/src/backfill/downloader.rs
··· 1 - use super::{DL_DONE_KEY, PDS_SERVICE_ID}; 1 + use super::DL_DONE_KEY; 2 2 use crate::db; 3 3 use chrono::prelude::*; 4 4 use deadpool_postgres::{Client as PgClient, Pool}; 5 - use did_resolver::Resolver; 6 5 use futures::TryStreamExt; 6 + use jacquard_common::types::did::Did; 7 + use jacquard_common::types::string::Handle; 8 + use jacquard_identity::resolver::IdentityResolver; 9 + use jacquard_identity::JacquardResolver; 7 10 use metrics::{counter, histogram}; 8 11 use parakeet_db::types::{ActorStatus, ActorSyncState}; 9 12 use redis::aio::MultiplexedConnection; ··· 11 14 use reqwest::header::HeaderMap; 12 15 use reqwest::Client as HttpClient; 13 16 use std::path::{Path, PathBuf}; 14 - use std::sync::Arc; 15 17 use tokio::sync::watch::Receiver as WatchReceiver; 16 18 use tokio::time::{Duration, Instant}; 17 19 use tokio_postgres::types::Type; ··· 26 28 pub async fn downloader( 27 29 mut rc: MultiplexedConnection, 28 30 pool: Pool, 29 - resolver: Arc<Resolver>, 31 + resolver: JacquardResolver, 30 32 tmp_dir: PathBuf, 31 33 concurrency: usize, 32 34 buffer: usize, ··· 105 107 } 106 108 } 107 109 108 - match resolver.resolve_did(&did).await { 109 - Ok(Some(did_doc)) => { 110 - let Some(service) = did_doc.find_service_by_id(PDS_SERVICE_ID) else { 110 + let jd = Did::raw(&did); 111 + match resolver 112 + .resolve_did_doc(&jd) 113 + .await 114 + .and_then(|v| v.into_owned()) 115 + { 116 + Ok(did_doc) => { 117 + let Some(service) = did_doc.pds_endpoint() else { 111 118 tracing::warn!("bad DID doc for {did}"); 112 119 db::backfill_job_write(&mut conn, &did, "failed.resolve.did_svc") 113 120 .await 114 121 .unwrap(); 115 122 continue; 116 123 }; 117 - let service = service.service_endpoint.clone(); 124 + let service = service.to_string(); 118 125 119 126 // set the repo to processing 120 - if let Err(e) = conn.execute(&status_stmt, &[&did]).await { 127 + if let Err(e) = conn.execute(&status_stmt, &[&did.as_str()]).await { 121 128 tracing::error!("failed to update repo status for {did}: {e}"); 122 129 continue; 123 130 } 124 131 125 - let handle = did_doc 126 - .also_known_as 127 - .and_then(|akas| akas.first().map(|v| v[5..].to_owned())); 132 + let handle = did_doc.handles().first().cloned(); 128 133 129 134 tracing::trace!("resolved repo {did} {service}"); 130 135 if let Err(e) = tx.send_async((service, did, handle)).await { 131 136 tracing::error!("failed to send: {e}"); 132 137 } 133 138 } 134 - Ok(None) => { 135 - tracing::warn!(did, "bad/missing DID doc"); 136 - db::actor_set_sync_status(&mut conn, &did, ActorSyncState::Dirty, Utc::now()) 137 - .await 138 - .unwrap(); 139 - db::backfill_job_write(&mut conn, &did, "failed.resolve.did_doc") 140 - .await 141 - .unwrap(); 142 - } 143 139 Err(e) => { 144 - tracing::error!(did, "failed to resolve DID doc: {e}"); 140 + tracing::error!(did = did.as_str(), "failed to resolve DID doc: {e}"); 145 141 db::actor_set_sync_status(&mut conn, &did, ActorSyncState::Dirty, Utc::now()) 146 142 .await 147 143 .unwrap(); ··· 156 152 async fn download_thread( 157 153 mut rc: MultiplexedConnection, 158 154 pool: Pool, 159 - resolver: Arc<Resolver>, 155 + resolver: JacquardResolver, 160 156 http: reqwest::Client, 161 - rx: flume::Receiver<(String, String, Option<String>)>, 157 + rx: flume::Receiver<(String, String, Option<Handle<'static>>)>, 162 158 tmp_dir: PathBuf, 163 159 ) { 164 160 tracing::debug!("spawning thread"); ··· 189 185 tracing::debug!("trying to resolve handle..."); 190 186 if let Some(handle) = maybe_handle { 191 187 if let Err(e) = resolve_and_set_handle(&conn, &resolver, &did, &handle).await { 192 - tracing::error!(pds, did, "failed to resolve handle: {e}"); 188 + tracing::error!(pds, did = did.as_str(), "failed to resolve handle: {e}"); 193 189 db::backfill_job_write(&mut conn, &did, "failed.resolve.handle") 194 190 .await 195 191 .unwrap(); ··· 254 250 did: &str, 255 251 ) -> eyre::Result<Option<(i32, i32)>> { 256 252 let res = http 257 - .get(format!("{pds}/xrpc/com.atproto.sync.getRepo?did={did}")) 253 + .get(format!("{pds}xrpc/com.atproto.sync.getRepo?did={did}")) 258 254 .send() 259 255 .await? 260 256 .error_for_status()?; ··· 316 312 317 313 async fn resolve_and_set_handle( 318 314 conn: &PgClient, 319 - resolver: &Resolver, 315 + resolver: &JacquardResolver, 320 316 did: &str, 321 - handle: &str, 317 + handle: &Handle<'_>, 322 318 ) -> eyre::Result<()> { 323 - if let Some(handle_did) = resolver.resolve_handle(handle).await? { 324 - if handle_did == did { 325 - conn.execute("UPDATE actors SET handle=$2 WHERE did=$1", &[&did, &handle]) 326 - .await?; 327 - } else { 328 - tracing::warn!("requested DID ({did}) doesn't match handle"); 329 - } 319 + let handle_did = resolver.resolve_handle(handle).await?; 320 + if handle_did == Did::raw(did) { 321 + conn.execute( 322 + "UPDATE actors SET handle=$2 WHERE did=$1", 323 + &[&did, &handle.as_str()], 324 + ) 325 + .await?; 326 + } else { 327 + tracing::warn!("requested DID ({did}) doesn't match handle"); 330 328 } 331 329 332 330 Ok(())
+4 -4
crates/consumer/src/backfill/mod.rs
··· 4 4 use crate::indexer::{self, records}; 5 5 use chrono::prelude::*; 6 6 use deadpool_postgres::{Object, Pool, Transaction}; 7 - use did_resolver::Resolver; 8 7 use ipld_core::cid::Cid; 8 + use jacquard_identity::JacquardResolver; 9 9 use lexica::StrongRef; 10 10 use metrics::counter; 11 11 use parakeet_db::types::{ActorStatus, ActorSyncState}; ··· 39 39 pub struct BackfillManager { 40 40 pool: Pool, 41 41 redis: MultiplexedConnection, 42 - resolver: Arc<Resolver>, 42 + resolver: JacquardResolver, 43 43 semaphore: Arc<Semaphore>, 44 44 opts: BackfillConfig, 45 45 inner: BackfillManagerInner, ··· 49 49 pub async fn new( 50 50 pool: Pool, 51 51 redis: MultiplexedConnection, 52 - resolver: Arc<Resolver>, 52 + resolver: JacquardResolver, 53 53 index_client: Option<parakeet_index::Client>, 54 54 opts: BackfillConfig, 55 55 ) -> eyre::Result<Self> { ··· 254 254 ) -> eyre::Result<Option<types::GetRepoStatusRes>> { 255 255 let res = client 256 256 .get(format!( 257 - "{pds}/xrpc/com.atproto.sync.getRepoStatus?did={repo}" 257 + "{pds}xrpc/com.atproto.sync.getRepoStatus?did={repo}" 258 258 )) 259 259 .send() 260 260 .await?;
+14 -35
crates/consumer/src/indexer/mod.rs
··· 9 9 }; 10 10 use crate::utils::at_uri_is_by; 11 11 use deadpool_postgres::{Object, Pool, Transaction}; 12 - use did_resolver::Resolver; 13 12 use foldhash::quality::RandomState; 14 13 use futures::StreamExt; 15 14 use ipld_core::cid::Cid; 15 + use jacquard_common::types::string::Handle; 16 + use jacquard_identity::JacquardResolver; 16 17 use metrics::counter; 17 18 use parakeet_db::types::{ActorStatus, ActorSyncState}; 18 19 use parakeet_index::AggregateType; ··· 20 21 use redis::AsyncCommands; 21 22 use std::collections::HashMap; 22 23 use std::hash::BuildHasher; 23 - use std::sync::Arc; 24 24 use tokio::sync::mpsc::{channel, Sender}; 25 25 use tokio::sync::watch::Receiver as WatchReceiver; 26 26 use tracing::instrument; ··· 37 37 #[derive(Clone)] 38 38 struct RelayIndexerState { 39 39 idxc_tx: Sender<parakeet_index::AggregateDeltaReq>, 40 - resolver: Arc<Resolver>, 40 + resolver: JacquardResolver, 41 41 do_backfill: bool, 42 42 do_handle_res: bool, 43 43 req_backfill: bool, ··· 57 57 pool: Pool, 58 58 redis: MultiplexedConnection, 59 59 idxc_tx: Sender<parakeet_index::AggregateDeltaReq>, 60 - resolver: Arc<Resolver>, 60 + resolver: JacquardResolver, 61 61 firehose: FirehoseConsumer, 62 62 resume: sled::Db, 63 63 opts: RelayIndexerOpts, ··· 253 253 did: &str, 254 254 expected_handle: Option<String>, 255 255 ) -> eyre::Result<Option<String>> { 256 - // Resolve the did doc 257 - let Some(did_doc) = state.resolver.resolve_did(did).await? else { 258 - eyre::bail!("missing did doc"); 256 + let Some(handle) = expected_handle else { 257 + return Ok(None); 259 258 }; 260 259 261 - // if there's no handles in aka or the expected is none, set to none in DB. 262 - if did_doc.also_known_as.as_ref().is_none_or(|v| v.is_empty()) || expected_handle.is_none() { 263 - return Ok(None); 264 - } 265 - 266 - let expected = expected_handle.unwrap(); 267 - 268 - // check if the handle from the event is in the did doc 269 - let expected_in_doc = did_doc.also_known_as.is_some_and(|v| { 270 - v.iter() 271 - .filter_map(|v| v.strip_prefix("at://")) 272 - .any(|v| v == expected) 273 - }); 274 - 275 - // if it isn't, set to invalid. 276 - if !expected_in_doc { 277 - tracing::warn!("Handle not in DID doc"); 278 - return Ok(None); 279 - } 280 - 281 - // in theory, we can use com.atproto.identity.resolveHandle against a PDS, but that seems 282 - // like a way to end up with really sus handles. 283 - let Some(handle_did) = state.resolver.resolve_handle(&expected).await? else { 284 - return Ok(None); 285 - }; 260 + // this verifies that the handle and the did it resolves to match. 261 + let (handle_did, _did_doc, _warnings) = state 262 + .resolver 263 + .resolve_handle_and_doc(&Handle::raw(&handle)) 264 + .await?; 286 265 287 266 // finally, check if the event did matches the handle, if not, set invalid, otherwise set the handle. 288 - if handle_did != did { 289 - Ok(None) 267 + if did == &*handle_did { 268 + return Ok(Some(handle)); 290 269 } else { 291 - Ok(Some(expected)) 270 + return Ok(None); 292 271 } 293 272 } 294 273
+20 -7
crates/consumer/src/main.rs
··· 1 1 use deadpool_postgres::Runtime; 2 - use did_resolver::{Resolver, ResolverOpts}; 3 2 use eyre::OptionExt; 3 + use jacquard_identity::{resolver::ResolverOptions, JacquardResolver}; 4 4 use metrics_exporter_prometheus::PrometheusBuilder; 5 - use std::sync::Arc; 6 5 use tokio::signal::ctrl_c; 7 6 use tokio_postgres::NoTls; 8 7 ··· 41 40 Ok::<_, eyre::Report>(()) 42 41 }); 43 42 44 - let resolver = Arc::new(Resolver::new(ResolverOpts { 45 - plc_directory: conf.plc_directory, 46 - user_agent: Some(user_agent.clone()), 47 - ..Default::default() 48 - })?); 43 + let resolver_opts = build_resolver_opts(conf.plc_directory); 44 + let resolver = JacquardResolver::new_dns(reqwest::Client::new(), resolver_opts).with_cache(); 49 45 50 46 let index_client = parakeet_index::Client::connect(conf.index_uri).await?; 51 47 ··· 172 168 173 169 ua 174 170 } 171 + 172 + fn build_resolver_opts(plc_dir: Option<String>) -> ResolverOptions { 173 + use jacquard_identity::resolver::{DidStep, HandleStep, PlcSource}; 174 + 175 + let plc_source = plc_dir 176 + .and_then(|url| url.parse().ok()) 177 + .map(|base| PlcSource::PlcDirectory { base }) 178 + .unwrap_or_default(); 179 + 180 + ResolverOptions::new() 181 + .plc_source(plc_source) 182 + .handle_order(vec![HandleStep::DnsTxt, HandleStep::HttpsWellKnown]) 183 + .did_order(vec![DidStep::DidWebHttps, DidStep::PlcHttp]) 184 + .validate_doc_id(true) 185 + .public_fallback_for_handle(false) 186 + .build() 187 + }
-12
crates/did-resolver/Cargo.toml
··· 1 - [package] 2 - name = "did-resolver" 3 - version = "0.1.0" 4 - edition = "2021" 5 - 6 - [dependencies] 7 - hickory-resolver = "0.24" 8 - reqwest = { version = "0.12.12", features = ["json", "native-tls"] } 9 - serde = { version = "1.0", features = ["derive"] } 10 - serde_json = "1.0" 11 - thiserror = "2.0" 12 - tokio = { version = "1.49", features = ["macros"] }
-19
crates/did-resolver/src/error.rs
··· 1 - use thiserror::Error; 2 - 3 - #[derive(Debug, Error)] 4 - pub enum Error { 5 - #[error("did was not in expected format did:method:identifier")] 6 - BadDidFormat, 7 - #[error("{0}")] 8 - Dns(#[from] hickory_resolver::error::ResolveError), 9 - #[error("{0}")] 10 - Http(#[from] reqwest::Error), 11 - #[error("the did endpoint returned a server error")] 12 - ServerError, 13 - #[error("document request timed out")] 14 - Timeout, 15 - #[error("too many redirects")] 16 - TooManyRedirects, 17 - #[error("did method was not plc or web: {0}")] 18 - UnsupportedDidMethod(String), 19 - }
-179
crates/did-resolver/src/lib.rs
··· 1 - use error::Error; 2 - use hickory_resolver::proto::serialize::binary::BinEncodable; 3 - use hickory_resolver::TokioAsyncResolver; 4 - use reqwest::header::CONTENT_TYPE; 5 - use reqwest::{Client, StatusCode}; 6 - 7 - pub mod error; 8 - pub mod types; 9 - 10 - const DEFAULT_DUR: std::time::Duration = std::time::Duration::from_secs(3); 11 - const DEFAULT_PLC: &str = "https://plc.directory"; 12 - 13 - #[derive(Default)] 14 - pub struct ResolverOpts { 15 - pub plc_directory: Option<String>, 16 - pub timeout: Option<std::time::Duration>, 17 - pub user_agent: Option<String>, 18 - } 19 - 20 - pub struct Resolver { 21 - client: Client, 22 - plc: String, 23 - dns: TokioAsyncResolver, 24 - } 25 - 26 - impl Resolver { 27 - pub fn new(opts: ResolverOpts) -> Result<Self, Error> { 28 - let dns = hickory_resolver::AsyncResolver::tokio_from_system_conf()?; 29 - 30 - let mut client = Client::builder().timeout(opts.timeout.unwrap_or(DEFAULT_DUR)); 31 - 32 - if let Some(user_agent) = opts.user_agent { 33 - client = client.user_agent(user_agent); 34 - } 35 - 36 - Ok(Resolver { 37 - client: client.build()?, 38 - plc: opts.plc_directory.unwrap_or(DEFAULT_PLC.to_string()), 39 - dns, 40 - }) 41 - } 42 - 43 - pub async fn resolve_did(&self, did: &str) -> Result<Option<types::DidDocument>, Error> { 44 - let did_parts = did.splitn(3, ':').collect::<Vec<&str>>(); 45 - 46 - if did_parts.len() != 3 { 47 - return Err(Error::BadDidFormat); 48 - } 49 - 50 - if did_parts[0] != "did" { 51 - return Err(Error::BadDidFormat); 52 - } 53 - 54 - match did_parts[1] { 55 - "plc" => self.resolve_did_plc(did).await, 56 - "web" => self.resolve_did_web(did_parts[2]).await, 57 - method => Err(Error::UnsupportedDidMethod(method.to_string())), 58 - } 59 - } 60 - 61 - async fn resolve_did_plc(&self, did: &str) -> Result<Option<types::DidDocument>, Error> { 62 - let res = self 63 - .client 64 - .get(format!("{}/{did}", self.plc)) 65 - .send() 66 - .await?; 67 - 68 - let status = res.status(); 69 - 70 - if status.is_server_error() { 71 - return Err(Error::ServerError); 72 - } 73 - 74 - if status == StatusCode::NOT_FOUND || status == StatusCode::GONE { 75 - return Ok(None); 76 - } 77 - 78 - let did_doc = res.json().await?; 79 - Ok(Some(did_doc)) 80 - } 81 - 82 - async fn resolve_did_web(&self, id: &str) -> Result<Option<types::DidDocument>, Error> { 83 - let res = match self 84 - .client 85 - .get(format!("https://{id}/.well-known/did.json")) 86 - .send() 87 - .await 88 - { 89 - Ok(res) => res, 90 - Err(err) => { 91 - if err.is_timeout() { 92 - return Err(Error::Timeout); 93 - } else if err.is_redirect() { 94 - return Err(Error::TooManyRedirects); 95 - } 96 - return Err(Error::Http(err)); 97 - } 98 - }; 99 - 100 - let status = res.status(); 101 - 102 - if status.is_server_error() { 103 - return Err(Error::ServerError); 104 - } 105 - 106 - if status == StatusCode::NOT_FOUND { 107 - return Ok(None); 108 - } 109 - 110 - let did_doc = res.json().await?; 111 - Ok(Some(did_doc)) 112 - } 113 - 114 - pub async fn resolve_handle(&self, handle: &str) -> Result<Option<String>, Error> { 115 - // we want one of these to succeed 116 - let http = self.resolve_handle_http(handle); 117 - let dns = self.resolve_handle_dns(handle); 118 - 119 - match tokio::join!(http, dns) { 120 - (Ok(http), Ok(dns)) => Ok(dns.or(http)), 121 - (http, dns) => http.or(dns), 122 - } 123 - } 124 - 125 - async fn resolve_handle_http(&self, handle: &str) -> Result<Option<String>, Error> { 126 - let res = self 127 - .client 128 - .get(format!("https://{handle}/.well-known/atproto-did")) 129 - .send() 130 - .await? 131 - .error_for_status()?; 132 - 133 - if let Some(ct) = res 134 - .headers() 135 - .get(CONTENT_TYPE) 136 - .and_then(|ct| ct.to_str().ok()) 137 - { 138 - if !ct.starts_with("text/plain") { 139 - return Ok(None); 140 - } 141 - } 142 - 143 - let did = res.text().await?; 144 - if !did.starts_with("did:") { 145 - return Ok(None); 146 - } 147 - 148 - Ok(Some(did)) 149 - } 150 - 151 - async fn resolve_handle_dns(&self, handle: &str) -> Result<Option<String>, Error> { 152 - let res = match self.dns.txt_lookup(format!("_atproto.{handle}.")).await { 153 - Ok(txt) => txt, 154 - Err(err) => { 155 - return match err.kind() { 156 - hickory_resolver::error::ResolveErrorKind::NoRecordsFound { .. } => Ok(None), 157 - _ => Err(err.into()), 158 - } 159 - } 160 - }; 161 - 162 - let Some(first) = res.as_lookup().records().first() else { 163 - return Ok(None); 164 - }; 165 - 166 - let Some(Ok(data)) = first.data().and_then(|v| v.as_txt()).map(|v| v.to_bytes()) else { 167 - return Ok(None); 168 - }; 169 - 170 - let Some(string_data) = String::from_utf8_lossy(&data) 171 - .strip_prefix("$did=") 172 - .map(|v| v.to_string()) 173 - else { 174 - return Ok(None); 175 - }; 176 - 177 - Ok(Some(string_data)) 178 - } 179 - }
-46
crates/did-resolver/src/types.rs
··· 1 - use serde::Deserialize; 2 - 3 - #[derive(Debug, Deserialize)] 4 - #[serde(rename_all = "camelCase")] 5 - pub struct DidDocument { 6 - #[serde(default, rename = "@context")] 7 - pub context: Vec<String>, 8 - pub id: String, 9 - /// Ordered set (no duplicates) of aliases and names for this account, in the form of URIs 10 - pub also_known_as: Option<Vec<String>>, 11 - pub service: Option<Vec<DidService>>, 12 - pub verification_method: Option<Vec<DidVerificationMethod>>, 13 - } 14 - 15 - impl DidDocument { 16 - pub fn find_service_by_id(&self, service: &str) -> Option<&DidService> { 17 - self.service 18 - .as_ref() 19 - .and_then(|services| services.iter().find(|s| s.id == service)) 20 - } 21 - 22 - pub fn find_verif_method_by_type(&self, ty: &str) -> Option<&DidVerificationMethod> { 23 - self.verification_method 24 - .as_ref() 25 - .and_then(|methods| methods.iter().find(|m| m.ty == ty)) 26 - } 27 - } 28 - 29 - #[derive(Debug, Deserialize)] 30 - #[serde(rename_all = "camelCase")] 31 - pub struct DidService { 32 - pub id: String, 33 - #[serde(rename = "type")] 34 - pub ty: String, 35 - pub service_endpoint: String, 36 - } 37 - 38 - #[derive(Debug, Deserialize)] 39 - #[serde(rename_all = "camelCase")] 40 - pub struct DidVerificationMethod { 41 - pub id: String, 42 - #[serde(rename = "type")] 43 - pub ty: String, 44 - pub controller: String, 45 - pub public_key_multibase: String, 46 - }
+2 -1
crates/parakeet/Cargo.toml
··· 12 12 chrono = { version = "0.4", features = ["serde"] } 13 13 dataloader = { path = "../dataloader-rs" } 14 14 deadpool = { version = "0.12", features = ["managed"] } 15 - did-resolver = { path = "../did-resolver" } 16 15 diesel = { version = "2.3", features = ["chrono", "serde_json"] } 17 16 diesel_migrations = "2.3" 18 17 diesel-async = { version = "0.7", features = ["deadpool", "postgres", "migrations"] } 19 18 eyre = "0.6.12" 20 19 figment = { version = "0.10.19", features = ["env", "toml"] } 21 20 itertools = "0.14" 21 + jacquard-common = "0.9.5" 22 + jacquard-identity = { version = "0.9.5", features = ["cache", "dns"] } 22 23 jsonwebtoken = { git = "https://gitlab.com/parakeet-social/jsonwebtoken", branch = "es256k" } 23 24 lexica = { path = "../lexica" } 24 25 multibase = "0.9"
+24 -5
crates/parakeet/src/main.rs
··· 3 3 use diesel_async::pooled_connection::AsyncDieselConnectionManager; 4 4 use diesel_async::{AsyncMigrationHarness, AsyncPgConnection}; 5 5 use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; 6 + use jacquard_identity::resolver::ResolverOptions; 7 + use jacquard_identity::JacquardResolver; 6 8 use redis::aio::MultiplexedConnection; 7 9 use std::sync::Arc; 8 10 use tower_http::cors::{AllowHeaders, AllowOrigin, CorsLayer}; ··· 23 25 pub pool: Pool<AsyncPgConnection>, 24 26 pub redis_mp: MultiplexedConnection, 25 27 pub dataloaders: Arc<loaders::Dataloaders>, 26 - pub resolver: Arc<did_resolver::Resolver>, 28 + pub resolver: JacquardResolver, 27 29 pub index_client: parakeet_index::Client, 28 30 pub jwt: Arc<xrpc::jwt::JwtVerifier>, 29 31 pub cdn: Arc<xrpc::cdn::BskyCdn>, ··· 59 61 redis_mp.clone(), 60 62 index_client.clone(), 61 63 )); 62 - let resolver = Arc::new(did_resolver::Resolver::new(did_resolver::ResolverOpts { 63 - plc_directory: conf.plc_directory, 64 - ..Default::default() 65 - })?); 64 + 65 + let resolver_opts = build_resolver_opts(conf.plc_directory); 66 + let resolver = JacquardResolver::new_dns(reqwest::Client::new(), resolver_opts).with_cache(); 67 + 66 68 let jwt = Arc::new(xrpc::jwt::JwtVerifier::new( 67 69 conf.service.did.clone(), 68 70 resolver.clone(), ··· 136 138 ] 137 139 }) 138 140 } 141 + 142 + fn build_resolver_opts(plc_dir: Option<String>) -> ResolverOptions { 143 + use jacquard_identity::resolver::{DidStep, HandleStep, PlcSource}; 144 + 145 + let plc_source = plc_dir 146 + .and_then(|url| url.parse().ok()) 147 + .map(|base| PlcSource::PlcDirectory { base }) 148 + .unwrap_or_default(); 149 + 150 + ResolverOptions::new() 151 + .plc_source(plc_source) 152 + .handle_order(vec![HandleStep::DnsTxt, HandleStep::HttpsWellKnown]) 153 + .did_order(vec![DidStep::DidWebHttps, DidStep::PlcHttp]) 154 + .validate_doc_id(true) 155 + .public_fallback_for_handle(false) 156 + .build() 157 + }
+20 -7
crates/parakeet/src/xrpc/app_bsky/feed/posts.rs
··· 15 15 use chrono::prelude::*; 16 16 use diesel::prelude::*; 17 17 use diesel_async::{AsyncPgConnection, RunQueryDsl}; 18 + use jacquard_common::types::did::Did; 19 + use jacquard_identity::resolver::IdentityResolver; 18 20 use lexica::app_bsky::actor::ProfileView; 19 21 use lexica::app_bsky::feed::{ 20 22 BlockedAuthor, FeedSkeletonResponse, FeedViewPost, PostView, SkeletonReason, ThreadViewPost, ··· 57 59 .find(&query.feed) 58 60 .get_result(&mut conn) 59 61 .await?; 62 + let service_did = Did::raw(&service_did); 60 63 61 64 // resolve the did 62 - let did_doc = match state.resolver.resolve_did(&service_did).await { 63 - Ok(Some(did_doc)) => did_doc, 64 - Ok(None) => return Err(Error::invalid_request(None)), 65 + let did_doc = match state.resolver.resolve_did_doc_owned(&service_did).await { 66 + Ok(did_doc) => did_doc, 65 67 Err(err) => { 66 68 tracing::error!( 67 - feedgen = service_did, 69 + feedgen = service_did.as_str(), 68 70 "failed to resolve feedgen service did: {err}" 69 71 ); 70 72 return Err(Error::invalid_request(None)); ··· 72 74 }; 73 75 74 76 // find the service 75 - let Some(service) = did_doc.find_service_by_id(FEEDGEN_SERVICE_ID) else { 77 + let service = did_doc 78 + .service 79 + .as_ref() 80 + .and_then(|services| services.iter().find(|svc| svc.id == FEEDGEN_SERVICE_ID)); 81 + 82 + let Some(service) = service else { 76 83 tracing::error!( 77 - feedgen = service_did, 84 + feedgen = service_did.as_str(), 78 85 "DID doc didn't contain BskyFeedGenerator service" 79 86 ); 80 87 return Err(Error::invalid_request(None)); 81 88 }; 82 89 83 - let endpoint = service.service_endpoint.clone(); 90 + let Some(endpoint) = service.service_endpoint.as_ref().and_then(|se| se.as_str()) else { 91 + tracing::error!( 92 + feedgen = service_did.as_str(), 93 + "DID doc didn't contain BskyFeedGenerator endpoint, or it was invalid" 94 + ); 95 + return Err(Error::invalid_request(None)); 96 + }; 84 97 let skeleton = get_feed_skeleton( 85 98 &query.feed, 86 99 &endpoint,
+11 -9
crates/parakeet/src/xrpc/jwt.rs
··· 1 - use did_resolver::Resolver; 1 + use jacquard_common::types::did::Did; 2 + use jacquard_identity::resolver::IdentityResolver; 3 + use jacquard_identity::JacquardResolver; 2 4 use jsonwebtoken::{Algorithm, DecodingKey, Validation}; 3 5 use serde::{Deserialize, Serialize}; 4 6 use std::collections::HashMap; 5 - use std::sync::{Arc, LazyLock}; 7 + use std::sync::LazyLock; 6 8 use tokio::sync::RwLock; 7 9 use tracing::instrument; 8 10 ··· 26 28 27 29 pub struct JwtVerifier { 28 30 aud: String, 29 - resolver: Arc<Resolver>, 31 + resolver: JacquardResolver, 30 32 key_cache: RwLock<HashMap<String, String>>, 31 33 } 32 34 33 35 impl JwtVerifier { 34 - pub fn new(aud: String, resolver: Arc<Resolver>) -> Self { 36 + pub fn new(aud: String, resolver: JacquardResolver) -> Self { 35 37 JwtVerifier { 36 38 aud, 37 39 resolver, ··· 61 63 #[instrument(skip_all)] 62 64 async fn resolve_key(&self, did: &str) -> Option<String> { 63 65 tracing::trace!("resolving multikey for {did}"); 64 - let did_doc = self.resolver.resolve_did(did).await.ok()??; 66 + let did = Did::new(did).ok()?; 67 + let did_doc = self.resolver.resolve_did_doc_owned(&did).await.ok()?; 65 68 66 - // try find the multibase key 67 - let multikey = did_doc.find_verif_method_by_type("Multikey")?; 69 + let multikey = did_doc.atproto_multikey()?.to_string(); 68 70 69 71 { 70 72 let mut l = self.key_cache.write().await; 71 - l.insert(did.to_string(), multikey.public_key_multibase.clone()); 73 + l.insert(did.to_string(), multikey.clone()); 72 74 } 73 75 74 - Some(multikey.public_key_multibase.clone()) 76 + Some(multikey) 75 77 } 76 78 77 79 pub fn verify_jwt_multibase(&self, token: &str, multibase_key: &str) -> Option<Claims> {