Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm

Merge branch 'videah-main'

+8
jetstream/.gitignore
··· 1 + target/ 2 + pkg/ 3 + **/*.rs.bk 4 + dist/ 5 + traces/ 6 + *.DS_Store 7 + .cargo/ 8 + .env
+1856
jetstream/Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 4 4 + 5 + [[package]] 6 + name = "addr2line" 7 + version = "0.24.2" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 + dependencies = [ 11 + "gimli", 12 + ] 13 + 14 + [[package]] 15 + name = "adler2" 16 + version = "2.0.0" 17 + source = "registry+https://github.com/rust-lang/crates.io-index" 18 + checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 + 20 + [[package]] 21 + name = "aho-corasick" 22 + version = "1.1.3" 23 + source = "registry+https://github.com/rust-lang/crates.io-index" 24 + checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 + dependencies = [ 26 + "memchr", 27 + ] 28 + 29 + [[package]] 30 + name = "android-tzdata" 31 + version = "0.1.1" 32 + source = "registry+https://github.com/rust-lang/crates.io-index" 33 + checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 34 + 35 + [[package]] 36 + name = "android_system_properties" 37 + version = "0.1.5" 38 + source = "registry+https://github.com/rust-lang/crates.io-index" 39 + checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 40 + dependencies = [ 41 + "libc", 42 + ] 43 + 44 + [[package]] 45 + name = "anstream" 46 + version = "0.6.18" 47 + source = "registry+https://github.com/rust-lang/crates.io-index" 48 + checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 49 + dependencies = [ 50 + "anstyle", 51 + "anstyle-parse", 52 + "anstyle-query", 53 + "anstyle-wincon", 54 + "colorchoice", 55 + "is_terminal_polyfill", 56 + "utf8parse", 57 + ] 58 + 59 + [[package]] 60 + name = "anstyle" 61 + version = "1.0.10" 62 + source = "registry+https://github.com/rust-lang/crates.io-index" 63 + checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 64 + 65 + [[package]] 66 + name = "anstyle-parse" 67 + version = "0.2.6" 68 + source = "registry+https://github.com/rust-lang/crates.io-index" 69 + checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 70 + dependencies = [ 71 + "utf8parse", 72 + ] 73 + 74 + [[package]] 75 + name = "anstyle-query" 76 + version = "1.1.2" 77 + source = "registry+https://github.com/rust-lang/crates.io-index" 78 + checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 79 + dependencies = [ 80 + "windows-sys 0.59.0", 81 + ] 82 + 83 + [[package]] 84 + name = "anstyle-wincon" 85 + version = "3.0.6" 86 + source = "registry+https://github.com/rust-lang/crates.io-index" 87 + checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 88 + dependencies = [ 89 + "anstyle", 90 + "windows-sys 0.59.0", 91 + ] 92 + 93 + [[package]] 94 + name = "anyhow" 95 + version = "1.0.93" 96 + source = "registry+https://github.com/rust-lang/crates.io-index" 97 + checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" 98 + 99 + [[package]] 100 + name = "async-trait" 101 + version = "0.1.83" 102 + source = "registry+https://github.com/rust-lang/crates.io-index" 103 + checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" 104 + dependencies = [ 105 + "proc-macro2", 106 + "quote", 107 + "syn 2.0.87", 108 + ] 109 + 110 + [[package]] 111 + name = "atrium-api" 112 + version = "0.24.7" 113 + source = "registry+https://github.com/rust-lang/crates.io-index" 114 + checksum = "ee68ddf7cde9eb121eed3a28b138f6a9b4c4a90ab0c5c2e38bc2817af0b06da3" 115 + dependencies = [ 116 + "atrium-xrpc", 117 + "chrono", 118 + "http", 119 + "ipld-core", 120 + "langtag", 121 + "regex", 122 + "serde", 123 + "serde_bytes", 124 + "serde_json", 125 + "thiserror 1.0.69", 126 + "trait-variant", 127 + ] 128 + 129 + [[package]] 130 + name = "atrium-xrpc" 131 + version = "0.11.6" 132 + source = "registry+https://github.com/rust-lang/crates.io-index" 133 + checksum = "737eea1de2eb174bbfe720619cb25a22c30b9640ae0d3b78386cedf007712963" 134 + dependencies = [ 135 + "http", 136 + "serde", 137 + "serde_html_form", 138 + "serde_json", 139 + "thiserror 1.0.69", 140 + "trait-variant", 141 + ] 142 + 143 + [[package]] 144 + name = "autocfg" 145 + version = "1.4.0" 146 + source = "registry+https://github.com/rust-lang/crates.io-index" 147 + checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 148 + 149 + [[package]] 150 + name = "backtrace" 151 + version = "0.3.74" 152 + source = "registry+https://github.com/rust-lang/crates.io-index" 153 + checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 154 + dependencies = [ 155 + "addr2line", 156 + "cfg-if", 157 + "libc", 158 + "miniz_oxide", 159 + "object", 160 + "rustc-demangle", 161 + "windows-targets", 162 + ] 163 + 164 + [[package]] 165 + name = "base-x" 166 + version = "0.2.11" 167 + source = "registry+https://github.com/rust-lang/crates.io-index" 168 + checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" 169 + 170 + [[package]] 171 + name = "bitflags" 172 + version = "2.6.0" 173 + source = "registry+https://github.com/rust-lang/crates.io-index" 174 + checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 175 + 176 + [[package]] 177 + name = "block-buffer" 178 + version = "0.10.4" 179 + source = "registry+https://github.com/rust-lang/crates.io-index" 180 + checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 181 + dependencies = [ 182 + "generic-array", 183 + ] 184 + 185 + [[package]] 186 + name = "bumpalo" 187 + version = "3.16.0" 188 + source = "registry+https://github.com/rust-lang/crates.io-index" 189 + checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 190 + 191 + [[package]] 192 + name = "byteorder" 193 + version = "1.5.0" 194 + source = "registry+https://github.com/rust-lang/crates.io-index" 195 + checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 196 + 197 + [[package]] 198 + name = "bytes" 199 + version = "1.9.0" 200 + source = "registry+https://github.com/rust-lang/crates.io-index" 201 + checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 202 + 203 + [[package]] 204 + name = "cc" 205 + version = "1.2.0" 206 + source = "registry+https://github.com/rust-lang/crates.io-index" 207 + checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" 208 + dependencies = [ 209 + "jobserver", 210 + "libc", 211 + "shlex", 212 + ] 213 + 214 + [[package]] 215 + name = "cfg-if" 216 + version = "1.0.0" 217 + source = "registry+https://github.com/rust-lang/crates.io-index" 218 + checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 219 + 220 + [[package]] 221 + name = "chrono" 222 + version = "0.4.38" 223 + source = "registry+https://github.com/rust-lang/crates.io-index" 224 + checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 225 + dependencies = [ 226 + "android-tzdata", 227 + "iana-time-zone", 228 + "js-sys", 229 + "num-traits", 230 + "serde", 231 + "wasm-bindgen", 232 + "windows-targets", 233 + ] 234 + 235 + [[package]] 236 + name = "cid" 237 + version = "0.11.1" 238 + source = "registry+https://github.com/rust-lang/crates.io-index" 239 + checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" 240 + dependencies = [ 241 + "core2", 242 + "multibase", 243 + "multihash", 244 + "serde", 245 + "serde_bytes", 246 + "unsigned-varint", 247 + ] 248 + 249 + [[package]] 250 + name = "clap" 251 + version = "4.5.21" 252 + source = "registry+https://github.com/rust-lang/crates.io-index" 253 + checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" 254 + dependencies = [ 255 + "clap_builder", 256 + "clap_derive", 257 + ] 258 + 259 + [[package]] 260 + name = "clap_builder" 261 + version = "4.5.21" 262 + source = "registry+https://github.com/rust-lang/crates.io-index" 263 + checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" 264 + dependencies = [ 265 + "anstream", 266 + "anstyle", 267 + "clap_lex", 268 + "strsim", 269 + ] 270 + 271 + [[package]] 272 + name = "clap_derive" 273 + version = "4.5.18" 274 + source = "registry+https://github.com/rust-lang/crates.io-index" 275 + checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" 276 + dependencies = [ 277 + "heck", 278 + "proc-macro2", 279 + "quote", 280 + "syn 2.0.87", 281 + ] 282 + 283 + [[package]] 284 + name = "clap_lex" 285 + version = "0.7.3" 286 + source = "registry+https://github.com/rust-lang/crates.io-index" 287 + checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" 288 + 289 + [[package]] 290 + name = "colorchoice" 291 + version = "1.0.3" 292 + source = "registry+https://github.com/rust-lang/crates.io-index" 293 + checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 294 + 295 + [[package]] 296 + name = "core-foundation" 297 + version = "0.9.4" 298 + source = "registry+https://github.com/rust-lang/crates.io-index" 299 + checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 300 + dependencies = [ 301 + "core-foundation-sys", 302 + "libc", 303 + ] 304 + 305 + [[package]] 306 + name = "core-foundation-sys" 307 + version = "0.8.7" 308 + source = "registry+https://github.com/rust-lang/crates.io-index" 309 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 310 + 311 + [[package]] 312 + name = "core2" 313 + version = "0.4.0" 314 + source = "registry+https://github.com/rust-lang/crates.io-index" 315 + checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" 316 + dependencies = [ 317 + "memchr", 318 + ] 319 + 320 + [[package]] 321 + name = "cpufeatures" 322 + version = "0.2.15" 323 + source = "registry+https://github.com/rust-lang/crates.io-index" 324 + checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" 325 + dependencies = [ 326 + "libc", 327 + ] 328 + 329 + [[package]] 330 + name = "crypto-common" 331 + version = "0.1.6" 332 + source = "registry+https://github.com/rust-lang/crates.io-index" 333 + checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 334 + dependencies = [ 335 + "generic-array", 336 + "typenum", 337 + ] 338 + 339 + [[package]] 340 + name = "data-encoding" 341 + version = "2.6.0" 342 + source = "registry+https://github.com/rust-lang/crates.io-index" 343 + checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" 344 + 345 + [[package]] 346 + name = "data-encoding-macro" 347 + version = "0.1.15" 348 + source = "registry+https://github.com/rust-lang/crates.io-index" 349 + checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" 350 + dependencies = [ 351 + "data-encoding", 352 + "data-encoding-macro-internal", 353 + ] 354 + 355 + [[package]] 356 + name = "data-encoding-macro-internal" 357 + version = "0.1.13" 358 + source = "registry+https://github.com/rust-lang/crates.io-index" 359 + checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" 360 + dependencies = [ 361 + "data-encoding", 362 + "syn 1.0.109", 363 + ] 364 + 365 + [[package]] 366 + name = "digest" 367 + version = "0.10.7" 368 + source = "registry+https://github.com/rust-lang/crates.io-index" 369 + checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 370 + dependencies = [ 371 + "block-buffer", 372 + "crypto-common", 373 + ] 374 + 375 + [[package]] 376 + name = "displaydoc" 377 + version = "0.2.5" 378 + source = "registry+https://github.com/rust-lang/crates.io-index" 379 + checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 380 + dependencies = [ 381 + "proc-macro2", 382 + "quote", 383 + "syn 2.0.87", 384 + ] 385 + 386 + [[package]] 387 + name = "equivalent" 388 + version = "1.0.1" 389 + source = "registry+https://github.com/rust-lang/crates.io-index" 390 + checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 391 + 392 + [[package]] 393 + name = "errno" 394 + version = "0.3.9" 395 + source = "registry+https://github.com/rust-lang/crates.io-index" 396 + checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 397 + dependencies = [ 398 + "libc", 399 + "windows-sys 0.52.0", 400 + ] 401 + 402 + [[package]] 403 + name = "fastrand" 404 + version = "2.2.0" 405 + source = "registry+https://github.com/rust-lang/crates.io-index" 406 + checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" 407 + 408 + [[package]] 409 + name = "flume" 410 + version = "0.11.1" 411 + source = "registry+https://github.com/rust-lang/crates.io-index" 412 + checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" 413 + dependencies = [ 414 + "futures-core", 415 + "futures-sink", 416 + "nanorand", 417 + "spin", 418 + ] 419 + 420 + [[package]] 421 + name = "fnv" 422 + version = "1.0.7" 423 + source = "registry+https://github.com/rust-lang/crates.io-index" 424 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 425 + 426 + [[package]] 427 + name = "foreign-types" 428 + version = "0.3.2" 429 + source = "registry+https://github.com/rust-lang/crates.io-index" 430 + checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 431 + dependencies = [ 432 + "foreign-types-shared", 433 + ] 434 + 435 + [[package]] 436 + name = "foreign-types-shared" 437 + version = "0.1.1" 438 + source = "registry+https://github.com/rust-lang/crates.io-index" 439 + checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 440 + 441 + [[package]] 442 + name = "form_urlencoded" 443 + version = "1.2.1" 444 + source = "registry+https://github.com/rust-lang/crates.io-index" 445 + checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 446 + dependencies = [ 447 + "percent-encoding", 448 + ] 449 + 450 + [[package]] 451 + name = "futures-core" 452 + version = "0.3.31" 453 + source = "registry+https://github.com/rust-lang/crates.io-index" 454 + checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 455 + 456 + [[package]] 457 + name = "futures-macro" 458 + version = "0.3.31" 459 + source = "registry+https://github.com/rust-lang/crates.io-index" 460 + checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 461 + dependencies = [ 462 + "proc-macro2", 463 + "quote", 464 + "syn 2.0.87", 465 + ] 466 + 467 + [[package]] 468 + name = "futures-sink" 469 + version = "0.3.31" 470 + source = "registry+https://github.com/rust-lang/crates.io-index" 471 + checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 472 + 473 + [[package]] 474 + name = "futures-task" 475 + version = "0.3.31" 476 + source = "registry+https://github.com/rust-lang/crates.io-index" 477 + checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 478 + 479 + [[package]] 480 + name = "futures-util" 481 + version = "0.3.31" 482 + source = "registry+https://github.com/rust-lang/crates.io-index" 483 + checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 484 + dependencies = [ 485 + "futures-core", 486 + "futures-macro", 487 + "futures-sink", 488 + "futures-task", 489 + "pin-project-lite", 490 + "pin-utils", 491 + "slab", 492 + ] 493 + 494 + [[package]] 495 + name = "generic-array" 496 + version = "0.14.7" 497 + source = "registry+https://github.com/rust-lang/crates.io-index" 498 + checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 499 + dependencies = [ 500 + "typenum", 501 + "version_check", 502 + ] 503 + 504 + [[package]] 505 + name = "getrandom" 506 + version = "0.2.15" 507 + source = "registry+https://github.com/rust-lang/crates.io-index" 508 + checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 509 + dependencies = [ 510 + "cfg-if", 511 + "js-sys", 512 + "libc", 513 + "wasi", 514 + "wasm-bindgen", 515 + ] 516 + 517 + [[package]] 518 + name = "gimli" 519 + version = "0.31.1" 520 + source = "registry+https://github.com/rust-lang/crates.io-index" 521 + checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 522 + 523 + [[package]] 524 + name = "hashbrown" 525 + version = "0.15.1" 526 + source = "registry+https://github.com/rust-lang/crates.io-index" 527 + checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" 528 + 529 + [[package]] 530 + name = "heck" 531 + version = "0.5.0" 532 + source = "registry+https://github.com/rust-lang/crates.io-index" 533 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 534 + 535 + [[package]] 536 + name = "hermit-abi" 537 + version = "0.3.9" 538 + source = "registry+https://github.com/rust-lang/crates.io-index" 539 + checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 540 + 541 + [[package]] 542 + name = "http" 543 + version = "1.1.0" 544 + source = "registry+https://github.com/rust-lang/crates.io-index" 545 + checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 546 + dependencies = [ 547 + "bytes", 548 + "fnv", 549 + "itoa", 550 + ] 551 + 552 + [[package]] 553 + name = "httparse" 554 + version = "1.9.5" 555 + source = "registry+https://github.com/rust-lang/crates.io-index" 556 + checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 557 + 558 + [[package]] 559 + name = "iana-time-zone" 560 + version = "0.1.61" 561 + source = "registry+https://github.com/rust-lang/crates.io-index" 562 + checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 563 + dependencies = [ 564 + "android_system_properties", 565 + "core-foundation-sys", 566 + "iana-time-zone-haiku", 567 + "js-sys", 568 + "wasm-bindgen", 569 + "windows-core", 570 + ] 571 + 572 + [[package]] 573 + name = "iana-time-zone-haiku" 574 + version = "0.1.2" 575 + source = "registry+https://github.com/rust-lang/crates.io-index" 576 + checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 577 + dependencies = [ 578 + "cc", 579 + ] 580 + 581 + [[package]] 582 + name = "icu_collections" 583 + version = "1.5.0" 584 + source = "registry+https://github.com/rust-lang/crates.io-index" 585 + checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 586 + dependencies = [ 587 + "displaydoc", 588 + "yoke", 589 + "zerofrom", 590 + "zerovec", 591 + ] 592 + 593 + [[package]] 594 + name = "icu_locid" 595 + version = "1.5.0" 596 + source = "registry+https://github.com/rust-lang/crates.io-index" 597 + checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 598 + dependencies = [ 599 + "displaydoc", 600 + "litemap", 601 + "tinystr", 602 + "writeable", 603 + "zerovec", 604 + ] 605 + 606 + [[package]] 607 + name = "icu_locid_transform" 608 + version = "1.5.0" 609 + source = "registry+https://github.com/rust-lang/crates.io-index" 610 + checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 611 + dependencies = [ 612 + "displaydoc", 613 + "icu_locid", 614 + "icu_locid_transform_data", 615 + "icu_provider", 616 + "tinystr", 617 + "zerovec", 618 + ] 619 + 620 + [[package]] 621 + name = "icu_locid_transform_data" 622 + version = "1.5.0" 623 + source = "registry+https://github.com/rust-lang/crates.io-index" 624 + checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 625 + 626 + [[package]] 627 + name = "icu_normalizer" 628 + version = "1.5.0" 629 + source = "registry+https://github.com/rust-lang/crates.io-index" 630 + checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 631 + dependencies = [ 632 + "displaydoc", 633 + "icu_collections", 634 + "icu_normalizer_data", 635 + "icu_properties", 636 + "icu_provider", 637 + "smallvec", 638 + "utf16_iter", 639 + "utf8_iter", 640 + "write16", 641 + "zerovec", 642 + ] 643 + 644 + [[package]] 645 + name = "icu_normalizer_data" 646 + version = "1.5.0" 647 + source = "registry+https://github.com/rust-lang/crates.io-index" 648 + checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 649 + 650 + [[package]] 651 + name = "icu_properties" 652 + version = "1.5.1" 653 + source = "registry+https://github.com/rust-lang/crates.io-index" 654 + checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 655 + dependencies = [ 656 + "displaydoc", 657 + "icu_collections", 658 + "icu_locid_transform", 659 + "icu_properties_data", 660 + "icu_provider", 661 + "tinystr", 662 + "zerovec", 663 + ] 664 + 665 + [[package]] 666 + name = "icu_properties_data" 667 + version = "1.5.0" 668 + source = "registry+https://github.com/rust-lang/crates.io-index" 669 + checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 670 + 671 + [[package]] 672 + name = "icu_provider" 673 + version = "1.5.0" 674 + source = "registry+https://github.com/rust-lang/crates.io-index" 675 + checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 676 + dependencies = [ 677 + "displaydoc", 678 + "icu_locid", 679 + "icu_provider_macros", 680 + "stable_deref_trait", 681 + "tinystr", 682 + "writeable", 683 + "yoke", 684 + "zerofrom", 685 + "zerovec", 686 + ] 687 + 688 + [[package]] 689 + name = "icu_provider_macros" 690 + version = "1.5.0" 691 + source = "registry+https://github.com/rust-lang/crates.io-index" 692 + checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 693 + dependencies = [ 694 + "proc-macro2", 695 + "quote", 696 + "syn 2.0.87", 697 + ] 698 + 699 + [[package]] 700 + name = "idna" 701 + version = "1.0.3" 702 + source = "registry+https://github.com/rust-lang/crates.io-index" 703 + checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 704 + dependencies = [ 705 + "idna_adapter", 706 + "smallvec", 707 + "utf8_iter", 708 + ] 709 + 710 + [[package]] 711 + name = "idna_adapter" 712 + version = "1.2.0" 713 + source = "registry+https://github.com/rust-lang/crates.io-index" 714 + checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 715 + dependencies = [ 716 + "icu_normalizer", 717 + "icu_properties", 718 + ] 719 + 720 + [[package]] 721 + name = "indexmap" 722 + version = "2.6.0" 723 + source = "registry+https://github.com/rust-lang/crates.io-index" 724 + checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 725 + dependencies = [ 726 + "equivalent", 727 + "hashbrown", 728 + ] 729 + 730 + [[package]] 731 + name = "ipld-core" 732 + version = "0.4.1" 733 + source = "registry+https://github.com/rust-lang/crates.io-index" 734 + checksum = "b4ede82a79e134f179f4b29b5fdb1eb92bd1b38c4dfea394c539051150a21b9b" 735 + dependencies = [ 736 + "cid", 737 + "serde", 738 + "serde_bytes", 739 + ] 740 + 741 + [[package]] 742 + name = "is_terminal_polyfill" 743 + version = "1.70.1" 744 + source = "registry+https://github.com/rust-lang/crates.io-index" 745 + checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 746 + 747 + [[package]] 748 + name = "itoa" 749 + version = "1.0.11" 750 + source = "registry+https://github.com/rust-lang/crates.io-index" 751 + checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 752 + 753 + [[package]] 754 + name = "jetstream-oxide" 755 + version = "0.1.1" 756 + dependencies = [ 757 + "anyhow", 758 + "async-trait", 759 + "atrium-api", 760 + "chrono", 761 + "clap", 762 + "flume", 763 + "futures-util", 764 + "log", 765 + "serde", 766 + "serde_json", 767 + "thiserror 2.0.11", 768 + "tokio", 769 + "tokio-tungstenite", 770 + "tokio-util", 771 + "url", 772 + "zstd", 773 + ] 774 + 775 + [[package]] 776 + name = "jobserver" 777 + version = "0.1.32" 778 + source = "registry+https://github.com/rust-lang/crates.io-index" 779 + checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 780 + dependencies = [ 781 + "libc", 782 + ] 783 + 784 + [[package]] 785 + name = "js-sys" 786 + version = "0.3.72" 787 + source = "registry+https://github.com/rust-lang/crates.io-index" 788 + checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" 789 + dependencies = [ 790 + "wasm-bindgen", 791 + ] 792 + 793 + [[package]] 794 + name = "langtag" 795 + version = "0.3.4" 796 + source = "registry+https://github.com/rust-lang/crates.io-index" 797 + checksum = "ed60c85f254d6ae8450cec15eedd921efbc4d1bdf6fcf6202b9a58b403f6f805" 798 + dependencies = [ 799 + "serde", 800 + ] 801 + 802 + [[package]] 803 + name = "libc" 804 + version = "0.2.162" 805 + source = "registry+https://github.com/rust-lang/crates.io-index" 806 + checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" 807 + 808 + [[package]] 809 + name = "linux-raw-sys" 810 + version = "0.4.14" 811 + source = "registry+https://github.com/rust-lang/crates.io-index" 812 + checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 813 + 814 + [[package]] 815 + name = "litemap" 816 + version = "0.7.3" 817 + source = "registry+https://github.com/rust-lang/crates.io-index" 818 + checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" 819 + 820 + [[package]] 821 + name = "lock_api" 822 + version = "0.4.12" 823 + source = "registry+https://github.com/rust-lang/crates.io-index" 824 + checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 825 + dependencies = [ 826 + "autocfg", 827 + "scopeguard", 828 + ] 829 + 830 + [[package]] 831 + name = "log" 832 + version = "0.4.22" 833 + source = "registry+https://github.com/rust-lang/crates.io-index" 834 + checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 835 + 836 + [[package]] 837 + name = "memchr" 838 + version = "2.7.4" 839 + source = "registry+https://github.com/rust-lang/crates.io-index" 840 + checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 841 + 842 + [[package]] 843 + name = "miniz_oxide" 844 + version = "0.8.0" 845 + source = "registry+https://github.com/rust-lang/crates.io-index" 846 + checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 847 + dependencies = [ 848 + "adler2", 849 + ] 850 + 851 + [[package]] 852 + name = "mio" 853 + version = "1.0.2" 854 + source = "registry+https://github.com/rust-lang/crates.io-index" 855 + checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" 856 + dependencies = [ 857 + "hermit-abi", 858 + "libc", 859 + "wasi", 860 + "windows-sys 0.52.0", 861 + ] 862 + 863 + [[package]] 864 + name = "multibase" 865 + version = "0.9.1" 866 + source = "registry+https://github.com/rust-lang/crates.io-index" 867 + checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" 868 + dependencies = [ 869 + "base-x", 870 + "data-encoding", 871 + "data-encoding-macro", 872 + ] 873 + 874 + [[package]] 875 + name = "multihash" 876 + version = "0.19.2" 877 + source = "registry+https://github.com/rust-lang/crates.io-index" 878 + checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" 879 + dependencies = [ 880 + "core2", 881 + "serde", 882 + "unsigned-varint", 883 + ] 884 + 885 + [[package]] 886 + name = "nanorand" 887 + version = "0.7.0" 888 + source = "registry+https://github.com/rust-lang/crates.io-index" 889 + checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" 890 + dependencies = [ 891 + "getrandom", 892 + ] 893 + 894 + [[package]] 895 + name = "native-tls" 896 + version = "0.2.12" 897 + source = "registry+https://github.com/rust-lang/crates.io-index" 898 + checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 899 + dependencies = [ 900 + "libc", 901 + "log", 902 + "openssl", 903 + "openssl-probe", 904 + "openssl-sys", 905 + "schannel", 906 + "security-framework", 907 + "security-framework-sys", 908 + "tempfile", 909 + ] 910 + 911 + [[package]] 912 + name = "num-traits" 913 + version = "0.2.19" 914 + source = "registry+https://github.com/rust-lang/crates.io-index" 915 + checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 916 + dependencies = [ 917 + "autocfg", 918 + ] 919 + 920 + [[package]] 921 + name = "object" 922 + version = "0.36.5" 923 + source = "registry+https://github.com/rust-lang/crates.io-index" 924 + checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 925 + dependencies = [ 926 + "memchr", 927 + ] 928 + 929 + [[package]] 930 + name = "once_cell" 931 + version = "1.20.2" 932 + source = "registry+https://github.com/rust-lang/crates.io-index" 933 + checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 934 + 935 + [[package]] 936 + name = "openssl" 937 + version = "0.10.68" 938 + source = "registry+https://github.com/rust-lang/crates.io-index" 939 + checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" 940 + dependencies = [ 941 + "bitflags", 942 + "cfg-if", 943 + "foreign-types", 944 + "libc", 945 + "once_cell", 946 + "openssl-macros", 947 + "openssl-sys", 948 + ] 949 + 950 + [[package]] 951 + name = "openssl-macros" 952 + version = "0.1.1" 953 + source = "registry+https://github.com/rust-lang/crates.io-index" 954 + checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 955 + dependencies = [ 956 + "proc-macro2", 957 + "quote", 958 + "syn 2.0.87", 959 + ] 960 + 961 + [[package]] 962 + name = "openssl-probe" 963 + version = "0.1.5" 964 + source = "registry+https://github.com/rust-lang/crates.io-index" 965 + checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 966 + 967 + [[package]] 968 + name = "openssl-src" 969 + version = "300.4.0+3.4.0" 970 + source = "registry+https://github.com/rust-lang/crates.io-index" 971 + checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" 972 + dependencies = [ 973 + "cc", 974 + ] 975 + 976 + [[package]] 977 + name = "openssl-sys" 978 + version = "0.9.104" 979 + source = "registry+https://github.com/rust-lang/crates.io-index" 980 + checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" 981 + dependencies = [ 982 + "cc", 983 + "libc", 984 + "openssl-src", 985 + "pkg-config", 986 + "vcpkg", 987 + ] 988 + 989 + [[package]] 990 + name = "parking_lot" 991 + version = "0.12.3" 992 + source = "registry+https://github.com/rust-lang/crates.io-index" 993 + checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 994 + dependencies = [ 995 + "lock_api", 996 + "parking_lot_core", 997 + ] 998 + 999 + [[package]] 1000 + name = "parking_lot_core" 1001 + version = "0.9.10" 1002 + source = "registry+https://github.com/rust-lang/crates.io-index" 1003 + checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1004 + dependencies = [ 1005 + "cfg-if", 1006 + "libc", 1007 + "redox_syscall", 1008 + "smallvec", 1009 + "windows-targets", 1010 + ] 1011 + 1012 + [[package]] 1013 + name = "percent-encoding" 1014 + version = "2.3.1" 1015 + source = "registry+https://github.com/rust-lang/crates.io-index" 1016 + checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1017 + 1018 + [[package]] 1019 + name = "pin-project-lite" 1020 + version = "0.2.15" 1021 + source = "registry+https://github.com/rust-lang/crates.io-index" 1022 + checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 1023 + 1024 + [[package]] 1025 + name = "pin-utils" 1026 + version = "0.1.0" 1027 + source = "registry+https://github.com/rust-lang/crates.io-index" 1028 + checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1029 + 1030 + [[package]] 1031 + name = "pkg-config" 1032 + version = "0.3.31" 1033 + source = "registry+https://github.com/rust-lang/crates.io-index" 1034 + checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1035 + 1036 + [[package]] 1037 + name = "ppv-lite86" 1038 + version = "0.2.20" 1039 + source = "registry+https://github.com/rust-lang/crates.io-index" 1040 + checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1041 + dependencies = [ 1042 + "zerocopy", 1043 + ] 1044 + 1045 + [[package]] 1046 + name = "proc-macro2" 1047 + version = "1.0.89" 1048 + source = "registry+https://github.com/rust-lang/crates.io-index" 1049 + checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" 1050 + dependencies = [ 1051 + "unicode-ident", 1052 + ] 1053 + 1054 + [[package]] 1055 + name = "quote" 1056 + version = "1.0.37" 1057 + source = "registry+https://github.com/rust-lang/crates.io-index" 1058 + checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 1059 + dependencies = [ 1060 + "proc-macro2", 1061 + ] 1062 + 1063 + [[package]] 1064 + name = "rand" 1065 + version = "0.8.5" 1066 + source = "registry+https://github.com/rust-lang/crates.io-index" 1067 + checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1068 + dependencies = [ 1069 + "libc", 1070 + "rand_chacha", 1071 + "rand_core", 1072 + ] 1073 + 1074 + [[package]] 1075 + name = "rand_chacha" 1076 + version = "0.3.1" 1077 + source = "registry+https://github.com/rust-lang/crates.io-index" 1078 + checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1079 + dependencies = [ 1080 + "ppv-lite86", 1081 + "rand_core", 1082 + ] 1083 + 1084 + [[package]] 1085 + name = "rand_core" 1086 + version = "0.6.4" 1087 + source = "registry+https://github.com/rust-lang/crates.io-index" 1088 + checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1089 + dependencies = [ 1090 + "getrandom", 1091 + ] 1092 + 1093 + [[package]] 1094 + name = "redox_syscall" 1095 + version = "0.5.7" 1096 + source = "registry+https://github.com/rust-lang/crates.io-index" 1097 + checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" 1098 + dependencies = [ 1099 + "bitflags", 1100 + ] 1101 + 1102 + [[package]] 1103 + name = "regex" 1104 + version = "1.11.1" 1105 + source = "registry+https://github.com/rust-lang/crates.io-index" 1106 + checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1107 + dependencies = [ 1108 + "aho-corasick", 1109 + "memchr", 1110 + "regex-automata", 1111 + "regex-syntax", 1112 + ] 1113 + 1114 + [[package]] 1115 + name = "regex-automata" 1116 + version = "0.4.9" 1117 + source = "registry+https://github.com/rust-lang/crates.io-index" 1118 + checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1119 + dependencies = [ 1120 + "aho-corasick", 1121 + "memchr", 1122 + "regex-syntax", 1123 + ] 1124 + 1125 + [[package]] 1126 + name = "regex-syntax" 1127 + version = "0.8.5" 1128 + source = "registry+https://github.com/rust-lang/crates.io-index" 1129 + checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1130 + 1131 + [[package]] 1132 + name = "rustc-demangle" 1133 + version = "0.1.24" 1134 + source = "registry+https://github.com/rust-lang/crates.io-index" 1135 + checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1136 + 1137 + [[package]] 1138 + name = "rustix" 1139 + version = "0.38.40" 1140 + source = "registry+https://github.com/rust-lang/crates.io-index" 1141 + checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" 1142 + dependencies = [ 1143 + "bitflags", 1144 + "errno", 1145 + "libc", 1146 + "linux-raw-sys", 1147 + "windows-sys 0.52.0", 1148 + ] 1149 + 1150 + [[package]] 1151 + name = "ryu" 1152 + version = "1.0.18" 1153 + source = "registry+https://github.com/rust-lang/crates.io-index" 1154 + checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1155 + 1156 + [[package]] 1157 + name = "schannel" 1158 + version = "0.1.26" 1159 + source = "registry+https://github.com/rust-lang/crates.io-index" 1160 + checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" 1161 + dependencies = [ 1162 + "windows-sys 0.59.0", 1163 + ] 1164 + 1165 + [[package]] 1166 + name = "scopeguard" 1167 + version = "1.2.0" 1168 + source = "registry+https://github.com/rust-lang/crates.io-index" 1169 + checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1170 + 1171 + [[package]] 1172 + name = "security-framework" 1173 + version = "2.11.1" 1174 + source = "registry+https://github.com/rust-lang/crates.io-index" 1175 + checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1176 + dependencies = [ 1177 + "bitflags", 1178 + "core-foundation", 1179 + "core-foundation-sys", 1180 + "libc", 1181 + "security-framework-sys", 1182 + ] 1183 + 1184 + [[package]] 1185 + name = "security-framework-sys" 1186 + version = "2.12.1" 1187 + source = "registry+https://github.com/rust-lang/crates.io-index" 1188 + checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" 1189 + dependencies = [ 1190 + "core-foundation-sys", 1191 + "libc", 1192 + ] 1193 + 1194 + [[package]] 1195 + name = "serde" 1196 + version = "1.0.215" 1197 + source = "registry+https://github.com/rust-lang/crates.io-index" 1198 + checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" 1199 + dependencies = [ 1200 + "serde_derive", 1201 + ] 1202 + 1203 + [[package]] 1204 + name = "serde_bytes" 1205 + version = "0.11.15" 1206 + source = "registry+https://github.com/rust-lang/crates.io-index" 1207 + checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" 1208 + dependencies = [ 1209 + "serde", 1210 + ] 1211 + 1212 + [[package]] 1213 + name = "serde_derive" 1214 + version = "1.0.215" 1215 + source = "registry+https://github.com/rust-lang/crates.io-index" 1216 + checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" 1217 + dependencies = [ 1218 + "proc-macro2", 1219 + "quote", 1220 + "syn 2.0.87", 1221 + ] 1222 + 1223 + [[package]] 1224 + name = "serde_html_form" 1225 + version = "0.2.6" 1226 + source = "registry+https://github.com/rust-lang/crates.io-index" 1227 + checksum = "8de514ef58196f1fc96dcaef80fe6170a1ce6215df9687a93fe8300e773fefc5" 1228 + dependencies = [ 1229 + "form_urlencoded", 1230 + "indexmap", 1231 + "itoa", 1232 + "ryu", 1233 + "serde", 1234 + ] 1235 + 1236 + [[package]] 1237 + name = "serde_json" 1238 + version = "1.0.132" 1239 + source = "registry+https://github.com/rust-lang/crates.io-index" 1240 + checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" 1241 + dependencies = [ 1242 + "itoa", 1243 + "memchr", 1244 + "ryu", 1245 + "serde", 1246 + ] 1247 + 1248 + [[package]] 1249 + name = "sha1" 1250 + version = "0.10.6" 1251 + source = "registry+https://github.com/rust-lang/crates.io-index" 1252 + checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1253 + dependencies = [ 1254 + "cfg-if", 1255 + "cpufeatures", 1256 + "digest", 1257 + ] 1258 + 1259 + [[package]] 1260 + name = "shlex" 1261 + version = "1.3.0" 1262 + source = "registry+https://github.com/rust-lang/crates.io-index" 1263 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1264 + 1265 + [[package]] 1266 + name = "signal-hook-registry" 1267 + version = "1.4.2" 1268 + source = "registry+https://github.com/rust-lang/crates.io-index" 1269 + checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1270 + dependencies = [ 1271 + "libc", 1272 + ] 1273 + 1274 + [[package]] 1275 + name = "slab" 1276 + version = "0.4.9" 1277 + source = "registry+https://github.com/rust-lang/crates.io-index" 1278 + checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1279 + dependencies = [ 1280 + "autocfg", 1281 + ] 1282 + 1283 + [[package]] 1284 + name = "smallvec" 1285 + version = "1.13.2" 1286 + source = "registry+https://github.com/rust-lang/crates.io-index" 1287 + checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1288 + 1289 + [[package]] 1290 + name = "socket2" 1291 + version = "0.5.7" 1292 + source = "registry+https://github.com/rust-lang/crates.io-index" 1293 + checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1294 + dependencies = [ 1295 + "libc", 1296 + "windows-sys 0.52.0", 1297 + ] 1298 + 1299 + [[package]] 1300 + name = "spin" 1301 + version = "0.9.8" 1302 + source = "registry+https://github.com/rust-lang/crates.io-index" 1303 + checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1304 + dependencies = [ 1305 + "lock_api", 1306 + ] 1307 + 1308 + [[package]] 1309 + name = "stable_deref_trait" 1310 + version = "1.2.0" 1311 + source = "registry+https://github.com/rust-lang/crates.io-index" 1312 + checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1313 + 1314 + [[package]] 1315 + name = "strsim" 1316 + version = "0.11.1" 1317 + source = "registry+https://github.com/rust-lang/crates.io-index" 1318 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1319 + 1320 + [[package]] 1321 + name = "syn" 1322 + version = "1.0.109" 1323 + source = "registry+https://github.com/rust-lang/crates.io-index" 1324 + checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1325 + dependencies = [ 1326 + "proc-macro2", 1327 + "quote", 1328 + "unicode-ident", 1329 + ] 1330 + 1331 + [[package]] 1332 + name = "syn" 1333 + version = "2.0.87" 1334 + source = "registry+https://github.com/rust-lang/crates.io-index" 1335 + checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" 1336 + dependencies = [ 1337 + "proc-macro2", 1338 + "quote", 1339 + "unicode-ident", 1340 + ] 1341 + 1342 + [[package]] 1343 + name = "synstructure" 1344 + version = "0.13.1" 1345 + source = "registry+https://github.com/rust-lang/crates.io-index" 1346 + checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1347 + dependencies = [ 1348 + "proc-macro2", 1349 + "quote", 1350 + "syn 2.0.87", 1351 + ] 1352 + 1353 + [[package]] 1354 + name = "tempfile" 1355 + version = "3.14.0" 1356 + source = "registry+https://github.com/rust-lang/crates.io-index" 1357 + checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" 1358 + dependencies = [ 1359 + "cfg-if", 1360 + "fastrand", 1361 + "once_cell", 1362 + "rustix", 1363 + "windows-sys 0.59.0", 1364 + ] 1365 + 1366 + [[package]] 1367 + name = "thiserror" 1368 + version = "1.0.69" 1369 + source = "registry+https://github.com/rust-lang/crates.io-index" 1370 + checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1371 + dependencies = [ 1372 + "thiserror-impl 1.0.69", 1373 + ] 1374 + 1375 + [[package]] 1376 + name = "thiserror" 1377 + version = "2.0.11" 1378 + source = "registry+https://github.com/rust-lang/crates.io-index" 1379 + checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" 1380 + dependencies = [ 1381 + "thiserror-impl 2.0.11", 1382 + ] 1383 + 1384 + [[package]] 1385 + name = "thiserror-impl" 1386 + version = "1.0.69" 1387 + source = "registry+https://github.com/rust-lang/crates.io-index" 1388 + checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1389 + dependencies = [ 1390 + "proc-macro2", 1391 + "quote", 1392 + "syn 2.0.87", 1393 + ] 1394 + 1395 + [[package]] 1396 + name = "thiserror-impl" 1397 + version = "2.0.11" 1398 + source = "registry+https://github.com/rust-lang/crates.io-index" 1399 + checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" 1400 + dependencies = [ 1401 + "proc-macro2", 1402 + "quote", 1403 + "syn 2.0.87", 1404 + ] 1405 + 1406 + [[package]] 1407 + name = "tinystr" 1408 + version = "0.7.6" 1409 + source = "registry+https://github.com/rust-lang/crates.io-index" 1410 + checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 1411 + dependencies = [ 1412 + "displaydoc", 1413 + "zerovec", 1414 + ] 1415 + 1416 + [[package]] 1417 + name = "tokio" 1418 + version = "1.41.1" 1419 + source = "registry+https://github.com/rust-lang/crates.io-index" 1420 + checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" 1421 + dependencies = [ 1422 + "backtrace", 1423 + "bytes", 1424 + "libc", 1425 + "mio", 1426 + "parking_lot", 1427 + "pin-project-lite", 1428 + "signal-hook-registry", 1429 + "socket2", 1430 + "tokio-macros", 1431 + "windows-sys 0.52.0", 1432 + ] 1433 + 1434 + [[package]] 1435 + name = "tokio-macros" 1436 + version = "2.4.0" 1437 + source = "registry+https://github.com/rust-lang/crates.io-index" 1438 + checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" 1439 + dependencies = [ 1440 + "proc-macro2", 1441 + "quote", 1442 + "syn 2.0.87", 1443 + ] 1444 + 1445 + [[package]] 1446 + name = "tokio-native-tls" 1447 + version = "0.3.1" 1448 + source = "registry+https://github.com/rust-lang/crates.io-index" 1449 + checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1450 + dependencies = [ 1451 + "native-tls", 1452 + "tokio", 1453 + ] 1454 + 1455 + [[package]] 1456 + name = "tokio-tungstenite" 1457 + version = "0.24.0" 1458 + source = "registry+https://github.com/rust-lang/crates.io-index" 1459 + checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" 1460 + dependencies = [ 1461 + "futures-util", 1462 + "log", 1463 + "native-tls", 1464 + "tokio", 1465 + "tokio-native-tls", 1466 + "tungstenite", 1467 + ] 1468 + 1469 + [[package]] 1470 + name = "tokio-util" 1471 + version = "0.7.13" 1472 + source = "registry+https://github.com/rust-lang/crates.io-index" 1473 + checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 1474 + dependencies = [ 1475 + "bytes", 1476 + "futures-core", 1477 + "futures-sink", 1478 + "pin-project-lite", 1479 + "tokio", 1480 + ] 1481 + 1482 + [[package]] 1483 + name = "trait-variant" 1484 + version = "0.1.2" 1485 + source = "registry+https://github.com/rust-lang/crates.io-index" 1486 + checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" 1487 + dependencies = [ 1488 + "proc-macro2", 1489 + "quote", 1490 + "syn 2.0.87", 1491 + ] 1492 + 1493 + [[package]] 1494 + name = "tungstenite" 1495 + version = "0.24.0" 1496 + source = "registry+https://github.com/rust-lang/crates.io-index" 1497 + checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" 1498 + dependencies = [ 1499 + "byteorder", 1500 + "bytes", 1501 + "data-encoding", 1502 + "http", 1503 + "httparse", 1504 + "log", 1505 + "native-tls", 1506 + "rand", 1507 + "sha1", 1508 + "thiserror 1.0.69", 1509 + "url", 1510 + "utf-8", 1511 + ] 1512 + 1513 + [[package]] 1514 + name = "typenum" 1515 + version = "1.17.0" 1516 + source = "registry+https://github.com/rust-lang/crates.io-index" 1517 + checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1518 + 1519 + [[package]] 1520 + name = "unicode-ident" 1521 + version = "1.0.13" 1522 + source = "registry+https://github.com/rust-lang/crates.io-index" 1523 + checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 1524 + 1525 + [[package]] 1526 + name = "unsigned-varint" 1527 + version = "0.8.0" 1528 + source = "registry+https://github.com/rust-lang/crates.io-index" 1529 + checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" 1530 + 1531 + [[package]] 1532 + name = "url" 1533 + version = "2.5.4" 1534 + source = "registry+https://github.com/rust-lang/crates.io-index" 1535 + checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1536 + dependencies = [ 1537 + "form_urlencoded", 1538 + "idna", 1539 + "percent-encoding", 1540 + ] 1541 + 1542 + [[package]] 1543 + name = "utf-8" 1544 + version = "0.7.6" 1545 + source = "registry+https://github.com/rust-lang/crates.io-index" 1546 + checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1547 + 1548 + [[package]] 1549 + name = "utf16_iter" 1550 + version = "1.0.5" 1551 + source = "registry+https://github.com/rust-lang/crates.io-index" 1552 + checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 1553 + 1554 + [[package]] 1555 + name = "utf8_iter" 1556 + version = "1.0.4" 1557 + source = "registry+https://github.com/rust-lang/crates.io-index" 1558 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1559 + 1560 + [[package]] 1561 + name = "utf8parse" 1562 + version = "0.2.2" 1563 + source = "registry+https://github.com/rust-lang/crates.io-index" 1564 + checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1565 + 1566 + [[package]] 1567 + name = "vcpkg" 1568 + version = "0.2.15" 1569 + source = "registry+https://github.com/rust-lang/crates.io-index" 1570 + checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1571 + 1572 + [[package]] 1573 + name = "version_check" 1574 + version = "0.9.5" 1575 + source = "registry+https://github.com/rust-lang/crates.io-index" 1576 + checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1577 + 1578 + [[package]] 1579 + name = "wasi" 1580 + version = "0.11.0+wasi-snapshot-preview1" 1581 + source = "registry+https://github.com/rust-lang/crates.io-index" 1582 + checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1583 + 1584 + [[package]] 1585 + name = "wasm-bindgen" 1586 + version = "0.2.95" 1587 + source = "registry+https://github.com/rust-lang/crates.io-index" 1588 + checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" 1589 + dependencies = [ 1590 + "cfg-if", 1591 + "once_cell", 1592 + "wasm-bindgen-macro", 1593 + ] 1594 + 1595 + [[package]] 1596 + name = "wasm-bindgen-backend" 1597 + version = "0.2.95" 1598 + source = "registry+https://github.com/rust-lang/crates.io-index" 1599 + checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" 1600 + dependencies = [ 1601 + "bumpalo", 1602 + "log", 1603 + "once_cell", 1604 + "proc-macro2", 1605 + "quote", 1606 + "syn 2.0.87", 1607 + "wasm-bindgen-shared", 1608 + ] 1609 + 1610 + [[package]] 1611 + name = "wasm-bindgen-macro" 1612 + version = "0.2.95" 1613 + source = "registry+https://github.com/rust-lang/crates.io-index" 1614 + checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" 1615 + dependencies = [ 1616 + "quote", 1617 + "wasm-bindgen-macro-support", 1618 + ] 1619 + 1620 + [[package]] 1621 + name = "wasm-bindgen-macro-support" 1622 + version = "0.2.95" 1623 + source = "registry+https://github.com/rust-lang/crates.io-index" 1624 + checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" 1625 + dependencies = [ 1626 + "proc-macro2", 1627 + "quote", 1628 + "syn 2.0.87", 1629 + "wasm-bindgen-backend", 1630 + "wasm-bindgen-shared", 1631 + ] 1632 + 1633 + [[package]] 1634 + name = "wasm-bindgen-shared" 1635 + version = "0.2.95" 1636 + source = "registry+https://github.com/rust-lang/crates.io-index" 1637 + checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" 1638 + 1639 + [[package]] 1640 + name = "windows-core" 1641 + version = "0.52.0" 1642 + source = "registry+https://github.com/rust-lang/crates.io-index" 1643 + checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1644 + dependencies = [ 1645 + "windows-targets", 1646 + ] 1647 + 1648 + [[package]] 1649 + name = "windows-sys" 1650 + version = "0.52.0" 1651 + source = "registry+https://github.com/rust-lang/crates.io-index" 1652 + checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1653 + dependencies = [ 1654 + "windows-targets", 1655 + ] 1656 + 1657 + [[package]] 1658 + name = "windows-sys" 1659 + version = "0.59.0" 1660 + source = "registry+https://github.com/rust-lang/crates.io-index" 1661 + checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1662 + dependencies = [ 1663 + "windows-targets", 1664 + ] 1665 + 1666 + [[package]] 1667 + name = "windows-targets" 1668 + version = "0.52.6" 1669 + source = "registry+https://github.com/rust-lang/crates.io-index" 1670 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1671 + dependencies = [ 1672 + "windows_aarch64_gnullvm", 1673 + "windows_aarch64_msvc", 1674 + "windows_i686_gnu", 1675 + "windows_i686_gnullvm", 1676 + "windows_i686_msvc", 1677 + "windows_x86_64_gnu", 1678 + "windows_x86_64_gnullvm", 1679 + "windows_x86_64_msvc", 1680 + ] 1681 + 1682 + [[package]] 1683 + name = "windows_aarch64_gnullvm" 1684 + version = "0.52.6" 1685 + source = "registry+https://github.com/rust-lang/crates.io-index" 1686 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1687 + 1688 + [[package]] 1689 + name = "windows_aarch64_msvc" 1690 + version = "0.52.6" 1691 + source = "registry+https://github.com/rust-lang/crates.io-index" 1692 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1693 + 1694 + [[package]] 1695 + name = "windows_i686_gnu" 1696 + version = "0.52.6" 1697 + source = "registry+https://github.com/rust-lang/crates.io-index" 1698 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1699 + 1700 + [[package]] 1701 + name = "windows_i686_gnullvm" 1702 + version = "0.52.6" 1703 + source = "registry+https://github.com/rust-lang/crates.io-index" 1704 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1705 + 1706 + [[package]] 1707 + name = "windows_i686_msvc" 1708 + version = "0.52.6" 1709 + source = "registry+https://github.com/rust-lang/crates.io-index" 1710 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1711 + 1712 + [[package]] 1713 + name = "windows_x86_64_gnu" 1714 + version = "0.52.6" 1715 + source = "registry+https://github.com/rust-lang/crates.io-index" 1716 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1717 + 1718 + [[package]] 1719 + name = "windows_x86_64_gnullvm" 1720 + version = "0.52.6" 1721 + source = "registry+https://github.com/rust-lang/crates.io-index" 1722 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1723 + 1724 + [[package]] 1725 + name = "windows_x86_64_msvc" 1726 + version = "0.52.6" 1727 + source = "registry+https://github.com/rust-lang/crates.io-index" 1728 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1729 + 1730 + [[package]] 1731 + name = "write16" 1732 + version = "1.0.0" 1733 + source = "registry+https://github.com/rust-lang/crates.io-index" 1734 + checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 1735 + 1736 + [[package]] 1737 + name = "writeable" 1738 + version = "0.5.5" 1739 + source = "registry+https://github.com/rust-lang/crates.io-index" 1740 + checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 1741 + 1742 + [[package]] 1743 + name = "yoke" 1744 + version = "0.7.4" 1745 + source = "registry+https://github.com/rust-lang/crates.io-index" 1746 + checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" 1747 + dependencies = [ 1748 + "serde", 1749 + "stable_deref_trait", 1750 + "yoke-derive", 1751 + "zerofrom", 1752 + ] 1753 + 1754 + [[package]] 1755 + name = "yoke-derive" 1756 + version = "0.7.4" 1757 + source = "registry+https://github.com/rust-lang/crates.io-index" 1758 + checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" 1759 + dependencies = [ 1760 + "proc-macro2", 1761 + "quote", 1762 + "syn 2.0.87", 1763 + "synstructure", 1764 + ] 1765 + 1766 + [[package]] 1767 + name = "zerocopy" 1768 + version = "0.7.35" 1769 + source = "registry+https://github.com/rust-lang/crates.io-index" 1770 + checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1771 + dependencies = [ 1772 + "byteorder", 1773 + "zerocopy-derive", 1774 + ] 1775 + 1776 + [[package]] 1777 + name = "zerocopy-derive" 1778 + version = "0.7.35" 1779 + source = "registry+https://github.com/rust-lang/crates.io-index" 1780 + checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1781 + dependencies = [ 1782 + "proc-macro2", 1783 + "quote", 1784 + "syn 2.0.87", 1785 + ] 1786 + 1787 + [[package]] 1788 + name = "zerofrom" 1789 + version = "0.1.4" 1790 + source = "registry+https://github.com/rust-lang/crates.io-index" 1791 + checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" 1792 + dependencies = [ 1793 + "zerofrom-derive", 1794 + ] 1795 + 1796 + [[package]] 1797 + name = "zerofrom-derive" 1798 + version = "0.1.4" 1799 + source = "registry+https://github.com/rust-lang/crates.io-index" 1800 + checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" 1801 + dependencies = [ 1802 + "proc-macro2", 1803 + "quote", 1804 + "syn 2.0.87", 1805 + "synstructure", 1806 + ] 1807 + 1808 + [[package]] 1809 + name = "zerovec" 1810 + version = "0.10.4" 1811 + source = "registry+https://github.com/rust-lang/crates.io-index" 1812 + checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 1813 + dependencies = [ 1814 + "yoke", 1815 + "zerofrom", 1816 + "zerovec-derive", 1817 + ] 1818 + 1819 + [[package]] 1820 + name = "zerovec-derive" 1821 + version = "0.10.3" 1822 + source = "registry+https://github.com/rust-lang/crates.io-index" 1823 + checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 1824 + dependencies = [ 1825 + "proc-macro2", 1826 + "quote", 1827 + "syn 2.0.87", 1828 + ] 1829 + 1830 + [[package]] 1831 + name = "zstd" 1832 + version = "0.13.2" 1833 + source = "registry+https://github.com/rust-lang/crates.io-index" 1834 + checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" 1835 + dependencies = [ 1836 + "zstd-safe", 1837 + ] 1838 + 1839 + [[package]] 1840 + name = "zstd-safe" 1841 + version = "7.2.1" 1842 + source = "registry+https://github.com/rust-lang/crates.io-index" 1843 + checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" 1844 + dependencies = [ 1845 + "zstd-sys", 1846 + ] 1847 + 1848 + [[package]] 1849 + name = "zstd-sys" 1850 + version = "2.0.13+zstd.1.5.6" 1851 + source = "registry+https://github.com/rust-lang/crates.io-index" 1852 + checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" 1853 + dependencies = [ 1854 + "cc", 1855 + "pkg-config", 1856 + ]
+35
jetstream/Cargo.toml
··· 1 + [package] 2 + authors = ["videah <videah@selfish.systems>"] 3 + name = "jetstream-oxide" 4 + version = "0.1.1" 5 + edition = "2021" 6 + license = "MIT" 7 + description = "Library for easily interacting with and consuming the Bluesky Jetstream service." 8 + repository = "https://github.com/videah/jetstream-oxide" 9 + readme = "README.md" 10 + 11 + [dependencies] 12 + async-trait = "0.1.83" 13 + atrium-api = { version = "0.24.7", default-features = false, features = [ 14 + "namespace-appbsky", 15 + ] } 16 + tokio = { version = "1.41.1", features = ["full", "sync", "time"] } 17 + tokio-tungstenite = { version = "0.24.0", features = [ 18 + "connect", 19 + "native-tls-vendored", 20 + "url", 21 + ] } 22 + futures-util = "0.3.31" 23 + url = "2.5.4" 24 + serde = { version = "1.0.215", features = ["derive"] } 25 + serde_json = "1.0.132" 26 + chrono = "0.4.38" 27 + zstd = "0.13.2" 28 + thiserror = "2.0.3" 29 + flume = "0.11.1" 30 + log = "0.4.22" 31 + tokio-util = "0.7.13" 32 + 33 + [dev-dependencies] 34 + anyhow = "1.0.93" 35 + clap = { version = "4.5.20", features = ["derive"] }
+21
jetstream/LICENSE
··· 1 + MIT License 2 + 3 + Copyright (c) 2024 videah 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+59
jetstream/README.md
··· 1 + # jetstream-oxide 2 + 3 + [![Crate](https://img.shields.io/crates/v/jetstream-oxide.svg)](https://crates.io/crates/jetstream-oxide) 4 + [![docs.rs](https://docs.rs/jetstream-oxide/badge.svg)](https://docs.rs/jetstream-oxide/latest/jetstream_oxide) 5 + 6 + A typed Rust library for easily interacting with and consuming the 7 + Bluesky [Jetstream](https://github.com/bluesky-social/jetstream) 8 + service. 9 + 10 + ```rust 11 + let config = JetstreamConfig { 12 + endpoint: DefaultJetstreamEndpoints::USEastOne.into(), 13 + compression: JetstreamCompression::Zstd, 14 + ..Default::default() 15 + }; 16 + 17 + let jetstream = JetstreamConnector::new(config).unwrap(); 18 + let receiver = jetstream.connect().await?; 19 + 20 + while let Ok(event) = receiver.recv_async().await { 21 + if let Commit(commit) = event { 22 + match commit { 23 + CommitEvent::Create { info, commit } => { 24 + println!("Received create event: {:#?}", info); 25 + } 26 + CommitEvent::Update { info, commit } => { 27 + println!("Received update event: {:#?}", info); 28 + } 29 + CommitEvent::Delete { info, commit } => { 30 + println!("Received delete event: {:#?}", info); 31 + } 32 + } 33 + } 34 + } 35 + ``` 36 + 37 + ## Example 38 + 39 + A small example CLI utility to show how to use this crate can be found in the `examples` directory. To run it, use the 40 + following command: 41 + 42 + ```sh 43 + cargo run --example basic -- --nsid "app.bsky.feed.post" 44 + ``` 45 + 46 + This will display a real-time feed of every single post that is being made or deleted in the entire Bluesky network, 47 + right in your terminal! 48 + 49 + You can filter it down to just specific accounts like this: 50 + 51 + ```sh 52 + cargo run --example basic -- \ 53 + --nsid "app.bsky.feed.post" \ 54 + --did "did:plc:inze6wrmsm7pjl7yta3oig77" 55 + ``` 56 + 57 + This listens for posts that *I personally make*. You can substitute your own DID and make a few test posts yourself if 58 + you'd 59 + like of course!
+63
jetstream/examples/basic.rs
··· 1 + //! A very basic example of how to listen for create/delete events on a specific DID and NSID. 2 + 3 + use atrium_api::{record::KnownRecord::AppBskyFeedPost, types::string}; 4 + use clap::Parser; 5 + use jetstream_oxide::{ 6 + events::{commit::CommitEvent, JetstreamEvent::Commit}, 7 + DefaultJetstreamEndpoints, JetstreamCompression, JetstreamConfig, JetstreamConnector, 8 + }; 9 + 10 + #[derive(Parser, Debug)] 11 + #[command(version, about, long_about = None)] 12 + struct Args { 13 + /// The DIDs to listen for events on, if not provided we will listen for all DIDs. 14 + #[arg(short, long)] 15 + did: Option<Vec<string::Did>>, 16 + /// The NSID for the collection to listen for (e.g. `app.bsky.feed.post`). 17 + #[arg(short, long)] 18 + nsid: string::Nsid, 19 + } 20 + 21 + #[tokio::main] 22 + async fn main() -> anyhow::Result<()> { 23 + let args = Args::parse(); 24 + 25 + let dids = args.did.unwrap_or_default(); 26 + let config = JetstreamConfig { 27 + endpoint: DefaultJetstreamEndpoints::USEastOne.into(), 28 + wanted_collections: vec![args.nsid.clone()], 29 + wanted_dids: dids.clone(), 30 + compression: JetstreamCompression::Zstd, 31 + cursor: None, 32 + }; 33 + 34 + let jetstream = JetstreamConnector::new(config)?; 35 + let receiver = jetstream.connect().await?; 36 + 37 + println!( 38 + "Listening for '{}' events on DIDs: {:?}", 39 + args.nsid.to_string(), 40 + dids, 41 + ); 42 + 43 + while let Ok(event) = receiver.recv_async().await { 44 + if let Commit(commit) = event { 45 + match commit { 46 + CommitEvent::Create { info: _, commit } => { 47 + if let AppBskyFeedPost(record) = commit.record { 48 + println!( 49 + "New post created! ({})\n\n'{}'", 50 + commit.info.rkey, record.text 51 + ); 52 + } 53 + } 54 + CommitEvent::Delete { info: _, commit } => { 55 + println!("A post has been deleted. ({})", commit.rkey); 56 + } 57 + _ => {} 58 + } 59 + } 60 + } 61 + 62 + Ok(()) 63 + }
+6
jetstream/rustfmt.toml
··· 1 + group_imports = "StdExternalCrate" 2 + comment_width = 100 3 + format_code_in_doc_comments = true 4 + imports_granularity = "Crate" 5 + imports_layout = "Vertical" 6 + wrap_comments = true
+43
jetstream/src/error.rs
··· 1 + //! Various error types. 2 + use std::io; 3 + 4 + use thiserror::Error; 5 + 6 + /// Possible errors that can occur when a [JetstreamConfig](crate::JetstreamConfig) that is passed 7 + /// to a [JetstreamConnector](crate::JetstreamConnector) is invalid. 8 + #[derive(Error, Debug)] 9 + pub enum ConfigValidationError { 10 + #[error("too many wanted collections: {0} > 100")] 11 + TooManyWantedCollections(usize), 12 + #[error("too many wanted DIDs: {0} > 10,000")] 13 + TooManyDids(usize), 14 + } 15 + 16 + /// Possible errors that can occur in the process of connecting to a Jetstream instance over 17 + /// WebSockets. 18 + /// 19 + /// See [JetstreamConnector::connect](crate::JetstreamConnector::connect). 20 + #[derive(Error, Debug)] 21 + pub enum ConnectionError { 22 + #[error("invalid endpoint: {0}")] 23 + InvalidEndpoint(#[from] url::ParseError), 24 + #[error("failed to connect to Jetstream instance: {0}")] 25 + WebSocketFailure(#[from] tokio_tungstenite::tungstenite::Error), 26 + #[error("the Jetstream config is invalid (this really should not happen here): {0}")] 27 + InvalidConfig(#[from] ConfigValidationError), 28 + } 29 + 30 + /// Possible errors that can occur when receiving events from a Jetstream instance over WebSockets. 31 + /// 32 + /// See [websocket_task](crate::websocket_task). 33 + #[derive(Error, Debug)] 34 + pub enum JetstreamEventError { 35 + #[error("received websocket message that could not be deserialized as JSON: {0}")] 36 + ReceivedMalformedJSON(#[from] serde_json::Error), 37 + #[error("failed to load built-in zstd dictionary for decoding: {0}")] 38 + CompressionDictionaryError(io::Error), 39 + #[error("failed to decode zstd-compressed message: {0}")] 40 + CompressionDecoderError(io::Error), 41 + #[error("all receivers were dropped but the websocket connection failed to close cleanly")] 42 + WebSocketCloseFailure, 43 + }
+40
jetstream/src/events/account.rs
··· 1 + use chrono::Utc; 2 + use serde::Deserialize; 3 + 4 + use crate::{ 5 + events::EventInfo, 6 + exports, 7 + }; 8 + 9 + /// An event representing a change to an account. 10 + #[derive(Deserialize, Debug)] 11 + pub struct AccountEvent { 12 + /// Basic metadata included with every event. 13 + #[serde(flatten)] 14 + pub info: EventInfo, 15 + /// Account specific data bundled with this event. 16 + pub account: AccountData, 17 + } 18 + 19 + /// Account specific data bundled with an account event. 20 + #[derive(Deserialize, Debug)] 21 + pub struct AccountData { 22 + /// Whether the account is currently active. 23 + pub active: bool, 24 + /// The DID of the account. 25 + pub did: exports::Did, 26 + pub seq: u64, 27 + pub time: chrono::DateTime<Utc>, 28 + /// If `active` is `false` this will be present to explain why the account is inactive. 29 + pub status: Option<AccountStatus>, 30 + } 31 + 32 + /// The possible reasons an account might be listed as inactive. 33 + #[derive(Deserialize, Debug)] 34 + #[serde(rename_all = "lowercase")] 35 + pub enum AccountStatus { 36 + Deactivated, 37 + Deleted, 38 + Suspended, 39 + TakenDown, 40 + }
+61
jetstream/src/events/commit.rs
··· 1 + use atrium_api::record::KnownRecord; 2 + use serde::Deserialize; 3 + 4 + use crate::{ 5 + events::EventInfo, 6 + exports, 7 + }; 8 + 9 + /// An event representing a repo commit, which can be a `create`, `update`, or `delete` operation. 10 + #[derive(Deserialize, Debug)] 11 + #[serde(untagged, rename_all = "snake_case")] 12 + pub enum CommitEvent { 13 + Create { 14 + #[serde(flatten)] 15 + info: EventInfo, 16 + commit: CommitData, 17 + }, 18 + Update { 19 + #[serde(flatten)] 20 + info: EventInfo, 21 + commit: CommitData, 22 + }, 23 + Delete { 24 + #[serde(flatten)] 25 + info: EventInfo, 26 + commit: CommitInfo, 27 + }, 28 + } 29 + 30 + /// The type of commit operation that was performed. 31 + #[derive(Deserialize, Debug)] 32 + #[serde(rename_all = "snake_case")] 33 + pub enum CommitType { 34 + Create, 35 + Update, 36 + Delete, 37 + } 38 + 39 + /// Basic commit specific info bundled with every event, also the only data included with a `delete` 40 + /// operation. 41 + #[derive(Deserialize, Debug)] 42 + pub struct CommitInfo { 43 + /// The type of commit operation that was performed. 44 + pub operation: CommitType, 45 + pub rev: String, 46 + pub rkey: String, 47 + /// The NSID of the record type that this commit is associated with. 48 + pub collection: exports::Nsid, 49 + } 50 + 51 + /// Detailed data bundled with a commit event. This data is only included when the event is 52 + /// `create` or `update`. 53 + #[derive(Deserialize, Debug)] 54 + pub struct CommitData { 55 + #[serde(flatten)] 56 + pub info: CommitInfo, 57 + /// The CID of the record that was operated on. 58 + pub cid: exports::Cid, 59 + /// The record that was operated on. 60 + pub record: KnownRecord, 61 + }
+28
jetstream/src/events/identity.rs
··· 1 + use chrono::Utc; 2 + use serde::Deserialize; 3 + 4 + use crate::{ 5 + events::EventInfo, 6 + exports, 7 + }; 8 + 9 + /// An event representing a change to an identity. 10 + #[derive(Deserialize, Debug)] 11 + pub struct IdentityEvent { 12 + /// Basic metadata included with every event. 13 + #[serde(flatten)] 14 + pub info: EventInfo, 15 + /// Identity specific data bundled with this event. 16 + pub identity: IdentityData, 17 + } 18 + 19 + /// Identity specific data bundled with an identity event. 20 + #[derive(Deserialize, Debug)] 21 + pub struct IdentityData { 22 + /// The DID of the identity. 23 + pub did: exports::Did, 24 + /// The handle associated with the identity. 25 + pub handle: Option<exports::Handle>, 26 + pub seq: u64, 27 + pub time: chrono::DateTime<Utc>, 28 + }
+31
jetstream/src/events/mod.rs
··· 1 + pub mod account; 2 + pub mod commit; 3 + pub mod identity; 4 + 5 + use serde::Deserialize; 6 + 7 + use crate::exports; 8 + 9 + /// Basic data that is included with every event. 10 + #[derive(Deserialize, Debug)] 11 + pub struct EventInfo { 12 + pub did: exports::Did, 13 + pub time_us: u64, 14 + pub kind: EventKind, 15 + } 16 + 17 + #[derive(Deserialize, Debug)] 18 + #[serde(untagged)] 19 + pub enum JetstreamEvent { 20 + Commit(commit::CommitEvent), 21 + Identity(identity::IdentityEvent), 22 + Account(account::AccountEvent), 23 + } 24 + 25 + #[derive(Deserialize, Debug)] 26 + #[serde(rename_all = "snake_case")] 27 + pub enum EventKind { 28 + Commit, 29 + Identity, 30 + Account, 31 + }
+8
jetstream/src/exports.rs
··· 1 + //! Useful exports for third-party crates used by this project. 2 + 3 + pub use atrium_api::types::string::{ 4 + Cid, 5 + Did, 6 + Handle, 7 + Nsid, 8 + };
+367
jetstream/src/lib.rs
··· 1 + pub mod error; 2 + pub mod events; 3 + pub mod exports; 4 + 5 + use std::{ 6 + io::{Cursor, Read}, 7 + sync::Arc, 8 + time::Duration, 9 + }; 10 + 11 + use chrono::Utc; 12 + use futures_util::{stream::StreamExt, SinkExt}; 13 + use tokio::{net::TcpStream, sync::Mutex}; 14 + use tokio_tungstenite::{connect_async, tungstenite::Message, MaybeTlsStream, WebSocketStream}; 15 + use tokio_util::sync::CancellationToken; 16 + use url::Url; 17 + use zstd::dict::DecoderDictionary; 18 + 19 + use crate::{ 20 + error::{ConfigValidationError, ConnectionError, JetstreamEventError}, 21 + events::JetstreamEvent, 22 + }; 23 + 24 + /// The Jetstream endpoints officially provided by Bluesky themselves. 25 + /// 26 + /// There are no guarantees that these endpoints will always be available, but you are free 27 + /// to run your own Jetstream instance in any case. 28 + pub enum DefaultJetstreamEndpoints { 29 + /// `jetstream1.us-east.bsky.network` 30 + USEastOne, 31 + /// `jetstream2.us-east.bsky.network` 32 + USEastTwo, 33 + /// `jetstream1.us-west.bsky.network` 34 + USWestOne, 35 + /// `jetstream2.us-west.bsky.network` 36 + USWestTwo, 37 + } 38 + 39 + impl From<DefaultJetstreamEndpoints> for String { 40 + fn from(endpoint: DefaultJetstreamEndpoints) -> Self { 41 + match endpoint { 42 + DefaultJetstreamEndpoints::USEastOne => { 43 + "wss://jetstream1.us-east.bsky.network/subscribe".to_owned() 44 + } 45 + DefaultJetstreamEndpoints::USEastTwo => { 46 + "wss://jetstream2.us-east.bsky.network/subscribe".to_owned() 47 + } 48 + DefaultJetstreamEndpoints::USWestOne => { 49 + "wss://jetstream1.us-west.bsky.network/subscribe".to_owned() 50 + } 51 + DefaultJetstreamEndpoints::USWestTwo => { 52 + "wss://jetstream2.us-west.bsky.network/subscribe".to_owned() 53 + } 54 + } 55 + } 56 + } 57 + 58 + /// The maximum number of wanted collections that can be requested on a single Jetstream connection. 59 + const MAX_WANTED_COLLECTIONS: usize = 100; 60 + /// The maximum number of wanted DIDs that can be requested on a single Jetstream connection. 61 + const MAX_WANTED_DIDS: usize = 10_000; 62 + 63 + /// The custom `zstd` dictionary used for decoding compressed Jetstream messages. 64 + /// 65 + /// Sourced from the [official Bluesky Jetstream repo.](https://github.com/bluesky-social/jetstream/tree/main/pkg/models) 66 + const JETSTREAM_ZSTD_DICTIONARY: &[u8] = include_bytes!("../zstd/dictionary"); 67 + 68 + /// A receiver channel for consuming Jetstream events. 69 + pub type JetstreamReceiver = flume::Receiver<JetstreamEvent>; 70 + 71 + /// An internal sender channel for sending Jetstream events to [JetstreamReceiver]'s. 72 + type JetstreamSender = flume::Sender<JetstreamEvent>; 73 + 74 + /// A wrapper connector type for working with a WebSocket connection to a Jetstream instance to 75 + /// receive and consume events. See [JetstreamConnector::connect] for more info. 76 + pub struct JetstreamConnector { 77 + /// The configuration for the Jetstream connection. 78 + config: JetstreamConfig, 79 + } 80 + 81 + pub enum JetstreamCompression { 82 + /// No compression, just raw plaintext JSON. 83 + None, 84 + /// Use the `zstd` compression algorithm, which can result in a ~56% smaller messages on 85 + /// average. See [here](https://github.com/bluesky-social/jetstream?tab=readme-ov-file#compression) for more info. 86 + Zstd, 87 + } 88 + 89 + impl From<JetstreamCompression> for bool { 90 + fn from(compression: JetstreamCompression) -> Self { 91 + match compression { 92 + JetstreamCompression::None => false, 93 + JetstreamCompression::Zstd => true, 94 + } 95 + } 96 + } 97 + 98 + pub struct JetstreamConfig { 99 + /// A Jetstream endpoint to connect to with a WebSocket Scheme i.e. 100 + /// `wss://jetstream1.us-east.bsky.network/subscribe`. 101 + pub endpoint: String, 102 + /// A list of collection [NSIDs](https://atproto.com/specs/nsid) to filter events for. 103 + /// 104 + /// An empty list will receive events for *all* collections. 105 + /// 106 + /// Regardless of desired collections, all subscribers receive 107 + /// [AccountEvent](events::account::AccountEvent) and 108 + /// [IdentityEvent](events::identity::Identity) events. 109 + pub wanted_collections: Vec<exports::Nsid>, 110 + /// A list of repo [DIDs](https://atproto.com/specs/did) to filter events for. 111 + /// 112 + /// An empty list will receive events for *all* repos, which is a lot of events! 113 + pub wanted_dids: Vec<exports::Did>, 114 + /// The compression algorithm to request and use for the WebSocket connection (if any). 115 + pub compression: JetstreamCompression, 116 + /// An optional timestamp to begin playback from. 117 + /// 118 + /// An absent cursor or a cursor from the future will result in live-tail operation. 119 + /// 120 + /// When reconnecting, use the time_us from your most recently processed event and maybe 121 + /// provide a negative buffer (i.e. subtract a few seconds) to ensure gapless playback. 122 + pub cursor: Option<chrono::DateTime<Utc>>, 123 + } 124 + 125 + impl Default for JetstreamConfig { 126 + fn default() -> Self { 127 + JetstreamConfig { 128 + endpoint: DefaultJetstreamEndpoints::USEastOne.into(), 129 + wanted_collections: Vec::new(), 130 + wanted_dids: Vec::new(), 131 + compression: JetstreamCompression::None, 132 + cursor: None, 133 + } 134 + } 135 + } 136 + 137 + impl JetstreamConfig { 138 + /// Constructs a new endpoint URL with the given [JetstreamConfig] applied. 139 + pub fn construct_endpoint(&self, endpoint: &str) -> Result<Url, url::ParseError> { 140 + let did_search_query = self 141 + .wanted_dids 142 + .iter() 143 + .map(|s| ("wantedDids", s.to_string())); 144 + 145 + let collection_search_query = self 146 + .wanted_collections 147 + .iter() 148 + .map(|s| ("wantedCollections", s.to_string())); 149 + 150 + let compression = ( 151 + "compress", 152 + match self.compression { 153 + JetstreamCompression::None => "false".to_owned(), 154 + JetstreamCompression::Zstd => "true".to_owned(), 155 + }, 156 + ); 157 + 158 + let cursor = self 159 + .cursor 160 + .map(|c| ("cursor", c.timestamp_micros().to_string())); 161 + 162 + let params = did_search_query 163 + .chain(collection_search_query) 164 + .chain(std::iter::once(compression)) 165 + .chain(cursor) 166 + .collect::<Vec<(&str, String)>>(); 167 + 168 + Url::parse_with_params(endpoint, params) 169 + } 170 + 171 + /// Validates the configuration to make sure it is within the limits of the Jetstream API. 172 + /// 173 + /// # Constants 174 + /// The following constants are used to validate the configuration and should only be changed 175 + /// if the Jetstream API has itself changed. 176 + /// - [MAX_WANTED_COLLECTIONS] 177 + /// - [MAX_WANTED_DIDS] 178 + pub fn validate(&self) -> Result<(), ConfigValidationError> { 179 + let collections = self.wanted_collections.len(); 180 + let dids = self.wanted_dids.len(); 181 + 182 + if collections > MAX_WANTED_COLLECTIONS { 183 + return Err(ConfigValidationError::TooManyWantedCollections(collections)); 184 + } 185 + 186 + if dids > MAX_WANTED_DIDS { 187 + return Err(ConfigValidationError::TooManyDids(dids)); 188 + } 189 + 190 + Ok(()) 191 + } 192 + } 193 + 194 + impl JetstreamConnector { 195 + /// Create a Jetstream connector with a valid [JetstreamConfig]. 196 + /// 197 + /// After creation, you can call [connect] to connect to the provided Jetstream instance. 198 + pub fn new(config: JetstreamConfig) -> Result<Self, ConfigValidationError> { 199 + // We validate the configuration here so any issues are caught early. 200 + config.validate()?; 201 + Ok(JetstreamConnector { config }) 202 + } 203 + 204 + /// Connects to a Jetstream instance as defined in the [JetstreamConfig]. 205 + /// 206 + /// A [JetstreamReceiver] is returned which can be used to respond to events. When all instances 207 + /// of this receiver are dropped, the connection and task are automatically closed. 208 + pub async fn connect(&self) -> Result<JetstreamReceiver, ConnectionError> { 209 + // We validate the config again for good measure. Probably not necessary but it can't hurt. 210 + self.config 211 + .validate() 212 + .map_err(ConnectionError::InvalidConfig)?; 213 + 214 + // TODO: Run some benchmarks and look into using a bounded channel instead. 215 + let (send_channel, receive_channel) = flume::unbounded(); 216 + 217 + let configured_endpoint = self 218 + .config 219 + .construct_endpoint(&self.config.endpoint) 220 + .map_err(ConnectionError::InvalidEndpoint)?; 221 + 222 + tokio::task::spawn(async move { 223 + let max_retries = 10; 224 + let base_delay_ms = 1_000; // 1 second 225 + let max_delay_ms = 30_000; // 30 seconds 226 + 227 + for retry_attempt in 0..max_retries { 228 + let dict = DecoderDictionary::copy(JETSTREAM_ZSTD_DICTIONARY); 229 + 230 + if let Ok((ws_stream, _)) = connect_async(&configured_endpoint).await { 231 + let _ = websocket_task(dict, ws_stream, send_channel.clone()).await; 232 + } 233 + 234 + // Exponential backoff 235 + let delay_ms = base_delay_ms * (2_u64.pow(retry_attempt)); 236 + 237 + log::error!("Connection failed, retrying in {delay_ms}ms..."); 238 + tokio::time::sleep(Duration::from_millis(delay_ms.min(max_delay_ms))).await; 239 + log::info!("Attempting to reconnect...") 240 + } 241 + log::error!("Connection retries exhausted. Jetstream is disconnected."); 242 + }); 243 + 244 + Ok(receive_channel) 245 + } 246 + } 247 + 248 + /// The main task that handles the WebSocket connection and sends [JetstreamEvent]'s to any 249 + /// receivers that are listening for them. 250 + async fn websocket_task( 251 + dictionary: DecoderDictionary<'_>, 252 + ws: WebSocketStream<MaybeTlsStream<TcpStream>>, 253 + send_channel: JetstreamSender, 254 + ) -> Result<(), JetstreamEventError> { 255 + // TODO: Use the write half to allow the user to change configuration settings on the fly. 256 + let (socket_write, mut socket_read) = ws.split(); 257 + let shared_socket_write = Arc::new(Mutex::new(socket_write)); 258 + 259 + let ping_cancellation_token = CancellationToken::new(); 260 + let mut ping_interval = tokio::time::interval(Duration::from_secs(30)); 261 + let ping_cancelled = ping_cancellation_token.clone(); 262 + let ping_shared_socket_write = shared_socket_write.clone(); 263 + tokio::spawn(async move { 264 + loop { 265 + ping_interval.tick().await; 266 + let false = ping_cancelled.is_cancelled() else { 267 + break; 268 + }; 269 + log::trace!("Sending ping"); 270 + match ping_shared_socket_write 271 + .lock() 272 + .await 273 + .send(Message::Ping("ping".as_bytes().to_vec())) 274 + .await 275 + { 276 + Ok(_) => (), 277 + Err(error) => { 278 + log::error!("Ping failed: {error}"); 279 + break; 280 + } 281 + } 282 + } 283 + }); 284 + 285 + let mut closing_connection = false; 286 + loop { 287 + match socket_read.next().await { 288 + Some(Ok(message)) => { 289 + match message { 290 + Message::Text(json) => { 291 + let event = serde_json::from_str::<JetstreamEvent>(&json) 292 + .map_err(JetstreamEventError::ReceivedMalformedJSON)?; 293 + 294 + if send_channel.send(event).is_err() { 295 + // We can assume that all receivers have been dropped, so we can close the 296 + // connection and exit the task. 297 + log::info!( 298 + "All receivers for the Jetstream connection have been dropped, closing connection." 299 + ); 300 + closing_connection = true; 301 + } 302 + } 303 + Message::Binary(zstd_json) => { 304 + let mut cursor = Cursor::new(zstd_json); 305 + let mut decoder = zstd::stream::Decoder::with_prepared_dictionary( 306 + &mut cursor, 307 + &dictionary, 308 + ) 309 + .map_err(JetstreamEventError::CompressionDictionaryError)?; 310 + 311 + let mut json = String::new(); 312 + decoder 313 + .read_to_string(&mut json) 314 + .map_err(JetstreamEventError::CompressionDecoderError)?; 315 + 316 + let event = serde_json::from_str::<JetstreamEvent>(&json) 317 + .map_err(JetstreamEventError::ReceivedMalformedJSON)?; 318 + 319 + if send_channel.send(event).is_err() { 320 + // We can assume that all receivers have been dropped, so we can close the 321 + // connection and exit the task. 322 + log::info!( 323 + "All receivers for the Jetstream connection have been dropped, closing connection..." 324 + ); 325 + closing_connection = true; 326 + } 327 + } 328 + Message::Ping(vec) => { 329 + log::trace!("Ping recieved, responding"); 330 + _ = shared_socket_write 331 + .lock() 332 + .await 333 + .send(Message::Pong(vec)) 334 + .await; 335 + } 336 + Message::Close(close_frame) => { 337 + if let Some(close_frame) = close_frame { 338 + let reason = close_frame.reason; 339 + let code = close_frame.code; 340 + log::trace!("Connection closed. Reason: {reason}, Code: {code}"); 341 + } 342 + } 343 + Message::Pong(pong) => { 344 + let pong_payload = 345 + String::from_utf8(pong).unwrap_or("Invalid payload".to_string()); 346 + log::trace!("Pong recieved. Payload: {pong_payload}"); 347 + } 348 + Message::Frame(_) => (), 349 + } 350 + } 351 + Some(Err(error)) => { 352 + log::error!("Web socket error: {error}"); 353 + ping_cancellation_token.cancel(); 354 + closing_connection = true; 355 + } 356 + None => { 357 + log::error!("No web socket result"); 358 + ping_cancellation_token.cancel(); 359 + closing_connection = true; 360 + } 361 + } 362 + if closing_connection { 363 + _ = shared_socket_write.lock().await.close().await; 364 + return Ok(()); 365 + } 366 + } 367 + }
jetstream/zstd/dictionary

This is a binary file and will not be displayed.