feat: initial commit

Signed-off-by: tjh <x@tjh.dev>

tjh.dev fd713192

+2
.gitignore
···
··· 1 + target/ 2 + .env
+16
.sqlx/query-21be3b3aca589adf8645ba819a423b5c4e942ab1689d71eb55cdaf6748b59317.json
···
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO deleted_record (SELECT did, collection, rkey, rev, cid, live, data FROM record WHERE (did, collection, rkey) = ($1, $2, $3))", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Text", 10 + "Text" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "21be3b3aca589adf8645ba819a423b5c4e942ab1689d71eb55cdaf6748b59317" 16 + }
+30
.sqlx/query-61e1b073c39dd8231d37c3dfd61459de6f0d1fdba50469fed8e1065a829f43db.json
···
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO identity (did, handle, active, status) VALUES ($1, $2, $3, $4) ON CONFLICT ON CONSTRAINT identity_pkey DO UPDATE SET (handle, active, status) = (EXCLUDED.handle, EXCLUDED.active, EXCLUDED.status)", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Text", 10 + "Bool", 11 + { 12 + "Custom": { 13 + "name": "identity_status", 14 + "kind": { 15 + "Enum": [ 16 + "active", 17 + "takendown", 18 + "suspended", 19 + "deactivated", 20 + "deleted" 21 + ] 22 + } 23 + } 24 + } 25 + ] 26 + }, 27 + "nullable": [] 28 + }, 29 + "hash": "61e1b073c39dd8231d37c3dfd61459de6f0d1fdba50469fed8e1065a829f43db" 30 + }
+16
.sqlx/query-c793a6e15d42d14529d811a4b22014263b52489b6a608e2da2ef8073d7a7e8f6.json
···
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM record WHERE (did, collection, rkey) = ($1, $2, $3)", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Text", 10 + "Text" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "c793a6e15d42d14529d811a4b22014263b52489b6a608e2da2ef8073d7a7e8f6" 16 + }
+20
.sqlx/query-de600b912681a60c29576ac6dcb417bf357e8eafd0cfb007be836b8defb8377d.json
···
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT did FROM identity", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "did", 9 + "type_info": "Text" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [] 14 + }, 15 + "nullable": [ 16 + false 17 + ] 18 + }, 19 + "hash": "de600b912681a60c29576ac6dcb417bf357e8eafd0cfb007be836b8defb8377d" 20 + }
+20
.sqlx/query-eea727151b4f26df90b6023548bf059e1bc5645e7600fe159cd20d09030e44dd.json
···
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO record (did, collection, rkey, rev, cid, live, data)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT\n ON CONSTRAINT record_pkey\n DO UPDATE\n SET (rev, cid, live, data) = (EXCLUDED.rev, EXCLUDED.cid, EXCLUDED.live, EXCLUDED.data)\n WHERE EXCLUDED.rev > record.rev\n", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Text", 10 + "Text", 11 + "Text", 12 + "Text", 13 + "Bool", 14 + "Jsonb" 15 + ] 16 + }, 17 + "nullable": [] 18 + }, 19 + "hash": "eea727151b4f26df90b6023548bf059e1bc5645e7600fe159cd20d09030e44dd" 20 + }
+2895
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 = "aho-corasick" 7 + version = "1.1.4" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" 10 + dependencies = [ 11 + "memchr", 12 + ] 13 + 14 + [[package]] 15 + name = "allocator-api2" 16 + version = "0.2.21" 17 + source = "registry+https://github.com/rust-lang/crates.io-index" 18 + checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 19 + 20 + [[package]] 21 + name = "anstream" 22 + version = "0.6.21" 23 + source = "registry+https://github.com/rust-lang/crates.io-index" 24 + checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" 25 + dependencies = [ 26 + "anstyle", 27 + "anstyle-parse", 28 + "anstyle-query", 29 + "anstyle-wincon", 30 + "colorchoice", 31 + "is_terminal_polyfill", 32 + "utf8parse", 33 + ] 34 + 35 + [[package]] 36 + name = "anstyle" 37 + version = "1.0.13" 38 + source = "registry+https://github.com/rust-lang/crates.io-index" 39 + checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" 40 + 41 + [[package]] 42 + name = "anstyle-parse" 43 + version = "0.2.7" 44 + source = "registry+https://github.com/rust-lang/crates.io-index" 45 + checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 46 + dependencies = [ 47 + "utf8parse", 48 + ] 49 + 50 + [[package]] 51 + name = "anstyle-query" 52 + version = "1.1.5" 53 + source = "registry+https://github.com/rust-lang/crates.io-index" 54 + checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" 55 + dependencies = [ 56 + "windows-sys 0.61.2", 57 + ] 58 + 59 + [[package]] 60 + name = "anstyle-wincon" 61 + version = "3.0.11" 62 + source = "registry+https://github.com/rust-lang/crates.io-index" 63 + checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" 64 + dependencies = [ 65 + "anstyle", 66 + "once_cell_polyfill", 67 + "windows-sys 0.61.2", 68 + ] 69 + 70 + [[package]] 71 + name = "anyhow" 72 + version = "1.0.100" 73 + source = "registry+https://github.com/rust-lang/crates.io-index" 74 + checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" 75 + 76 + [[package]] 77 + name = "atoi" 78 + version = "2.0.0" 79 + source = "registry+https://github.com/rust-lang/crates.io-index" 80 + checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" 81 + dependencies = [ 82 + "num-traits", 83 + ] 84 + 85 + [[package]] 86 + name = "atomic-waker" 87 + version = "1.1.2" 88 + source = "registry+https://github.com/rust-lang/crates.io-index" 89 + checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 90 + 91 + [[package]] 92 + name = "autocfg" 93 + version = "1.5.0" 94 + source = "registry+https://github.com/rust-lang/crates.io-index" 95 + checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 96 + 97 + [[package]] 98 + name = "base64" 99 + version = "0.22.1" 100 + source = "registry+https://github.com/rust-lang/crates.io-index" 101 + checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 102 + 103 + [[package]] 104 + name = "base64ct" 105 + version = "1.8.1" 106 + source = "registry+https://github.com/rust-lang/crates.io-index" 107 + checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" 108 + 109 + [[package]] 110 + name = "bitflags" 111 + version = "2.10.0" 112 + source = "registry+https://github.com/rust-lang/crates.io-index" 113 + checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" 114 + dependencies = [ 115 + "serde_core", 116 + ] 117 + 118 + [[package]] 119 + name = "block-buffer" 120 + version = "0.10.4" 121 + source = "registry+https://github.com/rust-lang/crates.io-index" 122 + checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 123 + dependencies = [ 124 + "generic-array", 125 + ] 126 + 127 + [[package]] 128 + name = "bumpalo" 129 + version = "3.19.1" 130 + source = "registry+https://github.com/rust-lang/crates.io-index" 131 + checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" 132 + 133 + [[package]] 134 + name = "byteorder" 135 + version = "1.5.0" 136 + source = "registry+https://github.com/rust-lang/crates.io-index" 137 + checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 138 + 139 + [[package]] 140 + name = "bytes" 141 + version = "1.11.0" 142 + source = "registry+https://github.com/rust-lang/crates.io-index" 143 + checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" 144 + 145 + [[package]] 146 + name = "cc" 147 + version = "1.2.49" 148 + source = "registry+https://github.com/rust-lang/crates.io-index" 149 + checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" 150 + dependencies = [ 151 + "find-msvc-tools", 152 + "shlex", 153 + ] 154 + 155 + [[package]] 156 + name = "cfg-if" 157 + version = "1.0.4" 158 + source = "registry+https://github.com/rust-lang/crates.io-index" 159 + checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 160 + 161 + [[package]] 162 + name = "clap" 163 + version = "4.5.53" 164 + source = "registry+https://github.com/rust-lang/crates.io-index" 165 + checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" 166 + dependencies = [ 167 + "clap_builder", 168 + "clap_derive", 169 + ] 170 + 171 + [[package]] 172 + name = "clap_builder" 173 + version = "4.5.53" 174 + source = "registry+https://github.com/rust-lang/crates.io-index" 175 + checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" 176 + dependencies = [ 177 + "anstream", 178 + "anstyle", 179 + "clap_lex", 180 + "strsim", 181 + ] 182 + 183 + [[package]] 184 + name = "clap_derive" 185 + version = "4.5.49" 186 + source = "registry+https://github.com/rust-lang/crates.io-index" 187 + checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" 188 + dependencies = [ 189 + "heck", 190 + "proc-macro2", 191 + "quote", 192 + "syn", 193 + ] 194 + 195 + [[package]] 196 + name = "clap_lex" 197 + version = "0.7.6" 198 + source = "registry+https://github.com/rust-lang/crates.io-index" 199 + checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" 200 + 201 + [[package]] 202 + name = "colorchoice" 203 + version = "1.0.4" 204 + source = "registry+https://github.com/rust-lang/crates.io-index" 205 + checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 206 + 207 + [[package]] 208 + name = "concurrent-queue" 209 + version = "2.5.0" 210 + source = "registry+https://github.com/rust-lang/crates.io-index" 211 + checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 212 + dependencies = [ 213 + "crossbeam-utils", 214 + ] 215 + 216 + [[package]] 217 + name = "const-oid" 218 + version = "0.9.6" 219 + source = "registry+https://github.com/rust-lang/crates.io-index" 220 + checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 221 + 222 + [[package]] 223 + name = "core-foundation" 224 + version = "0.9.4" 225 + source = "registry+https://github.com/rust-lang/crates.io-index" 226 + checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 227 + dependencies = [ 228 + "core-foundation-sys", 229 + "libc", 230 + ] 231 + 232 + [[package]] 233 + name = "core-foundation-sys" 234 + version = "0.8.7" 235 + source = "registry+https://github.com/rust-lang/crates.io-index" 236 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 237 + 238 + [[package]] 239 + name = "cpufeatures" 240 + version = "0.2.17" 241 + source = "registry+https://github.com/rust-lang/crates.io-index" 242 + checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 243 + dependencies = [ 244 + "libc", 245 + ] 246 + 247 + [[package]] 248 + name = "crc" 249 + version = "3.4.0" 250 + source = "registry+https://github.com/rust-lang/crates.io-index" 251 + checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" 252 + dependencies = [ 253 + "crc-catalog", 254 + ] 255 + 256 + [[package]] 257 + name = "crc-catalog" 258 + version = "2.4.0" 259 + source = "registry+https://github.com/rust-lang/crates.io-index" 260 + checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 261 + 262 + [[package]] 263 + name = "crossbeam-queue" 264 + version = "0.3.12" 265 + source = "registry+https://github.com/rust-lang/crates.io-index" 266 + checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" 267 + dependencies = [ 268 + "crossbeam-utils", 269 + ] 270 + 271 + [[package]] 272 + name = "crossbeam-utils" 273 + version = "0.8.21" 274 + source = "registry+https://github.com/rust-lang/crates.io-index" 275 + checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 276 + 277 + [[package]] 278 + name = "crypto-common" 279 + version = "0.1.7" 280 + source = "registry+https://github.com/rust-lang/crates.io-index" 281 + checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" 282 + dependencies = [ 283 + "generic-array", 284 + "typenum", 285 + ] 286 + 287 + [[package]] 288 + name = "data-encoding" 289 + version = "2.9.0" 290 + source = "registry+https://github.com/rust-lang/crates.io-index" 291 + checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 292 + 293 + [[package]] 294 + name = "der" 295 + version = "0.7.10" 296 + source = "registry+https://github.com/rust-lang/crates.io-index" 297 + checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" 298 + dependencies = [ 299 + "const-oid", 300 + "pem-rfc7468", 301 + "zeroize", 302 + ] 303 + 304 + [[package]] 305 + name = "deranged" 306 + version = "0.5.5" 307 + source = "registry+https://github.com/rust-lang/crates.io-index" 308 + checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" 309 + dependencies = [ 310 + "powerfmt", 311 + ] 312 + 313 + [[package]] 314 + name = "digest" 315 + version = "0.10.7" 316 + source = "registry+https://github.com/rust-lang/crates.io-index" 317 + checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 318 + dependencies = [ 319 + "block-buffer", 320 + "const-oid", 321 + "crypto-common", 322 + "subtle", 323 + ] 324 + 325 + [[package]] 326 + name = "displaydoc" 327 + version = "0.2.5" 328 + source = "registry+https://github.com/rust-lang/crates.io-index" 329 + checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 330 + dependencies = [ 331 + "proc-macro2", 332 + "quote", 333 + "syn", 334 + ] 335 + 336 + [[package]] 337 + name = "dotenvy" 338 + version = "0.15.7" 339 + source = "registry+https://github.com/rust-lang/crates.io-index" 340 + checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 341 + 342 + [[package]] 343 + name = "either" 344 + version = "1.15.0" 345 + source = "registry+https://github.com/rust-lang/crates.io-index" 346 + checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 347 + dependencies = [ 348 + "serde", 349 + ] 350 + 351 + [[package]] 352 + name = "encoding_rs" 353 + version = "0.8.35" 354 + source = "registry+https://github.com/rust-lang/crates.io-index" 355 + checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 356 + dependencies = [ 357 + "cfg-if", 358 + ] 359 + 360 + [[package]] 361 + name = "equivalent" 362 + version = "1.0.2" 363 + source = "registry+https://github.com/rust-lang/crates.io-index" 364 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 365 + 366 + [[package]] 367 + name = "errno" 368 + version = "0.3.14" 369 + source = "registry+https://github.com/rust-lang/crates.io-index" 370 + checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" 371 + dependencies = [ 372 + "libc", 373 + "windows-sys 0.61.2", 374 + ] 375 + 376 + [[package]] 377 + name = "etcetera" 378 + version = "0.8.0" 379 + source = "registry+https://github.com/rust-lang/crates.io-index" 380 + checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" 381 + dependencies = [ 382 + "cfg-if", 383 + "home", 384 + "windows-sys 0.48.0", 385 + ] 386 + 387 + [[package]] 388 + name = "event-listener" 389 + version = "5.4.1" 390 + source = "registry+https://github.com/rust-lang/crates.io-index" 391 + checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" 392 + dependencies = [ 393 + "concurrent-queue", 394 + "parking", 395 + "pin-project-lite", 396 + ] 397 + 398 + [[package]] 399 + name = "fastrand" 400 + version = "2.3.0" 401 + source = "registry+https://github.com/rust-lang/crates.io-index" 402 + checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 403 + 404 + [[package]] 405 + name = "find-msvc-tools" 406 + version = "0.1.5" 407 + source = "registry+https://github.com/rust-lang/crates.io-index" 408 + checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" 409 + 410 + [[package]] 411 + name = "flume" 412 + version = "0.11.1" 413 + source = "registry+https://github.com/rust-lang/crates.io-index" 414 + checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" 415 + dependencies = [ 416 + "futures-core", 417 + "futures-sink", 418 + "spin", 419 + ] 420 + 421 + [[package]] 422 + name = "fnv" 423 + version = "1.0.7" 424 + source = "registry+https://github.com/rust-lang/crates.io-index" 425 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 426 + 427 + [[package]] 428 + name = "foldhash" 429 + version = "0.1.5" 430 + source = "registry+https://github.com/rust-lang/crates.io-index" 431 + checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 432 + 433 + [[package]] 434 + name = "foreign-types" 435 + version = "0.3.2" 436 + source = "registry+https://github.com/rust-lang/crates.io-index" 437 + checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 438 + dependencies = [ 439 + "foreign-types-shared", 440 + ] 441 + 442 + [[package]] 443 + name = "foreign-types-shared" 444 + version = "0.1.1" 445 + source = "registry+https://github.com/rust-lang/crates.io-index" 446 + checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 447 + 448 + [[package]] 449 + name = "form_urlencoded" 450 + version = "1.2.2" 451 + source = "registry+https://github.com/rust-lang/crates.io-index" 452 + checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 453 + dependencies = [ 454 + "percent-encoding", 455 + ] 456 + 457 + [[package]] 458 + name = "futures-channel" 459 + version = "0.3.31" 460 + source = "registry+https://github.com/rust-lang/crates.io-index" 461 + checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 462 + dependencies = [ 463 + "futures-core", 464 + "futures-sink", 465 + ] 466 + 467 + [[package]] 468 + name = "futures-core" 469 + version = "0.3.31" 470 + source = "registry+https://github.com/rust-lang/crates.io-index" 471 + checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 472 + 473 + [[package]] 474 + name = "futures-executor" 475 + version = "0.3.31" 476 + source = "registry+https://github.com/rust-lang/crates.io-index" 477 + checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 478 + dependencies = [ 479 + "futures-core", 480 + "futures-task", 481 + "futures-util", 482 + ] 483 + 484 + [[package]] 485 + name = "futures-intrusive" 486 + version = "0.5.0" 487 + source = "registry+https://github.com/rust-lang/crates.io-index" 488 + checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" 489 + dependencies = [ 490 + "futures-core", 491 + "lock_api", 492 + "parking_lot", 493 + ] 494 + 495 + [[package]] 496 + name = "futures-io" 497 + version = "0.3.31" 498 + source = "registry+https://github.com/rust-lang/crates.io-index" 499 + checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 500 + 501 + [[package]] 502 + name = "futures-macro" 503 + version = "0.3.31" 504 + source = "registry+https://github.com/rust-lang/crates.io-index" 505 + checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 506 + dependencies = [ 507 + "proc-macro2", 508 + "quote", 509 + "syn", 510 + ] 511 + 512 + [[package]] 513 + name = "futures-sink" 514 + version = "0.3.31" 515 + source = "registry+https://github.com/rust-lang/crates.io-index" 516 + checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 517 + 518 + [[package]] 519 + name = "futures-task" 520 + version = "0.3.31" 521 + source = "registry+https://github.com/rust-lang/crates.io-index" 522 + checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 523 + 524 + [[package]] 525 + name = "futures-util" 526 + version = "0.3.31" 527 + source = "registry+https://github.com/rust-lang/crates.io-index" 528 + checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 529 + dependencies = [ 530 + "futures-core", 531 + "futures-io", 532 + "futures-macro", 533 + "futures-sink", 534 + "futures-task", 535 + "memchr", 536 + "pin-project-lite", 537 + "pin-utils", 538 + "slab", 539 + ] 540 + 541 + [[package]] 542 + name = "generic-array" 543 + version = "0.14.7" 544 + source = "registry+https://github.com/rust-lang/crates.io-index" 545 + checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 546 + dependencies = [ 547 + "typenum", 548 + "version_check", 549 + ] 550 + 551 + [[package]] 552 + name = "getrandom" 553 + version = "0.2.16" 554 + source = "registry+https://github.com/rust-lang/crates.io-index" 555 + checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 556 + dependencies = [ 557 + "cfg-if", 558 + "libc", 559 + "wasi", 560 + ] 561 + 562 + [[package]] 563 + name = "getrandom" 564 + version = "0.3.4" 565 + source = "registry+https://github.com/rust-lang/crates.io-index" 566 + checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" 567 + dependencies = [ 568 + "cfg-if", 569 + "libc", 570 + "r-efi", 571 + "wasip2", 572 + ] 573 + 574 + [[package]] 575 + name = "h2" 576 + version = "0.4.12" 577 + source = "registry+https://github.com/rust-lang/crates.io-index" 578 + checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" 579 + dependencies = [ 580 + "atomic-waker", 581 + "bytes", 582 + "fnv", 583 + "futures-core", 584 + "futures-sink", 585 + "http", 586 + "indexmap", 587 + "slab", 588 + "tokio", 589 + "tokio-util", 590 + "tracing", 591 + ] 592 + 593 + [[package]] 594 + name = "hashbrown" 595 + version = "0.15.5" 596 + source = "registry+https://github.com/rust-lang/crates.io-index" 597 + checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 598 + dependencies = [ 599 + "allocator-api2", 600 + "equivalent", 601 + "foldhash", 602 + ] 603 + 604 + [[package]] 605 + name = "hashbrown" 606 + version = "0.16.1" 607 + source = "registry+https://github.com/rust-lang/crates.io-index" 608 + checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 609 + 610 + [[package]] 611 + name = "hashlink" 612 + version = "0.10.0" 613 + source = "registry+https://github.com/rust-lang/crates.io-index" 614 + checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" 615 + dependencies = [ 616 + "hashbrown 0.15.5", 617 + ] 618 + 619 + [[package]] 620 + name = "heck" 621 + version = "0.5.0" 622 + source = "registry+https://github.com/rust-lang/crates.io-index" 623 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 624 + 625 + [[package]] 626 + name = "hex" 627 + version = "0.4.3" 628 + source = "registry+https://github.com/rust-lang/crates.io-index" 629 + checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 630 + 631 + [[package]] 632 + name = "hkdf" 633 + version = "0.12.4" 634 + source = "registry+https://github.com/rust-lang/crates.io-index" 635 + checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" 636 + dependencies = [ 637 + "hmac", 638 + ] 639 + 640 + [[package]] 641 + name = "hmac" 642 + version = "0.12.1" 643 + source = "registry+https://github.com/rust-lang/crates.io-index" 644 + checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 645 + dependencies = [ 646 + "digest", 647 + ] 648 + 649 + [[package]] 650 + name = "home" 651 + version = "0.5.12" 652 + source = "registry+https://github.com/rust-lang/crates.io-index" 653 + checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" 654 + dependencies = [ 655 + "windows-sys 0.61.2", 656 + ] 657 + 658 + [[package]] 659 + name = "http" 660 + version = "1.4.0" 661 + source = "registry+https://github.com/rust-lang/crates.io-index" 662 + checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" 663 + dependencies = [ 664 + "bytes", 665 + "itoa", 666 + ] 667 + 668 + [[package]] 669 + name = "http-body" 670 + version = "1.0.1" 671 + source = "registry+https://github.com/rust-lang/crates.io-index" 672 + checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 673 + dependencies = [ 674 + "bytes", 675 + "http", 676 + ] 677 + 678 + [[package]] 679 + name = "http-body-util" 680 + version = "0.1.3" 681 + source = "registry+https://github.com/rust-lang/crates.io-index" 682 + checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 683 + dependencies = [ 684 + "bytes", 685 + "futures-core", 686 + "http", 687 + "http-body", 688 + "pin-project-lite", 689 + ] 690 + 691 + [[package]] 692 + name = "httparse" 693 + version = "1.10.1" 694 + source = "registry+https://github.com/rust-lang/crates.io-index" 695 + checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 696 + 697 + [[package]] 698 + name = "hyper" 699 + version = "1.8.1" 700 + source = "registry+https://github.com/rust-lang/crates.io-index" 701 + checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" 702 + dependencies = [ 703 + "atomic-waker", 704 + "bytes", 705 + "futures-channel", 706 + "futures-core", 707 + "h2", 708 + "http", 709 + "http-body", 710 + "httparse", 711 + "itoa", 712 + "pin-project-lite", 713 + "pin-utils", 714 + "smallvec", 715 + "tokio", 716 + "want", 717 + ] 718 + 719 + [[package]] 720 + name = "hyper-rustls" 721 + version = "0.27.7" 722 + source = "registry+https://github.com/rust-lang/crates.io-index" 723 + checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" 724 + dependencies = [ 725 + "http", 726 + "hyper", 727 + "hyper-util", 728 + "rustls", 729 + "rustls-pki-types", 730 + "tokio", 731 + "tokio-rustls", 732 + "tower-service", 733 + ] 734 + 735 + [[package]] 736 + name = "hyper-tls" 737 + version = "0.6.0" 738 + source = "registry+https://github.com/rust-lang/crates.io-index" 739 + checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 740 + dependencies = [ 741 + "bytes", 742 + "http-body-util", 743 + "hyper", 744 + "hyper-util", 745 + "native-tls", 746 + "tokio", 747 + "tokio-native-tls", 748 + "tower-service", 749 + ] 750 + 751 + [[package]] 752 + name = "hyper-util" 753 + version = "0.1.19" 754 + source = "registry+https://github.com/rust-lang/crates.io-index" 755 + checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" 756 + dependencies = [ 757 + "base64", 758 + "bytes", 759 + "futures-channel", 760 + "futures-core", 761 + "futures-util", 762 + "http", 763 + "http-body", 764 + "hyper", 765 + "ipnet", 766 + "libc", 767 + "percent-encoding", 768 + "pin-project-lite", 769 + "socket2", 770 + "system-configuration", 771 + "tokio", 772 + "tower-service", 773 + "tracing", 774 + "windows-registry", 775 + ] 776 + 777 + [[package]] 778 + name = "icu_collections" 779 + version = "2.1.1" 780 + source = "registry+https://github.com/rust-lang/crates.io-index" 781 + checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" 782 + dependencies = [ 783 + "displaydoc", 784 + "potential_utf", 785 + "yoke", 786 + "zerofrom", 787 + "zerovec", 788 + ] 789 + 790 + [[package]] 791 + name = "icu_locale_core" 792 + version = "2.1.1" 793 + source = "registry+https://github.com/rust-lang/crates.io-index" 794 + checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" 795 + dependencies = [ 796 + "displaydoc", 797 + "litemap", 798 + "tinystr", 799 + "writeable", 800 + "zerovec", 801 + ] 802 + 803 + [[package]] 804 + name = "icu_normalizer" 805 + version = "2.1.1" 806 + source = "registry+https://github.com/rust-lang/crates.io-index" 807 + checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" 808 + dependencies = [ 809 + "icu_collections", 810 + "icu_normalizer_data", 811 + "icu_properties", 812 + "icu_provider", 813 + "smallvec", 814 + "zerovec", 815 + ] 816 + 817 + [[package]] 818 + name = "icu_normalizer_data" 819 + version = "2.1.1" 820 + source = "registry+https://github.com/rust-lang/crates.io-index" 821 + checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" 822 + 823 + [[package]] 824 + name = "icu_properties" 825 + version = "2.1.2" 826 + source = "registry+https://github.com/rust-lang/crates.io-index" 827 + checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" 828 + dependencies = [ 829 + "icu_collections", 830 + "icu_locale_core", 831 + "icu_properties_data", 832 + "icu_provider", 833 + "zerotrie", 834 + "zerovec", 835 + ] 836 + 837 + [[package]] 838 + name = "icu_properties_data" 839 + version = "2.1.2" 840 + source = "registry+https://github.com/rust-lang/crates.io-index" 841 + checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" 842 + 843 + [[package]] 844 + name = "icu_provider" 845 + version = "2.1.1" 846 + source = "registry+https://github.com/rust-lang/crates.io-index" 847 + checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" 848 + dependencies = [ 849 + "displaydoc", 850 + "icu_locale_core", 851 + "writeable", 852 + "yoke", 853 + "zerofrom", 854 + "zerotrie", 855 + "zerovec", 856 + ] 857 + 858 + [[package]] 859 + name = "idna" 860 + version = "1.1.0" 861 + source = "registry+https://github.com/rust-lang/crates.io-index" 862 + checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 863 + dependencies = [ 864 + "idna_adapter", 865 + "smallvec", 866 + "utf8_iter", 867 + ] 868 + 869 + [[package]] 870 + name = "idna_adapter" 871 + version = "1.2.1" 872 + source = "registry+https://github.com/rust-lang/crates.io-index" 873 + checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 874 + dependencies = [ 875 + "icu_normalizer", 876 + "icu_properties", 877 + ] 878 + 879 + [[package]] 880 + name = "indexmap" 881 + version = "2.12.1" 882 + source = "registry+https://github.com/rust-lang/crates.io-index" 883 + checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" 884 + dependencies = [ 885 + "equivalent", 886 + "hashbrown 0.16.1", 887 + ] 888 + 889 + [[package]] 890 + name = "ipnet" 891 + version = "2.11.0" 892 + source = "registry+https://github.com/rust-lang/crates.io-index" 893 + checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 894 + 895 + [[package]] 896 + name = "iri-string" 897 + version = "0.7.9" 898 + source = "registry+https://github.com/rust-lang/crates.io-index" 899 + checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" 900 + dependencies = [ 901 + "memchr", 902 + "serde", 903 + ] 904 + 905 + [[package]] 906 + name = "is_terminal_polyfill" 907 + version = "1.70.2" 908 + source = "registry+https://github.com/rust-lang/crates.io-index" 909 + checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" 910 + 911 + [[package]] 912 + name = "itoa" 913 + version = "1.0.15" 914 + source = "registry+https://github.com/rust-lang/crates.io-index" 915 + checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 916 + 917 + [[package]] 918 + name = "js-sys" 919 + version = "0.3.83" 920 + source = "registry+https://github.com/rust-lang/crates.io-index" 921 + checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" 922 + dependencies = [ 923 + "once_cell", 924 + "wasm-bindgen", 925 + ] 926 + 927 + [[package]] 928 + name = "lazy_static" 929 + version = "1.5.0" 930 + source = "registry+https://github.com/rust-lang/crates.io-index" 931 + checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 932 + dependencies = [ 933 + "spin", 934 + ] 935 + 936 + [[package]] 937 + name = "libc" 938 + version = "0.2.178" 939 + source = "registry+https://github.com/rust-lang/crates.io-index" 940 + checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" 941 + 942 + [[package]] 943 + name = "libm" 944 + version = "0.2.15" 945 + source = "registry+https://github.com/rust-lang/crates.io-index" 946 + checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" 947 + 948 + [[package]] 949 + name = "libredox" 950 + version = "0.1.11" 951 + source = "registry+https://github.com/rust-lang/crates.io-index" 952 + checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" 953 + dependencies = [ 954 + "bitflags", 955 + "libc", 956 + "redox_syscall 0.6.0", 957 + ] 958 + 959 + [[package]] 960 + name = "libsqlite3-sys" 961 + version = "0.30.1" 962 + source = "registry+https://github.com/rust-lang/crates.io-index" 963 + checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" 964 + dependencies = [ 965 + "pkg-config", 966 + "vcpkg", 967 + ] 968 + 969 + [[package]] 970 + name = "linux-raw-sys" 971 + version = "0.11.0" 972 + source = "registry+https://github.com/rust-lang/crates.io-index" 973 + checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 974 + 975 + [[package]] 976 + name = "litemap" 977 + version = "0.8.1" 978 + source = "registry+https://github.com/rust-lang/crates.io-index" 979 + checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 980 + 981 + [[package]] 982 + name = "lock_api" 983 + version = "0.4.14" 984 + source = "registry+https://github.com/rust-lang/crates.io-index" 985 + checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" 986 + dependencies = [ 987 + "scopeguard", 988 + ] 989 + 990 + [[package]] 991 + name = "log" 992 + version = "0.4.29" 993 + source = "registry+https://github.com/rust-lang/crates.io-index" 994 + checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 995 + 996 + [[package]] 997 + name = "matchers" 998 + version = "0.2.0" 999 + source = "registry+https://github.com/rust-lang/crates.io-index" 1000 + checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" 1001 + dependencies = [ 1002 + "regex-automata", 1003 + ] 1004 + 1005 + [[package]] 1006 + name = "md-5" 1007 + version = "0.10.6" 1008 + source = "registry+https://github.com/rust-lang/crates.io-index" 1009 + checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" 1010 + dependencies = [ 1011 + "cfg-if", 1012 + "digest", 1013 + ] 1014 + 1015 + [[package]] 1016 + name = "memchr" 1017 + version = "2.7.6" 1018 + source = "registry+https://github.com/rust-lang/crates.io-index" 1019 + checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" 1020 + 1021 + [[package]] 1022 + name = "mime" 1023 + version = "0.3.17" 1024 + source = "registry+https://github.com/rust-lang/crates.io-index" 1025 + checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1026 + 1027 + [[package]] 1028 + name = "mio" 1029 + version = "1.1.1" 1030 + source = "registry+https://github.com/rust-lang/crates.io-index" 1031 + checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" 1032 + dependencies = [ 1033 + "libc", 1034 + "wasi", 1035 + "windows-sys 0.61.2", 1036 + ] 1037 + 1038 + [[package]] 1039 + name = "native-tls" 1040 + version = "0.2.14" 1041 + source = "registry+https://github.com/rust-lang/crates.io-index" 1042 + checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" 1043 + dependencies = [ 1044 + "libc", 1045 + "log", 1046 + "openssl", 1047 + "openssl-probe", 1048 + "openssl-sys", 1049 + "schannel", 1050 + "security-framework", 1051 + "security-framework-sys", 1052 + "tempfile", 1053 + ] 1054 + 1055 + [[package]] 1056 + name = "nu-ansi-term" 1057 + version = "0.50.3" 1058 + source = "registry+https://github.com/rust-lang/crates.io-index" 1059 + checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" 1060 + dependencies = [ 1061 + "windows-sys 0.61.2", 1062 + ] 1063 + 1064 + [[package]] 1065 + name = "num-bigint-dig" 1066 + version = "0.8.6" 1067 + source = "registry+https://github.com/rust-lang/crates.io-index" 1068 + checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" 1069 + dependencies = [ 1070 + "lazy_static", 1071 + "libm", 1072 + "num-integer", 1073 + "num-iter", 1074 + "num-traits", 1075 + "rand 0.8.5", 1076 + "smallvec", 1077 + "zeroize", 1078 + ] 1079 + 1080 + [[package]] 1081 + name = "num-conv" 1082 + version = "0.1.0" 1083 + source = "registry+https://github.com/rust-lang/crates.io-index" 1084 + checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1085 + 1086 + [[package]] 1087 + name = "num-integer" 1088 + version = "0.1.46" 1089 + source = "registry+https://github.com/rust-lang/crates.io-index" 1090 + checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1091 + dependencies = [ 1092 + "num-traits", 1093 + ] 1094 + 1095 + [[package]] 1096 + name = "num-iter" 1097 + version = "0.1.45" 1098 + source = "registry+https://github.com/rust-lang/crates.io-index" 1099 + checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 1100 + dependencies = [ 1101 + "autocfg", 1102 + "num-integer", 1103 + "num-traits", 1104 + ] 1105 + 1106 + [[package]] 1107 + name = "num-traits" 1108 + version = "0.2.19" 1109 + source = "registry+https://github.com/rust-lang/crates.io-index" 1110 + checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1111 + dependencies = [ 1112 + "autocfg", 1113 + "libm", 1114 + ] 1115 + 1116 + [[package]] 1117 + name = "once_cell" 1118 + version = "1.21.3" 1119 + source = "registry+https://github.com/rust-lang/crates.io-index" 1120 + checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1121 + 1122 + [[package]] 1123 + name = "once_cell_polyfill" 1124 + version = "1.70.2" 1125 + source = "registry+https://github.com/rust-lang/crates.io-index" 1126 + checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" 1127 + 1128 + [[package]] 1129 + name = "openssl" 1130 + version = "0.10.75" 1131 + source = "registry+https://github.com/rust-lang/crates.io-index" 1132 + checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" 1133 + dependencies = [ 1134 + "bitflags", 1135 + "cfg-if", 1136 + "foreign-types", 1137 + "libc", 1138 + "once_cell", 1139 + "openssl-macros", 1140 + "openssl-sys", 1141 + ] 1142 + 1143 + [[package]] 1144 + name = "openssl-macros" 1145 + version = "0.1.1" 1146 + source = "registry+https://github.com/rust-lang/crates.io-index" 1147 + checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1148 + dependencies = [ 1149 + "proc-macro2", 1150 + "quote", 1151 + "syn", 1152 + ] 1153 + 1154 + [[package]] 1155 + name = "openssl-probe" 1156 + version = "0.1.6" 1157 + source = "registry+https://github.com/rust-lang/crates.io-index" 1158 + checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 1159 + 1160 + [[package]] 1161 + name = "openssl-sys" 1162 + version = "0.9.111" 1163 + source = "registry+https://github.com/rust-lang/crates.io-index" 1164 + checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" 1165 + dependencies = [ 1166 + "cc", 1167 + "libc", 1168 + "pkg-config", 1169 + "vcpkg", 1170 + ] 1171 + 1172 + [[package]] 1173 + name = "parking" 1174 + version = "2.2.1" 1175 + source = "registry+https://github.com/rust-lang/crates.io-index" 1176 + checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 1177 + 1178 + [[package]] 1179 + name = "parking_lot" 1180 + version = "0.12.5" 1181 + source = "registry+https://github.com/rust-lang/crates.io-index" 1182 + checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" 1183 + dependencies = [ 1184 + "lock_api", 1185 + "parking_lot_core", 1186 + ] 1187 + 1188 + [[package]] 1189 + name = "parking_lot_core" 1190 + version = "0.9.12" 1191 + source = "registry+https://github.com/rust-lang/crates.io-index" 1192 + checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" 1193 + dependencies = [ 1194 + "cfg-if", 1195 + "libc", 1196 + "redox_syscall 0.5.18", 1197 + "smallvec", 1198 + "windows-link", 1199 + ] 1200 + 1201 + [[package]] 1202 + name = "pem-rfc7468" 1203 + version = "0.7.0" 1204 + source = "registry+https://github.com/rust-lang/crates.io-index" 1205 + checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" 1206 + dependencies = [ 1207 + "base64ct", 1208 + ] 1209 + 1210 + [[package]] 1211 + name = "percent-encoding" 1212 + version = "2.3.2" 1213 + source = "registry+https://github.com/rust-lang/crates.io-index" 1214 + checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 1215 + 1216 + [[package]] 1217 + name = "pin-project-lite" 1218 + version = "0.2.16" 1219 + source = "registry+https://github.com/rust-lang/crates.io-index" 1220 + checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1221 + 1222 + [[package]] 1223 + name = "pin-utils" 1224 + version = "0.1.0" 1225 + source = "registry+https://github.com/rust-lang/crates.io-index" 1226 + checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1227 + 1228 + [[package]] 1229 + name = "pkcs1" 1230 + version = "0.7.5" 1231 + source = "registry+https://github.com/rust-lang/crates.io-index" 1232 + checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" 1233 + dependencies = [ 1234 + "der", 1235 + "pkcs8", 1236 + "spki", 1237 + ] 1238 + 1239 + [[package]] 1240 + name = "pkcs8" 1241 + version = "0.10.2" 1242 + source = "registry+https://github.com/rust-lang/crates.io-index" 1243 + checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 1244 + dependencies = [ 1245 + "der", 1246 + "spki", 1247 + ] 1248 + 1249 + [[package]] 1250 + name = "pkg-config" 1251 + version = "0.3.32" 1252 + source = "registry+https://github.com/rust-lang/crates.io-index" 1253 + checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 1254 + 1255 + [[package]] 1256 + name = "potential_utf" 1257 + version = "0.1.4" 1258 + source = "registry+https://github.com/rust-lang/crates.io-index" 1259 + checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" 1260 + dependencies = [ 1261 + "zerovec", 1262 + ] 1263 + 1264 + [[package]] 1265 + name = "powerfmt" 1266 + version = "0.2.0" 1267 + source = "registry+https://github.com/rust-lang/crates.io-index" 1268 + checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1269 + 1270 + [[package]] 1271 + name = "ppv-lite86" 1272 + version = "0.2.21" 1273 + source = "registry+https://github.com/rust-lang/crates.io-index" 1274 + checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 1275 + dependencies = [ 1276 + "zerocopy", 1277 + ] 1278 + 1279 + [[package]] 1280 + name = "proc-macro2" 1281 + version = "1.0.103" 1282 + source = "registry+https://github.com/rust-lang/crates.io-index" 1283 + checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" 1284 + dependencies = [ 1285 + "unicode-ident", 1286 + ] 1287 + 1288 + [[package]] 1289 + name = "quote" 1290 + version = "1.0.42" 1291 + source = "registry+https://github.com/rust-lang/crates.io-index" 1292 + checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" 1293 + dependencies = [ 1294 + "proc-macro2", 1295 + ] 1296 + 1297 + [[package]] 1298 + name = "r-efi" 1299 + version = "5.3.0" 1300 + source = "registry+https://github.com/rust-lang/crates.io-index" 1301 + checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 1302 + 1303 + [[package]] 1304 + name = "rand" 1305 + version = "0.8.5" 1306 + source = "registry+https://github.com/rust-lang/crates.io-index" 1307 + checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1308 + dependencies = [ 1309 + "libc", 1310 + "rand_chacha 0.3.1", 1311 + "rand_core 0.6.4", 1312 + ] 1313 + 1314 + [[package]] 1315 + name = "rand" 1316 + version = "0.9.2" 1317 + source = "registry+https://github.com/rust-lang/crates.io-index" 1318 + checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 1319 + dependencies = [ 1320 + "rand_chacha 0.9.0", 1321 + "rand_core 0.9.3", 1322 + ] 1323 + 1324 + [[package]] 1325 + name = "rand_chacha" 1326 + version = "0.3.1" 1327 + source = "registry+https://github.com/rust-lang/crates.io-index" 1328 + checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1329 + dependencies = [ 1330 + "ppv-lite86", 1331 + "rand_core 0.6.4", 1332 + ] 1333 + 1334 + [[package]] 1335 + name = "rand_chacha" 1336 + version = "0.9.0" 1337 + source = "registry+https://github.com/rust-lang/crates.io-index" 1338 + checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1339 + dependencies = [ 1340 + "ppv-lite86", 1341 + "rand_core 0.9.3", 1342 + ] 1343 + 1344 + [[package]] 1345 + name = "rand_core" 1346 + version = "0.6.4" 1347 + source = "registry+https://github.com/rust-lang/crates.io-index" 1348 + checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1349 + dependencies = [ 1350 + "getrandom 0.2.16", 1351 + ] 1352 + 1353 + [[package]] 1354 + name = "rand_core" 1355 + version = "0.9.3" 1356 + source = "registry+https://github.com/rust-lang/crates.io-index" 1357 + checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1358 + dependencies = [ 1359 + "getrandom 0.3.4", 1360 + ] 1361 + 1362 + [[package]] 1363 + name = "redox_syscall" 1364 + version = "0.5.18" 1365 + source = "registry+https://github.com/rust-lang/crates.io-index" 1366 + checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" 1367 + dependencies = [ 1368 + "bitflags", 1369 + ] 1370 + 1371 + [[package]] 1372 + name = "redox_syscall" 1373 + version = "0.6.0" 1374 + source = "registry+https://github.com/rust-lang/crates.io-index" 1375 + checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5" 1376 + dependencies = [ 1377 + "bitflags", 1378 + ] 1379 + 1380 + [[package]] 1381 + name = "regex-automata" 1382 + version = "0.4.13" 1383 + source = "registry+https://github.com/rust-lang/crates.io-index" 1384 + checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" 1385 + dependencies = [ 1386 + "aho-corasick", 1387 + "memchr", 1388 + "regex-syntax", 1389 + ] 1390 + 1391 + [[package]] 1392 + name = "regex-syntax" 1393 + version = "0.8.8" 1394 + source = "registry+https://github.com/rust-lang/crates.io-index" 1395 + checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" 1396 + 1397 + [[package]] 1398 + name = "reqwest" 1399 + version = "0.12.26" 1400 + source = "registry+https://github.com/rust-lang/crates.io-index" 1401 + checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" 1402 + dependencies = [ 1403 + "base64", 1404 + "bytes", 1405 + "encoding_rs", 1406 + "futures-core", 1407 + "h2", 1408 + "http", 1409 + "http-body", 1410 + "http-body-util", 1411 + "hyper", 1412 + "hyper-rustls", 1413 + "hyper-tls", 1414 + "hyper-util", 1415 + "js-sys", 1416 + "log", 1417 + "mime", 1418 + "native-tls", 1419 + "percent-encoding", 1420 + "pin-project-lite", 1421 + "rustls-pki-types", 1422 + "serde", 1423 + "serde_json", 1424 + "serde_urlencoded", 1425 + "sync_wrapper", 1426 + "tokio", 1427 + "tokio-native-tls", 1428 + "tower", 1429 + "tower-http", 1430 + "tower-service", 1431 + "url", 1432 + "wasm-bindgen", 1433 + "wasm-bindgen-futures", 1434 + "web-sys", 1435 + ] 1436 + 1437 + [[package]] 1438 + name = "ring" 1439 + version = "0.17.14" 1440 + source = "registry+https://github.com/rust-lang/crates.io-index" 1441 + checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1442 + dependencies = [ 1443 + "cc", 1444 + "cfg-if", 1445 + "getrandom 0.2.16", 1446 + "libc", 1447 + "untrusted", 1448 + "windows-sys 0.52.0", 1449 + ] 1450 + 1451 + [[package]] 1452 + name = "rsa" 1453 + version = "0.9.9" 1454 + source = "registry+https://github.com/rust-lang/crates.io-index" 1455 + checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" 1456 + dependencies = [ 1457 + "const-oid", 1458 + "digest", 1459 + "num-bigint-dig", 1460 + "num-integer", 1461 + "num-traits", 1462 + "pkcs1", 1463 + "pkcs8", 1464 + "rand_core 0.6.4", 1465 + "signature", 1466 + "spki", 1467 + "subtle", 1468 + "zeroize", 1469 + ] 1470 + 1471 + [[package]] 1472 + name = "rustix" 1473 + version = "1.1.2" 1474 + source = "registry+https://github.com/rust-lang/crates.io-index" 1475 + checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" 1476 + dependencies = [ 1477 + "bitflags", 1478 + "errno", 1479 + "libc", 1480 + "linux-raw-sys", 1481 + "windows-sys 0.61.2", 1482 + ] 1483 + 1484 + [[package]] 1485 + name = "rustls" 1486 + version = "0.23.35" 1487 + source = "registry+https://github.com/rust-lang/crates.io-index" 1488 + checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" 1489 + dependencies = [ 1490 + "once_cell", 1491 + "rustls-pki-types", 1492 + "rustls-webpki", 1493 + "subtle", 1494 + "zeroize", 1495 + ] 1496 + 1497 + [[package]] 1498 + name = "rustls-pki-types" 1499 + version = "1.13.2" 1500 + source = "registry+https://github.com/rust-lang/crates.io-index" 1501 + checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" 1502 + dependencies = [ 1503 + "zeroize", 1504 + ] 1505 + 1506 + [[package]] 1507 + name = "rustls-webpki" 1508 + version = "0.103.8" 1509 + source = "registry+https://github.com/rust-lang/crates.io-index" 1510 + checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" 1511 + dependencies = [ 1512 + "ring", 1513 + "rustls-pki-types", 1514 + "untrusted", 1515 + ] 1516 + 1517 + [[package]] 1518 + name = "rustversion" 1519 + version = "1.0.22" 1520 + source = "registry+https://github.com/rust-lang/crates.io-index" 1521 + checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 1522 + 1523 + [[package]] 1524 + name = "ryu" 1525 + version = "1.0.20" 1526 + source = "registry+https://github.com/rust-lang/crates.io-index" 1527 + checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1528 + 1529 + [[package]] 1530 + name = "schannel" 1531 + version = "0.1.28" 1532 + source = "registry+https://github.com/rust-lang/crates.io-index" 1533 + checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" 1534 + dependencies = [ 1535 + "windows-sys 0.61.2", 1536 + ] 1537 + 1538 + [[package]] 1539 + name = "scopeguard" 1540 + version = "1.2.0" 1541 + source = "registry+https://github.com/rust-lang/crates.io-index" 1542 + checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1543 + 1544 + [[package]] 1545 + name = "security-framework" 1546 + version = "2.11.1" 1547 + source = "registry+https://github.com/rust-lang/crates.io-index" 1548 + checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1549 + dependencies = [ 1550 + "bitflags", 1551 + "core-foundation", 1552 + "core-foundation-sys", 1553 + "libc", 1554 + "security-framework-sys", 1555 + ] 1556 + 1557 + [[package]] 1558 + name = "security-framework-sys" 1559 + version = "2.15.0" 1560 + source = "registry+https://github.com/rust-lang/crates.io-index" 1561 + checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" 1562 + dependencies = [ 1563 + "core-foundation-sys", 1564 + "libc", 1565 + ] 1566 + 1567 + [[package]] 1568 + name = "serde" 1569 + version = "1.0.228" 1570 + source = "registry+https://github.com/rust-lang/crates.io-index" 1571 + checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 1572 + dependencies = [ 1573 + "serde_core", 1574 + "serde_derive", 1575 + ] 1576 + 1577 + [[package]] 1578 + name = "serde_core" 1579 + version = "1.0.228" 1580 + source = "registry+https://github.com/rust-lang/crates.io-index" 1581 + checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 1582 + dependencies = [ 1583 + "serde_derive", 1584 + ] 1585 + 1586 + [[package]] 1587 + name = "serde_derive" 1588 + version = "1.0.228" 1589 + source = "registry+https://github.com/rust-lang/crates.io-index" 1590 + checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 1591 + dependencies = [ 1592 + "proc-macro2", 1593 + "quote", 1594 + "syn", 1595 + ] 1596 + 1597 + [[package]] 1598 + name = "serde_json" 1599 + version = "1.0.145" 1600 + source = "registry+https://github.com/rust-lang/crates.io-index" 1601 + checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" 1602 + dependencies = [ 1603 + "itoa", 1604 + "memchr", 1605 + "ryu", 1606 + "serde", 1607 + "serde_core", 1608 + ] 1609 + 1610 + [[package]] 1611 + name = "serde_urlencoded" 1612 + version = "0.7.1" 1613 + source = "registry+https://github.com/rust-lang/crates.io-index" 1614 + checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1615 + dependencies = [ 1616 + "form_urlencoded", 1617 + "itoa", 1618 + "ryu", 1619 + "serde", 1620 + ] 1621 + 1622 + [[package]] 1623 + name = "sha1" 1624 + version = "0.10.6" 1625 + source = "registry+https://github.com/rust-lang/crates.io-index" 1626 + checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1627 + dependencies = [ 1628 + "cfg-if", 1629 + "cpufeatures", 1630 + "digest", 1631 + ] 1632 + 1633 + [[package]] 1634 + name = "sha2" 1635 + version = "0.10.9" 1636 + source = "registry+https://github.com/rust-lang/crates.io-index" 1637 + checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 1638 + dependencies = [ 1639 + "cfg-if", 1640 + "cpufeatures", 1641 + "digest", 1642 + ] 1643 + 1644 + [[package]] 1645 + name = "sharded-slab" 1646 + version = "0.1.7" 1647 + source = "registry+https://github.com/rust-lang/crates.io-index" 1648 + checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1649 + dependencies = [ 1650 + "lazy_static", 1651 + ] 1652 + 1653 + [[package]] 1654 + name = "shlex" 1655 + version = "1.3.0" 1656 + source = "registry+https://github.com/rust-lang/crates.io-index" 1657 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1658 + 1659 + [[package]] 1660 + name = "signal-hook-registry" 1661 + version = "1.4.7" 1662 + source = "registry+https://github.com/rust-lang/crates.io-index" 1663 + checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" 1664 + dependencies = [ 1665 + "libc", 1666 + ] 1667 + 1668 + [[package]] 1669 + name = "signature" 1670 + version = "2.2.0" 1671 + source = "registry+https://github.com/rust-lang/crates.io-index" 1672 + checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 1673 + dependencies = [ 1674 + "digest", 1675 + "rand_core 0.6.4", 1676 + ] 1677 + 1678 + [[package]] 1679 + name = "slab" 1680 + version = "0.4.11" 1681 + source = "registry+https://github.com/rust-lang/crates.io-index" 1682 + checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 1683 + 1684 + [[package]] 1685 + name = "smallvec" 1686 + version = "1.15.1" 1687 + source = "registry+https://github.com/rust-lang/crates.io-index" 1688 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1689 + dependencies = [ 1690 + "serde", 1691 + ] 1692 + 1693 + [[package]] 1694 + name = "socket2" 1695 + version = "0.6.1" 1696 + source = "registry+https://github.com/rust-lang/crates.io-index" 1697 + checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" 1698 + dependencies = [ 1699 + "libc", 1700 + "windows-sys 0.60.2", 1701 + ] 1702 + 1703 + [[package]] 1704 + name = "spin" 1705 + version = "0.9.8" 1706 + source = "registry+https://github.com/rust-lang/crates.io-index" 1707 + checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1708 + dependencies = [ 1709 + "lock_api", 1710 + ] 1711 + 1712 + [[package]] 1713 + name = "spki" 1714 + version = "0.7.3" 1715 + source = "registry+https://github.com/rust-lang/crates.io-index" 1716 + checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 1717 + dependencies = [ 1718 + "base64ct", 1719 + "der", 1720 + ] 1721 + 1722 + [[package]] 1723 + name = "sqlx" 1724 + version = "0.8.6" 1725 + source = "registry+https://github.com/rust-lang/crates.io-index" 1726 + checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" 1727 + dependencies = [ 1728 + "sqlx-core", 1729 + "sqlx-macros", 1730 + "sqlx-mysql", 1731 + "sqlx-postgres", 1732 + "sqlx-sqlite", 1733 + ] 1734 + 1735 + [[package]] 1736 + name = "sqlx-core" 1737 + version = "0.8.6" 1738 + source = "registry+https://github.com/rust-lang/crates.io-index" 1739 + checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" 1740 + dependencies = [ 1741 + "base64", 1742 + "bytes", 1743 + "crc", 1744 + "crossbeam-queue", 1745 + "either", 1746 + "event-listener", 1747 + "futures-core", 1748 + "futures-intrusive", 1749 + "futures-io", 1750 + "futures-util", 1751 + "hashbrown 0.15.5", 1752 + "hashlink", 1753 + "indexmap", 1754 + "log", 1755 + "memchr", 1756 + "native-tls", 1757 + "once_cell", 1758 + "percent-encoding", 1759 + "serde", 1760 + "serde_json", 1761 + "sha2", 1762 + "smallvec", 1763 + "thiserror", 1764 + "time", 1765 + "tokio", 1766 + "tokio-stream", 1767 + "tracing", 1768 + "url", 1769 + ] 1770 + 1771 + [[package]] 1772 + name = "sqlx-macros" 1773 + version = "0.8.6" 1774 + source = "registry+https://github.com/rust-lang/crates.io-index" 1775 + checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" 1776 + dependencies = [ 1777 + "proc-macro2", 1778 + "quote", 1779 + "sqlx-core", 1780 + "sqlx-macros-core", 1781 + "syn", 1782 + ] 1783 + 1784 + [[package]] 1785 + name = "sqlx-macros-core" 1786 + version = "0.8.6" 1787 + source = "registry+https://github.com/rust-lang/crates.io-index" 1788 + checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" 1789 + dependencies = [ 1790 + "dotenvy", 1791 + "either", 1792 + "heck", 1793 + "hex", 1794 + "once_cell", 1795 + "proc-macro2", 1796 + "quote", 1797 + "serde", 1798 + "serde_json", 1799 + "sha2", 1800 + "sqlx-core", 1801 + "sqlx-mysql", 1802 + "sqlx-postgres", 1803 + "sqlx-sqlite", 1804 + "syn", 1805 + "tokio", 1806 + "url", 1807 + ] 1808 + 1809 + [[package]] 1810 + name = "sqlx-mysql" 1811 + version = "0.8.6" 1812 + source = "registry+https://github.com/rust-lang/crates.io-index" 1813 + checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" 1814 + dependencies = [ 1815 + "atoi", 1816 + "base64", 1817 + "bitflags", 1818 + "byteorder", 1819 + "bytes", 1820 + "crc", 1821 + "digest", 1822 + "dotenvy", 1823 + "either", 1824 + "futures-channel", 1825 + "futures-core", 1826 + "futures-io", 1827 + "futures-util", 1828 + "generic-array", 1829 + "hex", 1830 + "hkdf", 1831 + "hmac", 1832 + "itoa", 1833 + "log", 1834 + "md-5", 1835 + "memchr", 1836 + "once_cell", 1837 + "percent-encoding", 1838 + "rand 0.8.5", 1839 + "rsa", 1840 + "serde", 1841 + "sha1", 1842 + "sha2", 1843 + "smallvec", 1844 + "sqlx-core", 1845 + "stringprep", 1846 + "thiserror", 1847 + "time", 1848 + "tracing", 1849 + "whoami", 1850 + ] 1851 + 1852 + [[package]] 1853 + name = "sqlx-postgres" 1854 + version = "0.8.6" 1855 + source = "registry+https://github.com/rust-lang/crates.io-index" 1856 + checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" 1857 + dependencies = [ 1858 + "atoi", 1859 + "base64", 1860 + "bitflags", 1861 + "byteorder", 1862 + "crc", 1863 + "dotenvy", 1864 + "etcetera", 1865 + "futures-channel", 1866 + "futures-core", 1867 + "futures-util", 1868 + "hex", 1869 + "hkdf", 1870 + "hmac", 1871 + "home", 1872 + "itoa", 1873 + "log", 1874 + "md-5", 1875 + "memchr", 1876 + "once_cell", 1877 + "rand 0.8.5", 1878 + "serde", 1879 + "serde_json", 1880 + "sha2", 1881 + "smallvec", 1882 + "sqlx-core", 1883 + "stringprep", 1884 + "thiserror", 1885 + "time", 1886 + "tracing", 1887 + "whoami", 1888 + ] 1889 + 1890 + [[package]] 1891 + name = "sqlx-sqlite" 1892 + version = "0.8.6" 1893 + source = "registry+https://github.com/rust-lang/crates.io-index" 1894 + checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" 1895 + dependencies = [ 1896 + "atoi", 1897 + "flume", 1898 + "futures-channel", 1899 + "futures-core", 1900 + "futures-executor", 1901 + "futures-intrusive", 1902 + "futures-util", 1903 + "libsqlite3-sys", 1904 + "log", 1905 + "percent-encoding", 1906 + "serde", 1907 + "serde_urlencoded", 1908 + "sqlx-core", 1909 + "thiserror", 1910 + "time", 1911 + "tracing", 1912 + "url", 1913 + ] 1914 + 1915 + [[package]] 1916 + name = "stable_deref_trait" 1917 + version = "1.2.1" 1918 + source = "registry+https://github.com/rust-lang/crates.io-index" 1919 + checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 1920 + 1921 + [[package]] 1922 + name = "stringprep" 1923 + version = "0.1.5" 1924 + source = "registry+https://github.com/rust-lang/crates.io-index" 1925 + checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" 1926 + dependencies = [ 1927 + "unicode-bidi", 1928 + "unicode-normalization", 1929 + "unicode-properties", 1930 + ] 1931 + 1932 + [[package]] 1933 + name = "strsim" 1934 + version = "0.11.1" 1935 + source = "registry+https://github.com/rust-lang/crates.io-index" 1936 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1937 + 1938 + [[package]] 1939 + name = "subtle" 1940 + version = "2.6.1" 1941 + source = "registry+https://github.com/rust-lang/crates.io-index" 1942 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1943 + 1944 + [[package]] 1945 + name = "syn" 1946 + version = "2.0.111" 1947 + source = "registry+https://github.com/rust-lang/crates.io-index" 1948 + checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" 1949 + dependencies = [ 1950 + "proc-macro2", 1951 + "quote", 1952 + "unicode-ident", 1953 + ] 1954 + 1955 + [[package]] 1956 + name = "sync_wrapper" 1957 + version = "1.0.2" 1958 + source = "registry+https://github.com/rust-lang/crates.io-index" 1959 + checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1960 + dependencies = [ 1961 + "futures-core", 1962 + ] 1963 + 1964 + [[package]] 1965 + name = "synstructure" 1966 + version = "0.13.2" 1967 + source = "registry+https://github.com/rust-lang/crates.io-index" 1968 + checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1969 + dependencies = [ 1970 + "proc-macro2", 1971 + "quote", 1972 + "syn", 1973 + ] 1974 + 1975 + [[package]] 1976 + name = "system-configuration" 1977 + version = "0.6.1" 1978 + source = "registry+https://github.com/rust-lang/crates.io-index" 1979 + checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 1980 + dependencies = [ 1981 + "bitflags", 1982 + "core-foundation", 1983 + "system-configuration-sys", 1984 + ] 1985 + 1986 + [[package]] 1987 + name = "system-configuration-sys" 1988 + version = "0.6.0" 1989 + source = "registry+https://github.com/rust-lang/crates.io-index" 1990 + checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1991 + dependencies = [ 1992 + "core-foundation-sys", 1993 + "libc", 1994 + ] 1995 + 1996 + [[package]] 1997 + name = "tempfile" 1998 + version = "3.23.0" 1999 + source = "registry+https://github.com/rust-lang/crates.io-index" 2000 + checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" 2001 + dependencies = [ 2002 + "fastrand", 2003 + "getrandom 0.3.4", 2004 + "once_cell", 2005 + "rustix", 2006 + "windows-sys 0.61.2", 2007 + ] 2008 + 2009 + [[package]] 2010 + name = "thiserror" 2011 + version = "2.0.17" 2012 + source = "registry+https://github.com/rust-lang/crates.io-index" 2013 + checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" 2014 + dependencies = [ 2015 + "thiserror-impl", 2016 + ] 2017 + 2018 + [[package]] 2019 + name = "thiserror-impl" 2020 + version = "2.0.17" 2021 + source = "registry+https://github.com/rust-lang/crates.io-index" 2022 + checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" 2023 + dependencies = [ 2024 + "proc-macro2", 2025 + "quote", 2026 + "syn", 2027 + ] 2028 + 2029 + [[package]] 2030 + name = "thread_local" 2031 + version = "1.1.9" 2032 + source = "registry+https://github.com/rust-lang/crates.io-index" 2033 + checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" 2034 + dependencies = [ 2035 + "cfg-if", 2036 + ] 2037 + 2038 + [[package]] 2039 + name = "time" 2040 + version = "0.3.44" 2041 + source = "registry+https://github.com/rust-lang/crates.io-index" 2042 + checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" 2043 + dependencies = [ 2044 + "deranged", 2045 + "itoa", 2046 + "num-conv", 2047 + "powerfmt", 2048 + "serde", 2049 + "time-core", 2050 + "time-macros", 2051 + ] 2052 + 2053 + [[package]] 2054 + name = "time-core" 2055 + version = "0.1.6" 2056 + source = "registry+https://github.com/rust-lang/crates.io-index" 2057 + checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" 2058 + 2059 + [[package]] 2060 + name = "time-macros" 2061 + version = "0.2.24" 2062 + source = "registry+https://github.com/rust-lang/crates.io-index" 2063 + checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" 2064 + dependencies = [ 2065 + "num-conv", 2066 + "time-core", 2067 + ] 2068 + 2069 + [[package]] 2070 + name = "tinystr" 2071 + version = "0.8.2" 2072 + source = "registry+https://github.com/rust-lang/crates.io-index" 2073 + checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" 2074 + dependencies = [ 2075 + "displaydoc", 2076 + "zerovec", 2077 + ] 2078 + 2079 + [[package]] 2080 + name = "tinyvec" 2081 + version = "1.10.0" 2082 + source = "registry+https://github.com/rust-lang/crates.io-index" 2083 + checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" 2084 + dependencies = [ 2085 + "tinyvec_macros", 2086 + ] 2087 + 2088 + [[package]] 2089 + name = "tinyvec_macros" 2090 + version = "0.1.1" 2091 + source = "registry+https://github.com/rust-lang/crates.io-index" 2092 + checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2093 + 2094 + [[package]] 2095 + name = "tokio" 2096 + version = "1.48.0" 2097 + source = "registry+https://github.com/rust-lang/crates.io-index" 2098 + checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" 2099 + dependencies = [ 2100 + "bytes", 2101 + "libc", 2102 + "mio", 2103 + "pin-project-lite", 2104 + "signal-hook-registry", 2105 + "socket2", 2106 + "tokio-macros", 2107 + "windows-sys 0.61.2", 2108 + ] 2109 + 2110 + [[package]] 2111 + name = "tokio-macros" 2112 + version = "2.6.0" 2113 + source = "registry+https://github.com/rust-lang/crates.io-index" 2114 + checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" 2115 + dependencies = [ 2116 + "proc-macro2", 2117 + "quote", 2118 + "syn", 2119 + ] 2120 + 2121 + [[package]] 2122 + name = "tokio-native-tls" 2123 + version = "0.3.1" 2124 + source = "registry+https://github.com/rust-lang/crates.io-index" 2125 + checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2126 + dependencies = [ 2127 + "native-tls", 2128 + "tokio", 2129 + ] 2130 + 2131 + [[package]] 2132 + name = "tokio-rustls" 2133 + version = "0.26.4" 2134 + source = "registry+https://github.com/rust-lang/crates.io-index" 2135 + checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" 2136 + dependencies = [ 2137 + "rustls", 2138 + "tokio", 2139 + ] 2140 + 2141 + [[package]] 2142 + name = "tokio-stream" 2143 + version = "0.1.17" 2144 + source = "registry+https://github.com/rust-lang/crates.io-index" 2145 + checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" 2146 + dependencies = [ 2147 + "futures-core", 2148 + "pin-project-lite", 2149 + "tokio", 2150 + ] 2151 + 2152 + [[package]] 2153 + name = "tokio-tungstenite" 2154 + version = "0.28.0" 2155 + source = "registry+https://github.com/rust-lang/crates.io-index" 2156 + checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" 2157 + dependencies = [ 2158 + "futures-util", 2159 + "log", 2160 + "native-tls", 2161 + "tokio", 2162 + "tokio-native-tls", 2163 + "tungstenite", 2164 + ] 2165 + 2166 + [[package]] 2167 + name = "tokio-util" 2168 + version = "0.7.17" 2169 + source = "registry+https://github.com/rust-lang/crates.io-index" 2170 + checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" 2171 + dependencies = [ 2172 + "bytes", 2173 + "futures-core", 2174 + "futures-sink", 2175 + "pin-project-lite", 2176 + "tokio", 2177 + ] 2178 + 2179 + [[package]] 2180 + name = "tower" 2181 + version = "0.5.2" 2182 + source = "registry+https://github.com/rust-lang/crates.io-index" 2183 + checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 2184 + dependencies = [ 2185 + "futures-core", 2186 + "futures-util", 2187 + "pin-project-lite", 2188 + "sync_wrapper", 2189 + "tokio", 2190 + "tower-layer", 2191 + "tower-service", 2192 + ] 2193 + 2194 + [[package]] 2195 + name = "tower-http" 2196 + version = "0.6.8" 2197 + source = "registry+https://github.com/rust-lang/crates.io-index" 2198 + checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" 2199 + dependencies = [ 2200 + "bitflags", 2201 + "bytes", 2202 + "futures-util", 2203 + "http", 2204 + "http-body", 2205 + "iri-string", 2206 + "pin-project-lite", 2207 + "tower", 2208 + "tower-layer", 2209 + "tower-service", 2210 + ] 2211 + 2212 + [[package]] 2213 + name = "tower-layer" 2214 + version = "0.3.3" 2215 + source = "registry+https://github.com/rust-lang/crates.io-index" 2216 + checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 2217 + 2218 + [[package]] 2219 + name = "tower-service" 2220 + version = "0.3.3" 2221 + source = "registry+https://github.com/rust-lang/crates.io-index" 2222 + checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 2223 + 2224 + [[package]] 2225 + name = "tracing" 2226 + version = "0.1.43" 2227 + source = "registry+https://github.com/rust-lang/crates.io-index" 2228 + checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" 2229 + dependencies = [ 2230 + "log", 2231 + "pin-project-lite", 2232 + "tracing-attributes", 2233 + "tracing-core", 2234 + ] 2235 + 2236 + [[package]] 2237 + name = "tracing-attributes" 2238 + version = "0.1.31" 2239 + source = "registry+https://github.com/rust-lang/crates.io-index" 2240 + checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" 2241 + dependencies = [ 2242 + "proc-macro2", 2243 + "quote", 2244 + "syn", 2245 + ] 2246 + 2247 + [[package]] 2248 + name = "tracing-core" 2249 + version = "0.1.35" 2250 + source = "registry+https://github.com/rust-lang/crates.io-index" 2251 + checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" 2252 + dependencies = [ 2253 + "once_cell", 2254 + "valuable", 2255 + ] 2256 + 2257 + [[package]] 2258 + name = "tracing-log" 2259 + version = "0.2.0" 2260 + source = "registry+https://github.com/rust-lang/crates.io-index" 2261 + checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2262 + dependencies = [ 2263 + "log", 2264 + "once_cell", 2265 + "tracing-core", 2266 + ] 2267 + 2268 + [[package]] 2269 + name = "tracing-subscriber" 2270 + version = "0.3.22" 2271 + source = "registry+https://github.com/rust-lang/crates.io-index" 2272 + checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" 2273 + dependencies = [ 2274 + "matchers", 2275 + "nu-ansi-term", 2276 + "once_cell", 2277 + "regex-automata", 2278 + "sharded-slab", 2279 + "smallvec", 2280 + "thread_local", 2281 + "tracing", 2282 + "tracing-core", 2283 + "tracing-log", 2284 + ] 2285 + 2286 + [[package]] 2287 + name = "trap" 2288 + version = "0.0.0" 2289 + dependencies = [ 2290 + "anyhow", 2291 + "clap", 2292 + "data-encoding", 2293 + "futures-util", 2294 + "reqwest", 2295 + "serde", 2296 + "serde_json", 2297 + "sqlx", 2298 + "thiserror", 2299 + "tokio", 2300 + "tokio-tungstenite", 2301 + "tracing", 2302 + "tracing-subscriber", 2303 + "url", 2304 + ] 2305 + 2306 + [[package]] 2307 + name = "try-lock" 2308 + version = "0.2.5" 2309 + source = "registry+https://github.com/rust-lang/crates.io-index" 2310 + checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2311 + 2312 + [[package]] 2313 + name = "tungstenite" 2314 + version = "0.28.0" 2315 + source = "registry+https://github.com/rust-lang/crates.io-index" 2316 + checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" 2317 + dependencies = [ 2318 + "bytes", 2319 + "data-encoding", 2320 + "http", 2321 + "httparse", 2322 + "log", 2323 + "native-tls", 2324 + "rand 0.9.2", 2325 + "sha1", 2326 + "thiserror", 2327 + "utf-8", 2328 + ] 2329 + 2330 + [[package]] 2331 + name = "typenum" 2332 + version = "1.19.0" 2333 + source = "registry+https://github.com/rust-lang/crates.io-index" 2334 + checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" 2335 + 2336 + [[package]] 2337 + name = "unicode-bidi" 2338 + version = "0.3.18" 2339 + source = "registry+https://github.com/rust-lang/crates.io-index" 2340 + checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" 2341 + 2342 + [[package]] 2343 + name = "unicode-ident" 2344 + version = "1.0.22" 2345 + source = "registry+https://github.com/rust-lang/crates.io-index" 2346 + checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 2347 + 2348 + [[package]] 2349 + name = "unicode-normalization" 2350 + version = "0.1.25" 2351 + source = "registry+https://github.com/rust-lang/crates.io-index" 2352 + checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" 2353 + dependencies = [ 2354 + "tinyvec", 2355 + ] 2356 + 2357 + [[package]] 2358 + name = "unicode-properties" 2359 + version = "0.1.4" 2360 + source = "registry+https://github.com/rust-lang/crates.io-index" 2361 + checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" 2362 + 2363 + [[package]] 2364 + name = "untrusted" 2365 + version = "0.9.0" 2366 + source = "registry+https://github.com/rust-lang/crates.io-index" 2367 + checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2368 + 2369 + [[package]] 2370 + name = "url" 2371 + version = "2.5.7" 2372 + source = "registry+https://github.com/rust-lang/crates.io-index" 2373 + checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 2374 + dependencies = [ 2375 + "form_urlencoded", 2376 + "idna", 2377 + "percent-encoding", 2378 + "serde", 2379 + ] 2380 + 2381 + [[package]] 2382 + name = "utf-8" 2383 + version = "0.7.6" 2384 + source = "registry+https://github.com/rust-lang/crates.io-index" 2385 + checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 2386 + 2387 + [[package]] 2388 + name = "utf8_iter" 2389 + version = "1.0.4" 2390 + source = "registry+https://github.com/rust-lang/crates.io-index" 2391 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 2392 + 2393 + [[package]] 2394 + name = "utf8parse" 2395 + version = "0.2.2" 2396 + source = "registry+https://github.com/rust-lang/crates.io-index" 2397 + checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 2398 + 2399 + [[package]] 2400 + name = "valuable" 2401 + version = "0.1.1" 2402 + source = "registry+https://github.com/rust-lang/crates.io-index" 2403 + checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 2404 + 2405 + [[package]] 2406 + name = "vcpkg" 2407 + version = "0.2.15" 2408 + source = "registry+https://github.com/rust-lang/crates.io-index" 2409 + checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2410 + 2411 + [[package]] 2412 + name = "version_check" 2413 + version = "0.9.5" 2414 + source = "registry+https://github.com/rust-lang/crates.io-index" 2415 + checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2416 + 2417 + [[package]] 2418 + name = "want" 2419 + version = "0.3.1" 2420 + source = "registry+https://github.com/rust-lang/crates.io-index" 2421 + checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2422 + dependencies = [ 2423 + "try-lock", 2424 + ] 2425 + 2426 + [[package]] 2427 + name = "wasi" 2428 + version = "0.11.1+wasi-snapshot-preview1" 2429 + source = "registry+https://github.com/rust-lang/crates.io-index" 2430 + checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 2431 + 2432 + [[package]] 2433 + name = "wasip2" 2434 + version = "1.0.1+wasi-0.2.4" 2435 + source = "registry+https://github.com/rust-lang/crates.io-index" 2436 + checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" 2437 + dependencies = [ 2438 + "wit-bindgen", 2439 + ] 2440 + 2441 + [[package]] 2442 + name = "wasite" 2443 + version = "0.1.0" 2444 + source = "registry+https://github.com/rust-lang/crates.io-index" 2445 + checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" 2446 + 2447 + [[package]] 2448 + name = "wasm-bindgen" 2449 + version = "0.2.106" 2450 + source = "registry+https://github.com/rust-lang/crates.io-index" 2451 + checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" 2452 + dependencies = [ 2453 + "cfg-if", 2454 + "once_cell", 2455 + "rustversion", 2456 + "wasm-bindgen-macro", 2457 + "wasm-bindgen-shared", 2458 + ] 2459 + 2460 + [[package]] 2461 + name = "wasm-bindgen-futures" 2462 + version = "0.4.56" 2463 + source = "registry+https://github.com/rust-lang/crates.io-index" 2464 + checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" 2465 + dependencies = [ 2466 + "cfg-if", 2467 + "js-sys", 2468 + "once_cell", 2469 + "wasm-bindgen", 2470 + "web-sys", 2471 + ] 2472 + 2473 + [[package]] 2474 + name = "wasm-bindgen-macro" 2475 + version = "0.2.106" 2476 + source = "registry+https://github.com/rust-lang/crates.io-index" 2477 + checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" 2478 + dependencies = [ 2479 + "quote", 2480 + "wasm-bindgen-macro-support", 2481 + ] 2482 + 2483 + [[package]] 2484 + name = "wasm-bindgen-macro-support" 2485 + version = "0.2.106" 2486 + source = "registry+https://github.com/rust-lang/crates.io-index" 2487 + checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" 2488 + dependencies = [ 2489 + "bumpalo", 2490 + "proc-macro2", 2491 + "quote", 2492 + "syn", 2493 + "wasm-bindgen-shared", 2494 + ] 2495 + 2496 + [[package]] 2497 + name = "wasm-bindgen-shared" 2498 + version = "0.2.106" 2499 + source = "registry+https://github.com/rust-lang/crates.io-index" 2500 + checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" 2501 + dependencies = [ 2502 + "unicode-ident", 2503 + ] 2504 + 2505 + [[package]] 2506 + name = "web-sys" 2507 + version = "0.3.83" 2508 + source = "registry+https://github.com/rust-lang/crates.io-index" 2509 + checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" 2510 + dependencies = [ 2511 + "js-sys", 2512 + "wasm-bindgen", 2513 + ] 2514 + 2515 + [[package]] 2516 + name = "whoami" 2517 + version = "1.6.1" 2518 + source = "registry+https://github.com/rust-lang/crates.io-index" 2519 + checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" 2520 + dependencies = [ 2521 + "libredox", 2522 + "wasite", 2523 + ] 2524 + 2525 + [[package]] 2526 + name = "windows-link" 2527 + version = "0.2.1" 2528 + source = "registry+https://github.com/rust-lang/crates.io-index" 2529 + checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 2530 + 2531 + [[package]] 2532 + name = "windows-registry" 2533 + version = "0.6.1" 2534 + source = "registry+https://github.com/rust-lang/crates.io-index" 2535 + checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 2536 + dependencies = [ 2537 + "windows-link", 2538 + "windows-result", 2539 + "windows-strings", 2540 + ] 2541 + 2542 + [[package]] 2543 + name = "windows-result" 2544 + version = "0.4.1" 2545 + source = "registry+https://github.com/rust-lang/crates.io-index" 2546 + checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 2547 + dependencies = [ 2548 + "windows-link", 2549 + ] 2550 + 2551 + [[package]] 2552 + name = "windows-strings" 2553 + version = "0.5.1" 2554 + source = "registry+https://github.com/rust-lang/crates.io-index" 2555 + checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 2556 + dependencies = [ 2557 + "windows-link", 2558 + ] 2559 + 2560 + [[package]] 2561 + name = "windows-sys" 2562 + version = "0.48.0" 2563 + source = "registry+https://github.com/rust-lang/crates.io-index" 2564 + checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2565 + dependencies = [ 2566 + "windows-targets 0.48.5", 2567 + ] 2568 + 2569 + [[package]] 2570 + name = "windows-sys" 2571 + version = "0.52.0" 2572 + source = "registry+https://github.com/rust-lang/crates.io-index" 2573 + checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2574 + dependencies = [ 2575 + "windows-targets 0.52.6", 2576 + ] 2577 + 2578 + [[package]] 2579 + name = "windows-sys" 2580 + version = "0.60.2" 2581 + source = "registry+https://github.com/rust-lang/crates.io-index" 2582 + checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 2583 + dependencies = [ 2584 + "windows-targets 0.53.5", 2585 + ] 2586 + 2587 + [[package]] 2588 + name = "windows-sys" 2589 + version = "0.61.2" 2590 + source = "registry+https://github.com/rust-lang/crates.io-index" 2591 + checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 2592 + dependencies = [ 2593 + "windows-link", 2594 + ] 2595 + 2596 + [[package]] 2597 + name = "windows-targets" 2598 + version = "0.48.5" 2599 + source = "registry+https://github.com/rust-lang/crates.io-index" 2600 + checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2601 + dependencies = [ 2602 + "windows_aarch64_gnullvm 0.48.5", 2603 + "windows_aarch64_msvc 0.48.5", 2604 + "windows_i686_gnu 0.48.5", 2605 + "windows_i686_msvc 0.48.5", 2606 + "windows_x86_64_gnu 0.48.5", 2607 + "windows_x86_64_gnullvm 0.48.5", 2608 + "windows_x86_64_msvc 0.48.5", 2609 + ] 2610 + 2611 + [[package]] 2612 + name = "windows-targets" 2613 + version = "0.52.6" 2614 + source = "registry+https://github.com/rust-lang/crates.io-index" 2615 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2616 + dependencies = [ 2617 + "windows_aarch64_gnullvm 0.52.6", 2618 + "windows_aarch64_msvc 0.52.6", 2619 + "windows_i686_gnu 0.52.6", 2620 + "windows_i686_gnullvm 0.52.6", 2621 + "windows_i686_msvc 0.52.6", 2622 + "windows_x86_64_gnu 0.52.6", 2623 + "windows_x86_64_gnullvm 0.52.6", 2624 + "windows_x86_64_msvc 0.52.6", 2625 + ] 2626 + 2627 + [[package]] 2628 + name = "windows-targets" 2629 + version = "0.53.5" 2630 + source = "registry+https://github.com/rust-lang/crates.io-index" 2631 + checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 2632 + dependencies = [ 2633 + "windows-link", 2634 + "windows_aarch64_gnullvm 0.53.1", 2635 + "windows_aarch64_msvc 0.53.1", 2636 + "windows_i686_gnu 0.53.1", 2637 + "windows_i686_gnullvm 0.53.1", 2638 + "windows_i686_msvc 0.53.1", 2639 + "windows_x86_64_gnu 0.53.1", 2640 + "windows_x86_64_gnullvm 0.53.1", 2641 + "windows_x86_64_msvc 0.53.1", 2642 + ] 2643 + 2644 + [[package]] 2645 + name = "windows_aarch64_gnullvm" 2646 + version = "0.48.5" 2647 + source = "registry+https://github.com/rust-lang/crates.io-index" 2648 + checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2649 + 2650 + [[package]] 2651 + name = "windows_aarch64_gnullvm" 2652 + version = "0.52.6" 2653 + source = "registry+https://github.com/rust-lang/crates.io-index" 2654 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2655 + 2656 + [[package]] 2657 + name = "windows_aarch64_gnullvm" 2658 + version = "0.53.1" 2659 + source = "registry+https://github.com/rust-lang/crates.io-index" 2660 + checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 2661 + 2662 + [[package]] 2663 + name = "windows_aarch64_msvc" 2664 + version = "0.48.5" 2665 + source = "registry+https://github.com/rust-lang/crates.io-index" 2666 + checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2667 + 2668 + [[package]] 2669 + name = "windows_aarch64_msvc" 2670 + version = "0.52.6" 2671 + source = "registry+https://github.com/rust-lang/crates.io-index" 2672 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2673 + 2674 + [[package]] 2675 + name = "windows_aarch64_msvc" 2676 + version = "0.53.1" 2677 + source = "registry+https://github.com/rust-lang/crates.io-index" 2678 + checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 2679 + 2680 + [[package]] 2681 + name = "windows_i686_gnu" 2682 + version = "0.48.5" 2683 + source = "registry+https://github.com/rust-lang/crates.io-index" 2684 + checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2685 + 2686 + [[package]] 2687 + name = "windows_i686_gnu" 2688 + version = "0.52.6" 2689 + source = "registry+https://github.com/rust-lang/crates.io-index" 2690 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2691 + 2692 + [[package]] 2693 + name = "windows_i686_gnu" 2694 + version = "0.53.1" 2695 + source = "registry+https://github.com/rust-lang/crates.io-index" 2696 + checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 2697 + 2698 + [[package]] 2699 + name = "windows_i686_gnullvm" 2700 + version = "0.52.6" 2701 + source = "registry+https://github.com/rust-lang/crates.io-index" 2702 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2703 + 2704 + [[package]] 2705 + name = "windows_i686_gnullvm" 2706 + version = "0.53.1" 2707 + source = "registry+https://github.com/rust-lang/crates.io-index" 2708 + checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 2709 + 2710 + [[package]] 2711 + name = "windows_i686_msvc" 2712 + version = "0.48.5" 2713 + source = "registry+https://github.com/rust-lang/crates.io-index" 2714 + checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2715 + 2716 + [[package]] 2717 + name = "windows_i686_msvc" 2718 + version = "0.52.6" 2719 + source = "registry+https://github.com/rust-lang/crates.io-index" 2720 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2721 + 2722 + [[package]] 2723 + name = "windows_i686_msvc" 2724 + version = "0.53.1" 2725 + source = "registry+https://github.com/rust-lang/crates.io-index" 2726 + checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 2727 + 2728 + [[package]] 2729 + name = "windows_x86_64_gnu" 2730 + version = "0.48.5" 2731 + source = "registry+https://github.com/rust-lang/crates.io-index" 2732 + checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2733 + 2734 + [[package]] 2735 + name = "windows_x86_64_gnu" 2736 + version = "0.52.6" 2737 + source = "registry+https://github.com/rust-lang/crates.io-index" 2738 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2739 + 2740 + [[package]] 2741 + name = "windows_x86_64_gnu" 2742 + version = "0.53.1" 2743 + source = "registry+https://github.com/rust-lang/crates.io-index" 2744 + checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 2745 + 2746 + [[package]] 2747 + name = "windows_x86_64_gnullvm" 2748 + version = "0.48.5" 2749 + source = "registry+https://github.com/rust-lang/crates.io-index" 2750 + checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2751 + 2752 + [[package]] 2753 + name = "windows_x86_64_gnullvm" 2754 + version = "0.52.6" 2755 + source = "registry+https://github.com/rust-lang/crates.io-index" 2756 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2757 + 2758 + [[package]] 2759 + name = "windows_x86_64_gnullvm" 2760 + version = "0.53.1" 2761 + source = "registry+https://github.com/rust-lang/crates.io-index" 2762 + checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 2763 + 2764 + [[package]] 2765 + name = "windows_x86_64_msvc" 2766 + version = "0.48.5" 2767 + source = "registry+https://github.com/rust-lang/crates.io-index" 2768 + checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2769 + 2770 + [[package]] 2771 + name = "windows_x86_64_msvc" 2772 + version = "0.52.6" 2773 + source = "registry+https://github.com/rust-lang/crates.io-index" 2774 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2775 + 2776 + [[package]] 2777 + name = "windows_x86_64_msvc" 2778 + version = "0.53.1" 2779 + source = "registry+https://github.com/rust-lang/crates.io-index" 2780 + checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 2781 + 2782 + [[package]] 2783 + name = "wit-bindgen" 2784 + version = "0.46.0" 2785 + source = "registry+https://github.com/rust-lang/crates.io-index" 2786 + checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 2787 + 2788 + [[package]] 2789 + name = "writeable" 2790 + version = "0.6.2" 2791 + source = "registry+https://github.com/rust-lang/crates.io-index" 2792 + checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 2793 + 2794 + [[package]] 2795 + name = "yoke" 2796 + version = "0.8.1" 2797 + source = "registry+https://github.com/rust-lang/crates.io-index" 2798 + checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" 2799 + dependencies = [ 2800 + "stable_deref_trait", 2801 + "yoke-derive", 2802 + "zerofrom", 2803 + ] 2804 + 2805 + [[package]] 2806 + name = "yoke-derive" 2807 + version = "0.8.1" 2808 + source = "registry+https://github.com/rust-lang/crates.io-index" 2809 + checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" 2810 + dependencies = [ 2811 + "proc-macro2", 2812 + "quote", 2813 + "syn", 2814 + "synstructure", 2815 + ] 2816 + 2817 + [[package]] 2818 + name = "zerocopy" 2819 + version = "0.8.31" 2820 + source = "registry+https://github.com/rust-lang/crates.io-index" 2821 + checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" 2822 + dependencies = [ 2823 + "zerocopy-derive", 2824 + ] 2825 + 2826 + [[package]] 2827 + name = "zerocopy-derive" 2828 + version = "0.8.31" 2829 + source = "registry+https://github.com/rust-lang/crates.io-index" 2830 + checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" 2831 + dependencies = [ 2832 + "proc-macro2", 2833 + "quote", 2834 + "syn", 2835 + ] 2836 + 2837 + [[package]] 2838 + name = "zerofrom" 2839 + version = "0.1.6" 2840 + source = "registry+https://github.com/rust-lang/crates.io-index" 2841 + checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2842 + dependencies = [ 2843 + "zerofrom-derive", 2844 + ] 2845 + 2846 + [[package]] 2847 + name = "zerofrom-derive" 2848 + version = "0.1.6" 2849 + source = "registry+https://github.com/rust-lang/crates.io-index" 2850 + checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2851 + dependencies = [ 2852 + "proc-macro2", 2853 + "quote", 2854 + "syn", 2855 + "synstructure", 2856 + ] 2857 + 2858 + [[package]] 2859 + name = "zeroize" 2860 + version = "1.8.2" 2861 + source = "registry+https://github.com/rust-lang/crates.io-index" 2862 + checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" 2863 + 2864 + [[package]] 2865 + name = "zerotrie" 2866 + version = "0.2.3" 2867 + source = "registry+https://github.com/rust-lang/crates.io-index" 2868 + checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" 2869 + dependencies = [ 2870 + "displaydoc", 2871 + "yoke", 2872 + "zerofrom", 2873 + ] 2874 + 2875 + [[package]] 2876 + name = "zerovec" 2877 + version = "0.11.5" 2878 + source = "registry+https://github.com/rust-lang/crates.io-index" 2879 + checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" 2880 + dependencies = [ 2881 + "yoke", 2882 + "zerofrom", 2883 + "zerovec-derive", 2884 + ] 2885 + 2886 + [[package]] 2887 + name = "zerovec-derive" 2888 + version = "0.11.2" 2889 + source = "registry+https://github.com/rust-lang/crates.io-index" 2890 + checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" 2891 + dependencies = [ 2892 + "proc-macro2", 2893 + "quote", 2894 + "syn", 2895 + ]
+26
Cargo.toml
···
··· 1 + [package] 2 + name = "trap" 3 + version= "0.0.0" 4 + edition = "2024" 5 + publish = false 6 + 7 + [dependencies] 8 + anyhow = "1.0.100" 9 + clap = { version = "4.5.53", features = ["derive", "env"] } 10 + data-encoding = "2.9.0" 11 + futures-util = { version = "0.3.31", features = ["sink"] } 12 + reqwest = { version = "0.12.26", features = ["json"] } 13 + serde = { version = "1.0.228", features = ["derive"] } 14 + serde_json = "1.0.145" 15 + sqlx = { version = "0.8.6", features = ["runtime-tokio", "tls-native-tls", "postgres", "time", "json", "macros", "derive"] } 16 + thiserror = "2.0.17" 17 + tokio = { version = "1.47.1", features = ["io-util", "macros", "net", "process", "signal", "rt-multi-thread"] } 18 + tokio-tungstenite = { version = "0.28.0", features = ["native-tls"] } 19 + tracing = "0.1.43" 20 + tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } 21 + url = "2.5.7" 22 + 23 + [profile.release] 24 + panic = "abort" 25 + lto = "fat" 26 + strip = true
+102
README.md
···
··· 1 + # Trap 2 + 3 + Traverse records received from a Tap service and dump into a PostgreSQL database. 4 + 5 + ## Example Usage 6 + 7 + In this example we'll *tap into* (😉) everything in the "sh.tangled.*" NSID starting from the @tangled.org repo (ATproto repo, not git repo). 8 + 9 + 1. Setup a PostgreSQL cluster and create a database 10 + 11 + ... 12 + 13 + Let's assume you've created a DB called `trap_tangled`. 14 + 15 + 2. Tap 16 + 17 + ```bash 18 + TAP_COLLECTION_FILTERS="sh.tangled.*" TAP_BIND=127.0.0.1:2480 tap run 19 + ``` 20 + 21 + `trap` will collect *any* records the Tap service sends. You can control this with the `TAP_COLLECTION_FILTERS` variable. 22 + 23 + 3. Trap 24 + 25 + Run `trap`, seeding from the DID of @tangled.org: 26 + 27 + ```bash 28 + RUST_LOG=debug,sqlx=warn INDEX_DATABASE_URL=postgresql:///trap_tangled trap --seed did:plc:wshs7t2adsemcrrd4snkeqli 29 + ``` 30 + 31 + `trap` will submit the seed DIDs to the Tap service. Each record return by Tap will be scanned, and any DIDs found will also be added to the Tap service. 32 + 33 + 4. Wait. 34 + 35 + *Eventually*, and I mean *eventually*, you'll end up with a table named `record` filled with every "sh.tangled.*" record reachable from the @tangled.org repo. 36 + 37 + 5. Perform *Data Science* 38 + 39 + Time to jump into `psql`! 40 + 41 + The `record_by_collection` view counts how many records have been indexed for each collection. 42 + 43 + ``` 44 + trap_tangled=# select * from record_by_collection ; 45 + collection | count 46 + -------------------------------+------- 47 + sh.tangled.feed.star | 5350 48 + sh.tangled.spindle.member | 4821 49 + sh.tangled.graph.follow | 4425 50 + sh.tangled.knot.member | 3607 51 + sh.tangled.repo | 2618 52 + sh.tangled.repo.pull | 1785 53 + sh.tangled.repo.issue | 1390 54 + sh.tangled.repo.issue.comment | 1386 55 + sh.tangled.publicKey | 1298 56 + sh.tangled.repo.pull.comment | 1127 57 + sh.tangled.actor.profile | 713 58 + sh.tangled.label.op | 628 59 + sh.tangled.feed.reaction | 479 60 + sh.tangled.string | 364 61 + sh.tangled.repo.issue.state | 320 62 + sh.tangled.knot | 158 63 + sh.tangled.repo.collaborator | 146 64 + sh.tangled.label.definition | 106 65 + sh.tangled.repo.artifact | 69 66 + sh.tangled.spindle | 51 67 + (20 rows) 68 + 69 + trap_tangled=# 70 + ``` 71 + 72 + Analyse SSH public-key statistics: 73 + 74 + ``` 75 + trap_tangled=# SELECT split_part(data->>'key', ' ', 1) AS key_type, 76 + count(*) AS count 77 + FROM record 78 + WHERE collection = 'sh.tangled.publicKey' 79 + GROUP BY (split_part(data->>'key', ' ', 1)) 80 + ORDER BY (count(*)) DESC; 81 + key_type | count 82 + ------------------------------------+------- 83 + ssh-ed25519 | 989 84 + ssh-rsa | 239 85 + sk-ssh-ed25519@openssh.com | 44 86 + ecdsa-sha2-nistp256 | 22 87 + sh-ed25519 | 2 88 + sk-ecdsa-sha2-nistp256@openssh.com | 1 89 + ecdsa-sha2-nistp521 | 1 90 + (7 rows) 91 + 92 + trap_tangled=# 93 + ``` 94 + 95 + Fascinating! 96 + 97 + ## Future work 98 + 99 + ???? 100 + 101 + Suggestions and PRs welcome! 102 +
+10
migrations/20251216142421_init.down.sql
···
··· 1 + DROP VIEW record_by_collection; 2 + 3 + DROP INDEX identity_handle_idx; 4 + DROP TABLE identity; 5 + DROP TYPE identity_status; 6 + 7 + DROP TABLE deleted_record; 8 + 9 + DROP INDEX record_collection_idx; 10 + DROP TABLE record;
+48
migrations/20251216142421_init.up.sql
···
··· 1 + CREATE TABLE IF NOT EXISTS record ( 2 + did text NOT NULL, 3 + collection text NOT NULL, 4 + rkey text NOT NULL, 5 + rev text NOT NULL, 6 + cid text NOT NULL, 7 + live boolean NOT NULL, 8 + data jsonb NOT NULL, 9 + 10 + PRIMARY KEY (did, collection, rkey) 11 + ); 12 + 13 + CREATE INDEX ON record (collection); 14 + 15 + CREATE TABLE IF NOT EXISTS deleted_record ( 16 + LIKE record 17 + INCLUDING all 18 + ); 19 + 20 + DO $$ BEGIN 21 + CREATE TYPE identity_status AS ENUM ( 22 + 'active', 23 + 'takendown', 24 + 'suspended', 25 + 'deactivated', 26 + 'deleted' 27 + ); 28 + EXCEPTION 29 + WHEN duplicate_object THEN null; 30 + END $$; 31 + 32 + CREATE TABLE IF NOT EXISTS identity ( 33 + did text NOT NULL, 34 + handle text NOT NULL, 35 + active boolean NOT NULL, 36 + status identity_status NOT NULL, 37 + 38 + PRIMARY KEY (did) 39 + ); 40 + 41 + CREATE INDEX ON identity (handle); 42 + 43 + CREATE OR REPLACE VIEW record_by_collection AS 44 + SELECT collection, 45 + count(*) AS count 46 + FROM record 47 + GROUP BY collection 48 + ORDER BY (count(*)) DESC;
+7
queries/upsert_record.sql
···
··· 1 + INSERT INTO record (did, collection, rkey, rev, cid, live, data) 2 + VALUES ($1, $2, $3, $4, $5, $6, $7) 3 + ON CONFLICT 4 + ON CONSTRAINT record_pkey 5 + DO UPDATE 6 + SET (rev, cid, live, data) = (EXCLUDED.rev, EXCLUDED.cid, EXCLUDED.live, EXCLUDED.data) 7 + WHERE EXCLUDED.rev > record.rev
+3
rust-toolchain.toml
···
··· 1 + [toolchain] 2 + channel = "stable" 3 + profile = "default"
+31
src/cli.rs
···
··· 1 + use clap::Parser; 2 + use url::Url; 3 + 4 + /// Traverse records from Tap, saving to a PostgreSQL DB. 5 + #[derive(Debug, Parser)] 6 + pub struct Arguments { 7 + /// URL for the PostgreSQL database. 8 + #[arg(long, short = 'd', env = "TAP_DUMP_DATABASE_URL")] 9 + pub db: Url, 10 + 11 + /// URL for the Tap service. 12 + #[arg( 13 + long, 14 + short = 'H', 15 + env = "TAP_DUMP_TAP_URL", 16 + default_value = "http://localhost:2480" 17 + )] 18 + pub tap: Url, 19 + 20 + /// Admin password for the Tap service. 21 + #[arg(long, short = 'p', env = "TAP_DUMP_TAP_PASSWORD")] 22 + pub tap_password: Option<String>, 23 + 24 + /// DIDs to seed from. 25 + #[arg(long, value_delimiter = ',', env = "TAP_DUMP_SEED")] 26 + pub seed: Vec<String>, 27 + } 28 + 29 + pub fn parse() -> Arguments { 30 + Arguments::parse() 31 + }
+2
src/lib.rs
···
··· 1 + pub mod tap; 2 + pub mod util;
+305
src/main.rs
···
··· 1 + mod cli; 2 + mod query; 3 + 4 + use std::{ 5 + collections::{HashSet, VecDeque}, 6 + io, 7 + ops::ControlFlow::{self, *}, 8 + time::Duration, 9 + }; 10 + 11 + use futures_util::StreamExt; 12 + use serde_json::Value; 13 + use sqlx::PgPool; 14 + use tokio::{ 15 + sync::{mpsc, watch}, 16 + task::JoinSet, 17 + }; 18 + use tracing::level_filters::LevelFilter; 19 + use tracing_subscriber::{EnvFilter, layer::SubscriberExt as _, util::SubscriberInitExt as _}; 20 + use trap::{ 21 + tap::{IdentityEvent, RecordAction, RecordEvent, TapChannel, TapClient, TapEvent}, 22 + util::with_shutdown, 23 + }; 24 + 25 + /// DID provenance. 26 + #[derive(Debug)] 27 + #[allow(unused)] 28 + enum DidSource { 29 + Seed, 30 + Record(Box<str>), 31 + } 32 + 33 + #[tokio::main] 34 + async fn main() -> anyhow::Result<()> { 35 + setup_tracing()?; 36 + 37 + let arguments = cli::parse(); 38 + let pool = PgPool::connect(arguments.db.as_str()).await?; 39 + let version = db_version(&pool).await?; 40 + tracing::info!(%version, "connected to db"); 41 + 42 + sqlx::migrate!().run(&pool).await?; 43 + 44 + let (shutdown_tx, shutdown_rx) = watch::channel(false); 45 + let (did_tx, did_rx) = mpsc::unbounded_channel::<(String, DidSource)>(); 46 + 47 + let tap = TapClient::new(arguments.tap, arguments.tap_password.as_deref())?; 48 + let (tap_channel, tap_task) = tap.channel(); 49 + 50 + let mut tasks = JoinSet::new(); 51 + tasks.spawn(async move { 52 + let unsent_acks = tap_task.await?; 53 + if !unsent_acks.is_empty() { 54 + tracing::error!(?unsent_acks, "failed to clear Acks"); 55 + } 56 + Ok(()) 57 + }); 58 + 59 + tasks.spawn(event_consumer( 60 + tap_channel, 61 + pool.clone(), 62 + did_tx.clone(), 63 + shutdown_rx.clone(), 64 + )); 65 + 66 + tasks.spawn(did_task(tap, pool, did_rx, shutdown_rx.clone())); 67 + tasks.spawn(shutdown_task(shutdown_tx.clone())); 68 + 69 + // Submit seed DIDs to the Tap service. 70 + for did in arguments.seed.into_iter().filter(|s| possible_did(s)) { 71 + did_tx.send((did, DidSource::Seed))?; 72 + } 73 + 74 + for task in tasks.join_all().await { 75 + if let Err(error) = task { 76 + tracing::error!(?error, "task failed"); 77 + shutdown_tx.send(true)?; 78 + } 79 + } 80 + 81 + Ok(()) 82 + } 83 + 84 + fn setup_tracing() -> anyhow::Result<()> { 85 + tracing_subscriber::registry() 86 + .with( 87 + EnvFilter::builder() 88 + .with_default_directive(LevelFilter::INFO.into()) 89 + .from_env()?, 90 + ) 91 + .with(tracing_subscriber::fmt::layer().with_writer(io::stderr)) 92 + .try_init()?; 93 + 94 + Ok(()) 95 + } 96 + 97 + async fn db_version(pool: &PgPool) -> sqlx::Result<String> { 98 + let row: (String,) = sqlx::query_as("SELECT version()").fetch_one(pool).await?; 99 + Ok(row.0) 100 + } 101 + 102 + #[tracing::instrument(skip(channel, pool, tx, rx))] 103 + async fn event_consumer( 104 + mut channel: TapChannel, 105 + pool: PgPool, 106 + tx: mpsc::UnboundedSender<(String, DidSource)>, 107 + mut rx: watch::Receiver<bool>, 108 + ) -> anyhow::Result<()> { 109 + use ControlFlow::Continue; 110 + 111 + while let Continue(Some((event, ack))) = with_shutdown(channel.recv(), &mut rx).await { 112 + let mut transaction = pool.begin().await?; 113 + match event { 114 + TapEvent::Record(record) => { 115 + let (record, parsed_record) = handle_record(record, &mut transaction).await?; 116 + 117 + // Expand the network of tracked DIDs. 118 + let nsid = record.collection.into_boxed_str(); 119 + for did in extract_dids(&parsed_record) { 120 + tx.send((did, DidSource::Record(nsid.clone())))?; 121 + } 122 + } 123 + TapEvent::Identity(identity) => { 124 + handle_identity(identity, &mut transaction).await?; 125 + } 126 + } 127 + 128 + transaction.commit().await?; 129 + ack.acknowledge().await?; 130 + } 131 + 132 + tracing::info!("complete"); 133 + Ok(()) 134 + } 135 + 136 + async fn handle_identity( 137 + identity_event: IdentityEvent, 138 + transaction: &mut sqlx::Transaction<'static, sqlx::Postgres>, 139 + ) -> anyhow::Result<()> { 140 + let IdentityEvent { 141 + id: _, 142 + did, 143 + handle, 144 + is_active, 145 + status, 146 + } = identity_event; 147 + 148 + query::upsert_identity(&did, &handle, &status, is_active) 149 + .execute(&mut **transaction) 150 + .await?; 151 + 152 + Ok(()) 153 + } 154 + 155 + async fn handle_record( 156 + record_event: RecordEvent, 157 + transaction: &mut sqlx::Transaction<'static, sqlx::Postgres>, 158 + ) -> anyhow::Result<(RecordEvent, Value)> { 159 + let RecordEvent { 160 + id: _, 161 + did, 162 + rev, 163 + collection, 164 + rkey, 165 + action, 166 + record, 167 + cid, 168 + live, 169 + } = &record_event; 170 + 171 + let parsed_record: Value = record 172 + .as_ref() 173 + .map(|record| serde_json::from_str(record.get())) 174 + .transpose()? 175 + .unwrap_or_default(); 176 + 177 + match action { 178 + RecordAction::Create | RecordAction::Update => { 179 + sqlx::query_file!( 180 + "queries/upsert_record.sql", 181 + did.as_str(), 182 + collection, 183 + rkey, 184 + rev, 185 + cid.as_deref(), 186 + live, 187 + parsed_record 188 + ) 189 + .execute(&mut **transaction) 190 + .await?; 191 + } 192 + RecordAction::Delete => { 193 + query::archive_record(did, collection, rkey) 194 + .execute(&mut **transaction) 195 + .await?; 196 + query::delete_record(did, collection, rkey) 197 + .execute(&mut **transaction) 198 + .await?; 199 + } 200 + } 201 + 202 + Ok((record_event, parsed_record)) 203 + } 204 + 205 + #[tracing::instrument(skip(tap, pool, did_rx, shutdown_rx))] 206 + async fn did_task( 207 + tap: TapClient, 208 + pool: PgPool, 209 + mut did_rx: mpsc::UnboundedReceiver<(String, DidSource)>, 210 + mut shutdown_rx: watch::Receiver<bool>, 211 + ) -> anyhow::Result<()> { 212 + const BATCH: usize = 64; 213 + 214 + let mut seen: HashSet<String> = HashSet::with_capacity(10_000); 215 + let mut dids = Vec::new(); 216 + 217 + // Query known DIDs from the database. 218 + let mut query = sqlx::query!("SELECT did FROM identity").fetch(&pool); 219 + while let Some(Ok(row)) = query.next().await { 220 + seen.insert(row.did); 221 + } 222 + 223 + tracing::debug!(count = seen.len(), "loaded tracked DIDs from database"); 224 + 225 + loop { 226 + tokio::time::sleep(Duration::from_millis(200)).await; 227 + match with_shutdown(did_rx.recv_many(&mut dids, BATCH), &mut shutdown_rx).await { 228 + Continue(0) | Break(_) => break, 229 + Continue(_) => {} 230 + } 231 + 232 + // Convert Vec<Box<Did>> to a Vec<&Did>. 233 + let mut dedup: HashSet<&str> = HashSet::new(); 234 + let mut slice = Vec::with_capacity(dids.len()); 235 + for (did, source) in &dids { 236 + if !dedup.insert(did) { 237 + continue; 238 + } 239 + 240 + if !seen.contains(did) || slice.contains(&did.as_ref()) { 241 + tracing::info!(?did, ?source, "tracking DID"); 242 + slice.push(did.as_ref()); 243 + } 244 + } 245 + 246 + tap.add_repos(&slice).await?; 247 + 248 + dids.drain(..).for_each(|(did, _)| _ = seen.insert(did)); 249 + } 250 + 251 + tracing::info!("complete"); 252 + Ok(()) 253 + } 254 + 255 + #[tracing::instrument(skip(tx))] 256 + async fn shutdown_task(tx: watch::Sender<bool>) -> anyhow::Result<()> { 257 + tokio::signal::ctrl_c().await?; 258 + eprintln!(); 259 + tracing::info!("shutdown signal received"); 260 + tx.send(true)?; 261 + Ok(()) 262 + } 263 + 264 + /// Extract any strings that look like DIDs from a JSON document. 265 + fn extract_dids(value: &Value) -> HashSet<String> { 266 + let mut dids = HashSet::new(); 267 + 268 + let mut queue = VecDeque::from_iter([value]); 269 + while let Some(value) = queue.pop_front() { 270 + match value { 271 + Value::Null | Value::Bool(_) | Value::Number(_) => {} 272 + Value::Array(values) => { 273 + for value in values { 274 + queue.push_back(value); 275 + } 276 + } 277 + Value::Object(map) => { 278 + for (_, value) in map { 279 + queue.push_back(value); 280 + } 281 + } 282 + Value::String(maybe_did) => { 283 + if possible_did(maybe_did) { 284 + dids.insert(maybe_did.to_string()); 285 + continue; 286 + } 287 + 288 + // First segment of an "at://..." URI might be a DID. 289 + if let Some(uri) = maybe_did.strip_prefix("at://") 290 + && let Some((maybe_did, _)) = uri.split_once('/') 291 + && possible_did(maybe_did) 292 + { 293 + dids.insert(maybe_did.to_string()); 294 + continue; 295 + } 296 + } 297 + } 298 + } 299 + 300 + dids 301 + } 302 + 303 + fn possible_did(s: &str) -> bool { 304 + s.starts_with("did:plc") || s.starts_with("did:web") 305 + }
+42
src/query.rs
···
··· 1 + use trap::tap::IdentityStatus; 2 + 3 + pub fn archive_record<'a>( 4 + did: &'a str, 5 + collection: &'a str, 6 + rkey: &'a str, 7 + ) -> sqlx::query::Query<'a, sqlx::Postgres, sqlx::postgres::PgArguments> { 8 + sqlx::query!( 9 + "INSERT INTO deleted_record (SELECT did, collection, rkey, rev, cid, live, data FROM record WHERE (did, collection, rkey) = ($1, $2, $3))", 10 + did, 11 + collection, 12 + rkey, 13 + ) 14 + } 15 + 16 + pub fn delete_record<'a>( 17 + did: &'a str, 18 + collection: &'a str, 19 + rkey: &'a str, 20 + ) -> sqlx::query::Query<'a, sqlx::Postgres, sqlx::postgres::PgArguments> { 21 + sqlx::query!( 22 + "DELETE FROM record WHERE (did, collection, rkey) = ($1, $2, $3)", 23 + did, 24 + collection, 25 + rkey, 26 + ) 27 + } 28 + 29 + pub fn upsert_identity<'a>( 30 + did: &'a str, 31 + handle: &'a str, 32 + status: &'a IdentityStatus, 33 + is_active: bool, 34 + ) -> sqlx::query::Query<'a, sqlx::Postgres, sqlx::postgres::PgArguments> { 35 + sqlx::query!( 36 + "INSERT INTO identity (did, handle, active, status) VALUES ($1, $2, $3, $4) ON CONFLICT ON CONSTRAINT identity_pkey DO UPDATE SET (handle, active, status) = (EXCLUDED.handle, EXCLUDED.active, EXCLUDED.status)", 37 + did, 38 + handle, 39 + is_active, 40 + status as &IdentityStatus 41 + ) 42 + }
+13
src/tap.rs
···
··· 1 + mod channel; 2 + mod client; 3 + mod error; 4 + mod types; 5 + 6 + const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); 7 + 8 + pub type HttpClient = reqwest::Client; 9 + 10 + pub use channel::TapChannel; 11 + pub use client::TapClient; 12 + pub use error::Error; 13 + pub use types::*;
+313
src/tap/channel.rs
···
··· 1 + use core::fmt; 2 + use std::{ 3 + collections::HashSet, 4 + time::{Duration, SystemTime}, 5 + }; 6 + 7 + use futures_util::{SinkExt as _, StreamExt}; 8 + use serde::Serialize; 9 + use tokio::{ 10 + net::TcpStream, 11 + sync::{mpsc, watch}, 12 + }; 13 + use tokio_tungstenite::{ 14 + MaybeTlsStream, WebSocketStream, 15 + tungstenite::{Bytes, ClientRequestBuilder, Message}, 16 + }; 17 + 18 + use crate::tap::{TapClient, TapEvent}; 19 + 20 + /// Maximum number of unanswered Ping messages to allow before the connection is 21 + /// considered broken. 22 + const MAX_INFLIGHT_PINGS: usize = 2; 23 + 24 + const TIMEOUT: Duration = Duration::from_secs(30); 25 + 26 + #[derive(Debug, thiserror::Error)] 27 + #[error("Failed to enqueue acknowledgement for event #{0}")] 28 + pub struct AckError(u64); 29 + 30 + impl From<mpsc::error::SendError<Ack>> for AckError { 31 + fn from(error: mpsc::error::SendError<Ack>) -> Self { 32 + Self(error.0.0) 33 + } 34 + } 35 + 36 + pub struct AckHandle { 37 + id: u64, 38 + tx: mpsc::Sender<Ack>, 39 + } 40 + 41 + impl AckHandle { 42 + /// Acknowledge receipt of the associated event. 43 + /// 44 + /// Success does *not* mean the Tap server has successfully received the 45 + /// acknowledgement, only that the ack has be queued by the client. 46 + pub async fn acknowledge(self) -> Result<(), AckError> { 47 + self.tx.send(Ack::new(self.id)).await?; 48 + Ok(()) 49 + } 50 + } 51 + 52 + #[derive(Debug)] 53 + pub struct Ack(u64); 54 + 55 + impl fmt::Display for Ack { 56 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 57 + fmt::Display::fmt(&self.0, f) 58 + } 59 + } 60 + 61 + impl Ack { 62 + fn new(id: u64) -> Self { 63 + Self(id) 64 + } 65 + } 66 + 67 + /// Messages that are serialized and sent to the Tap server. 68 + #[derive(Debug, Serialize)] 69 + #[serde(tag = "type", rename_all = "snake_case")] 70 + enum ClientMessage { 71 + Ack { id: u64 }, 72 + } 73 + 74 + impl From<&Ack> for ClientMessage { 75 + fn from(&Ack(id): &Ack) -> Self { 76 + Self::Ack { id } 77 + } 78 + } 79 + 80 + #[derive(Debug)] 81 + pub struct TapChannel { 82 + rx: mpsc::Receiver<(TapEvent, AckHandle)>, 83 + shutdown: watch::Sender<bool>, 84 + } 85 + 86 + impl TapChannel { 87 + pub const DEFAULT_CAPACITY: usize = 128; 88 + 89 + pub fn new( 90 + tap: &TapClient, 91 + capacity: usize, 92 + ) -> ( 93 + Self, 94 + impl Future<Output = Result<Vec<Ack>, ChannelError>> + Send + 'static, 95 + ) { 96 + let mut url = tap.url().clone(); 97 + url.set_path("/channel"); 98 + url.set_scheme(match url.scheme() { 99 + "https" => "wss", 100 + "http" => "ws", 101 + _ => unreachable!("Tap::new should reject unknown schemes"), 102 + }) 103 + .expect("'http' or 'https' is a valid URL scheme"); 104 + 105 + let uri = url 106 + .as_str() 107 + .parse() 108 + .expect("Url has already been validated"); 109 + 110 + let mut builder = ClientRequestBuilder::new(uri); 111 + for (header_name, header_value) in &tap.headers { 112 + builder = builder.with_header( 113 + header_name.to_string(), 114 + header_value 115 + .to_str() 116 + .expect("Header value has already been validated"), 117 + ); 118 + } 119 + 120 + let (tx, rx) = mpsc::channel(capacity); 121 + let (shutdown, shutdown_rx) = watch::channel(false); 122 + let handle = channel_task(builder, tx, shutdown_rx, capacity); 123 + 124 + (Self { rx, shutdown }, handle) 125 + } 126 + } 127 + 128 + impl TapChannel { 129 + pub async fn recv(&mut self) -> Option<(TapEvent, AckHandle)> { 130 + self.rx.recv().await 131 + } 132 + } 133 + 134 + impl Drop for TapChannel { 135 + fn drop(&mut self) { 136 + self.rx.close(); 137 + let _ = self.shutdown.send(true); 138 + } 139 + } 140 + 141 + #[derive(Debug, thiserror::Error)] 142 + pub enum ChannelError { 143 + #[error("Client authorization failed")] 144 + Authorization, 145 + #[error("Failed to send pending Acks: {0:?}: {1}")] 146 + FailedAcks(Vec<Ack>, tokio_tungstenite::tungstenite::Error), 147 + } 148 + 149 + async fn channel_task( 150 + request_builder: ClientRequestBuilder, 151 + event_tx: mpsc::Sender<(TapEvent, AckHandle)>, 152 + mut shutdown_rx: watch::Receiver<bool>, 153 + capacity: usize, 154 + ) -> Result<Vec<Ack>, ChannelError> { 155 + #[derive(Debug)] 156 + enum Action { 157 + Message(Message), 158 + Timeout, 159 + Ack, 160 + ClearAcks, 161 + } 162 + 163 + let mut pings: HashSet<Bytes> = HashSet::with_capacity(MAX_INFLIGHT_PINGS + 1); 164 + let mut timeout = tokio::time::interval(TIMEOUT); 165 + timeout.tick().await; 166 + 167 + let (ack_tx, mut ack_rx) = mpsc::channel(capacity); 168 + let mut acks: Vec<_> = Default::default(); 169 + 170 + 'outer: loop { 171 + let request = request_builder.clone(); 172 + let (mut socket, _) = match tokio_tungstenite::connect_async(request).await { 173 + Ok(result) => result, 174 + Err(tokio_tungstenite::tungstenite::Error::Http(error)) 175 + if error.status().is_client_error() => 176 + { 177 + tracing::error!(?error, "failed to connect to Tap channel"); 178 + return Err(ChannelError::Authorization); 179 + } 180 + Err(error) => { 181 + tracing::error!(?error); 182 + 183 + // @TODO Reconnect delay 184 + 185 + continue 'outer; 186 + } 187 + }; 188 + 189 + // Send any pending Acks. 190 + if let Err(error) = send_acknowledgements(&mut acks, &mut socket).await { 191 + tracing::error!(?error, "failed to send Ack"); 192 + continue; 193 + } 194 + 195 + loop { 196 + let action = tokio::select! { 197 + Some(Ok(message)) = socket.next() => Action::Message(message), 198 + count = ack_rx.recv_many(&mut acks, 64) => match count { 199 + 0 => Action::ClearAcks, 200 + _ => Action::Ack, 201 + }, 202 + _ = timeout.tick() => Action::Timeout, 203 + _ = shutdown_rx.wait_for(|v| *v) => Action::ClearAcks, 204 + else => Action::ClearAcks, 205 + }; 206 + 207 + match action { 208 + Action::Message(message) => match message { 209 + Message::Text(bytes) => { 210 + let event = match serde_json::from_str::<TapEvent>(bytes.as_str()) { 211 + Ok(event) => event, 212 + Err(error) => { 213 + tracing::error!(?error, bytes = %bytes.as_str(), "failed to deserialize event"); 214 + continue; 215 + } 216 + }; 217 + 218 + let ack = AckHandle { 219 + id: event.id(), 220 + tx: ack_tx.clone(), 221 + }; 222 + 223 + if event_tx.send((event, ack)).await.is_err() { 224 + tracing::error!("failed to dispatch event"); 225 + break 'outer; 226 + } 227 + } 228 + Message::Binary(_) | Message::Frame(_) => { 229 + tracing::error!("unexpected Binary or Frame message from server"); 230 + break; 231 + } 232 + Message::Ping(bytes) => { 233 + if let Err(error) = socket.send(Message::Pong(bytes)).await { 234 + tracing::error!(?error, "failed to send Pong"); 235 + continue 'outer; 236 + } 237 + } 238 + Message::Pong(bytes) => { 239 + tracing::trace!(?bytes, "received Pong from server"); 240 + if !pings.remove(&bytes) { 241 + tracing::error!("unsolicited Pong"); 242 + break; 243 + } 244 + } 245 + Message::Close(close_frame) => { 246 + tracing::debug!(?close_frame, "received close frame"); 247 + break; 248 + } 249 + }, 250 + Action::Ack => { 251 + if let Err(error) = send_acknowledgements(&mut acks, &mut socket).await { 252 + tracing::error!(?error, "failed to send Ack"); 253 + break; 254 + } 255 + } 256 + Action::Timeout => { 257 + if pings.len() > MAX_INFLIGHT_PINGS { 258 + tracing::error!("too many missed pings"); 259 + break; 260 + } 261 + 262 + let timestamp = SystemTime::now() 263 + .duration_since(SystemTime::UNIX_EPOCH) 264 + .expect("system time precedes UNIX epoch") 265 + .as_micros(); 266 + 267 + let payload = format!("{timestamp}"); 268 + let payload: Bytes = payload.into(); 269 + pings.insert(payload.clone()); 270 + 271 + if socket.send(Message::Ping(payload)).await.is_err() { 272 + tracing::error!("failed to send Ping to server"); 273 + break; 274 + } 275 + } 276 + Action::ClearAcks => { 277 + drop(ack_tx); 278 + while let Some(ack) = ack_rx.recv().await { 279 + acks.push(ack); 280 + } 281 + 282 + if let Err(error) = send_acknowledgements(&mut acks, &mut socket).await { 283 + return Err(ChannelError::FailedAcks(acks, error)); 284 + } 285 + 286 + break 'outer; 287 + } 288 + } 289 + } 290 + 291 + tracing::warn!("disconnected"); 292 + } 293 + 294 + tracing::info!("complete"); 295 + Ok(acks) 296 + } 297 + 298 + async fn send_acknowledgements( 299 + acks: &mut Vec<Ack>, 300 + socket: &mut WebSocketStream<MaybeTlsStream<TcpStream>>, 301 + ) -> Result<usize, tokio_tungstenite::tungstenite::Error> { 302 + let mut count = 0; 303 + for ack in acks.drain(..) { 304 + tracing::debug!(?ack, "sending ack"); 305 + let message = serde_json::to_string(&ClientMessage::from(&ack)) 306 + .expect("ClientMessage should be serializable"); 307 + 308 + socket.send(Message::text(message)).await?; 309 + count += 1; 310 + } 311 + 312 + Ok(count) 313 + }
+155
src/tap/client.rs
···
··· 1 + use data_encoding::BASE64URL; 2 + use reqwest::{ 3 + IntoUrl, 4 + header::{self, HeaderMap, HeaderValue}, 5 + }; 6 + use serde_json::Value; 7 + use url::Url; 8 + 9 + use crate::tap::{ 10 + Error, HttpClient, RepoInfo, TapChannel, 11 + channel::{Ack, ChannelError}, 12 + }; 13 + 14 + pub type Result<T> = core::result::Result<T, Error>; 15 + 16 + #[derive(Clone)] 17 + pub struct TapClient { 18 + http: HttpClient, 19 + url: Url, 20 + pub(crate) headers: HeaderMap, 21 + } 22 + 23 + impl TapClient { 24 + pub fn new<U: IntoUrl>(url: U, admin_password: Option<&str>) -> Result<Self> { 25 + fn inner(url: Url, admin_password: Option<&str>) -> Result<TapClient> { 26 + if !["http", "https"].contains(&url.scheme()) { 27 + return Err(Error::UnsupportedScheme); 28 + } 29 + 30 + let mut headers = HeaderMap::new(); 31 + if let Some(password) = admin_password { 32 + let token = format!("admin:{password}"); 33 + let encoded = BASE64URL.encode(token.as_bytes()); 34 + headers.append( 35 + header::AUTHORIZATION, 36 + HeaderValue::from_str(&format!("Basic {encoded}"))?, 37 + ); 38 + } 39 + 40 + let http = HttpClient::builder() 41 + .default_headers(headers.clone()) 42 + .user_agent(crate::tap::USER_AGENT) 43 + .build()?; 44 + 45 + Ok(TapClient { http, url, headers }) 46 + } 47 + 48 + inner(url.into_url()?, admin_password) 49 + } 50 + 51 + pub fn url(&self) -> &Url { 52 + &self.url 53 + } 54 + } 55 + 56 + impl TapClient { 57 + /// Create a WebSocket channel to receive events. 58 + pub fn channel( 59 + &self, 60 + ) -> ( 61 + TapChannel, 62 + impl Future<Output = core::result::Result<Vec<Ack>, ChannelError>> + Send + 'static, 63 + ) { 64 + TapChannel::new(self, TapChannel::DEFAULT_CAPACITY) 65 + } 66 + 67 + /// Start tracking repos. 68 + /// 69 + /// This will trigger backfill. 70 + pub async fn add_repos(&self, dids: &[&str]) -> Result<()> { 71 + #[derive(serde::Serialize)] 72 + struct RequestBody<'a> { 73 + dids: &'a [&'a str], 74 + } 75 + 76 + // An empty slice will trigger an internal service error in the Tap service. 77 + if dids.is_empty() { 78 + return Ok(()); 79 + } 80 + 81 + let mut url = self.url.clone(); 82 + url.set_path("/repos/add"); 83 + 84 + let response = self 85 + .http 86 + .post(url) 87 + .json(&RequestBody { dids }) 88 + .send() 89 + .await? 90 + .error_for_status()?; 91 + 92 + let body = response.bytes().await?; 93 + assert!(body.is_empty(), "expected an empty response body"); 94 + 95 + Ok(()) 96 + } 97 + 98 + /// Stop tracking repos. 99 + pub async fn remove_repos(&self, dids: &[&str]) -> Result<()> { 100 + #[derive(serde::Serialize)] 101 + struct RequestBody<'a> { 102 + dids: &'a [&'a str], 103 + } 104 + 105 + let mut url = self.url.clone(); 106 + url.set_path("/repos/remove"); 107 + 108 + let response = self 109 + .http 110 + .post(url) 111 + .json(&RequestBody { dids }) 112 + .send() 113 + .await? 114 + .error_for_status()?; 115 + 116 + let body = response.bytes().await?; 117 + assert!(body.is_empty(), "expected an empty response body"); 118 + 119 + Ok(()) 120 + } 121 + 122 + /// Resolve a DID to its DID document. 123 + pub async fn resolve_did(&self, did: &str) -> Result<Value> { 124 + let mut url = self.url.clone(); 125 + url.set_path(&format!("/resolve/{did}")); 126 + 127 + let response = self 128 + .http 129 + .get(url) 130 + .send() 131 + .await? 132 + .error_for_status()? 133 + .json() 134 + .await?; 135 + 136 + Ok(response) 137 + } 138 + 139 + /// Get info about a tracked repo. 140 + pub async fn get_repo_info(&self, did: &str) -> Result<RepoInfo> { 141 + let mut url = self.url.clone(); 142 + url.set_path(&format!("/info/{did}")); 143 + 144 + let response = self 145 + .http 146 + .get(url) 147 + .send() 148 + .await? 149 + .error_for_status()? 150 + .json() 151 + .await?; 152 + 153 + Ok(response) 154 + } 155 + }
+9
src/tap/error.rs
···
··· 1 + #[derive(Debug, thiserror::Error)] 2 + pub enum Error { 3 + #[error(transparent)] 4 + Http(#[from] reqwest::Error), 5 + #[error("Unsupported scheme")] 6 + UnsupportedScheme, 7 + #[error("Failed to construct a valid Authorization header: {0}")] 8 + InvalidAuthorization(#[from] reqwest::header::InvalidHeaderValue), 9 + }
+182
src/tap/types.rs
···
··· 1 + use serde::{Deserialize, Serialize}; 2 + use serde_json::value::RawValue; 3 + 4 + #[derive(Debug, Hash, Deserialize, Serialize)] 5 + #[serde(rename_all = "lowercase")] 6 + pub enum RecordAction { 7 + Create, 8 + Update, 9 + Delete, 10 + } 11 + 12 + #[derive(Debug, Deserialize, Serialize)] 13 + struct InnerRecordEvent { 14 + did: String, 15 + rev: String, 16 + collection: String, 17 + rkey: String, 18 + action: RecordAction, 19 + record: Option<Box<RawValue>>, 20 + cid: Option<String>, 21 + live: bool, 22 + } 23 + 24 + #[derive(Debug, Deserialize, Serialize)] 25 + pub struct RecordEvent { 26 + pub id: u64, 27 + pub did: String, 28 + pub rev: String, 29 + pub collection: String, 30 + pub rkey: String, 31 + pub action: RecordAction, 32 + pub record: Option<Box<RawValue>>, 33 + pub cid: Option<String>, 34 + pub live: bool, 35 + } 36 + 37 + #[derive(Debug, Deserialize, Serialize, sqlx::Type)] 38 + #[serde(rename_all = "lowercase")] 39 + #[sqlx(type_name = "identity_status", rename_all = "lowercase")] 40 + pub enum IdentityStatus { 41 + Active, 42 + Takendown, 43 + Suspended, 44 + Deactivated, 45 + Deleted, 46 + } 47 + 48 + #[derive(Debug, Deserialize, Serialize)] 49 + struct InnerIdentityEvent { 50 + did: String, 51 + handle: String, 52 + is_active: bool, 53 + status: IdentityStatus, 54 + } 55 + 56 + #[derive(Debug, Deserialize, Serialize)] 57 + pub struct IdentityEvent { 58 + pub id: u64, 59 + pub did: String, 60 + pub handle: String, 61 + pub is_active: bool, 62 + pub status: IdentityStatus, 63 + } 64 + 65 + #[derive(Debug, Deserialize, Serialize)] 66 + #[serde(rename_all = "snake_case")] 67 + pub enum EventType { 68 + Record, 69 + Identity, 70 + } 71 + 72 + #[derive(Debug, Deserialize, Serialize)] 73 + struct InnerEvent { 74 + id: u64, 75 + r#type: EventType, 76 + #[serde(skip_serializing_if = "Option::is_none")] 77 + record: Option<InnerRecordEvent>, 78 + #[serde(skip_serializing_if = "Option::is_none")] 79 + identity: Option<InnerIdentityEvent>, 80 + } 81 + 82 + #[derive(Debug, Deserialize, Serialize)] 83 + #[serde(try_from = "InnerEvent")] 84 + pub enum TapEvent { 85 + Record(RecordEvent), 86 + Identity(IdentityEvent), 87 + } 88 + 89 + impl TapEvent { 90 + pub const fn id(&self) -> u64 { 91 + match self { 92 + Self::Record(record) => record.id, 93 + Self::Identity(identity) => identity.id, 94 + } 95 + } 96 + } 97 + 98 + #[derive(Debug, thiserror::Error)] 99 + enum EventError { 100 + #[error("event with 'record' type should have 'record' property set")] 101 + RecordEventMissingRecord, 102 + #[error("event with 'record' type should not have 'identity' property set")] 103 + RecordEventWithIdentity, 104 + #[error("event with 'identity' type should have 'identity' property set")] 105 + IdentityEventMissingIdentity, 106 + #[error("event with 'identity' type should not have 'record' property set")] 107 + IdentityEventWithRecord, 108 + } 109 + 110 + impl TryFrom<InnerEvent> for TapEvent { 111 + type Error = EventError; 112 + 113 + fn try_from(value: InnerEvent) -> Result<Self, Self::Error> { 114 + match (value.r#type, value.record, value.identity) { 115 + (EventType::Record, None, _) => Err(EventError::RecordEventMissingRecord), 116 + (EventType::Record, _, Some(_)) => Err(EventError::RecordEventWithIdentity), 117 + (EventType::Record, Some(record), None) => { 118 + let InnerRecordEvent { 119 + did, 120 + rev, 121 + collection, 122 + rkey, 123 + action, 124 + record, 125 + cid, 126 + live, 127 + } = record; 128 + Ok(Self::Record(RecordEvent { 129 + id: value.id, 130 + did, 131 + rev, 132 + collection, 133 + rkey, 134 + action, 135 + record, 136 + cid, 137 + live, 138 + })) 139 + } 140 + (EventType::Identity, _, None) => Err(EventError::IdentityEventMissingIdentity), 141 + (EventType::Identity, Some(_), _) => Err(EventError::IdentityEventWithRecord), 142 + (EventType::Identity, None, Some(identity)) => { 143 + let InnerIdentityEvent { 144 + did, 145 + handle, 146 + is_active, 147 + status, 148 + } = identity; 149 + Ok(Self::Identity(IdentityEvent { 150 + id: value.id, 151 + did, 152 + handle, 153 + is_active, 154 + status, 155 + })) 156 + } 157 + } 158 + } 159 + } 160 + 161 + #[derive(Debug, Deserialize, Serialize)] 162 + pub struct RepoInfo { 163 + pub did: String, 164 + pub handle: String, 165 + pub state: String, 166 + pub rev: String, 167 + pub records: u64, 168 + pub error: Option<String>, 169 + pub retries: Option<u64>, 170 + } 171 + 172 + #[cfg(test)] 173 + mod tests { 174 + use super::*; 175 + 176 + #[test] 177 + fn deserialized_record_event() { 178 + const SAMPLE: &str = r#"{"id":24431,"type":"record","record":{"live":false,"did":"did:plc:jlplwn5pi4dqrls7i6dx2me7","rev":"3m7xjcvqmch2k","collection":"sh.tangled.repo.issue.comment","rkey":"3lxy6urnngt22","action":"create","record":{"$type":"sh.tangled.repo.issue.comment","body":"x","commentId":66128,"createdAt":"2025-09-04T03:20:53Z","issue":"at://did:plc:qfpnj4og54vl56wngdriaxug/sh.tangled.repo.issue/3ljnffq4axj22","owner":"did:plc:jlplwn5pi4dqrls7i6dx2me7","repo":"at://did:plc:wshs7t2adsemcrrd4snkeqli/sh.tangled.repo/3liuighjy2h22"},"cid":"bafyreielwpdea6mnhgqz2r4yfyr5ne6v6h2ucncm46enukpqlclrned5ia"}}"#; 179 + let event: TapEvent = serde_json::from_str(SAMPLE).unwrap(); 180 + assert!(matches!(event, TapEvent::Record(_))); 181 + } 182 + }
+19
src/util.rs
···
··· 1 + use std::ops; 2 + 3 + use tokio::sync::watch; 4 + 5 + #[derive(Debug, thiserror::Error)] 6 + #[error("Shutdown signal received")] 7 + pub struct Shutdown; 8 + 9 + pub async fn with_shutdown<F: Future>( 10 + f: F, 11 + rx: &mut watch::Receiver<bool>, 12 + ) -> ops::ControlFlow<Shutdown, F::Output> { 13 + use ops::ControlFlow::{Break, Continue}; 14 + 15 + tokio::select! { 16 + result = f => Continue(result), 17 + Ok(_) = rx.wait_for(|&v| v) => Break(Shutdown), 18 + } 19 + }