Demonstration bridge between ATproto and GraphQL. Generate schema types and interface with the ATmosphere via GraphQL queries. Includes a TypeScript server with IDE.
2
fork

Configure Feed

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

refactor: clean up Python code

Tim Ryan 82318312 c1f4c82e

+6 -3316
-14
Pipfile
··· 1 - [[source]] 2 - url = "https://pypi.org/simple" 3 - verify_ssl = true 4 - name = "pypi" 5 - 6 - [packages] 7 - atproto = "==0.0.65" 8 - typer = "==0.21.1" 9 - pytest = "*" 10 - 11 - [dev-packages] 12 - 13 - [requires] 14 - python_version = "3.14"
-666
Pipfile.lock
··· 1 - { 2 - "_meta": { 3 - "hash": { 4 - "sha256": "60e3e4849fadc75bda934e7f5a78b3a88203e1e0b20e0058faf9e737b7c8f0c1" 5 - }, 6 - "pipfile-spec": 6, 7 - "requires": { 8 - "python_version": "3.14" 9 - }, 10 - "sources": [ 11 - { 12 - "name": "pypi", 13 - "url": "https://pypi.org/simple", 14 - "verify_ssl": true 15 - } 16 - ] 17 - }, 18 - "default": { 19 - "annotated-types": { 20 - "hashes": [ 21 - "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", 22 - "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" 23 - ], 24 - "markers": "python_version >= '3.8'", 25 - "version": "==0.7.0" 26 - }, 27 - "anyio": { 28 - "hashes": [ 29 - "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", 30 - "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc" 31 - ], 32 - "markers": "python_version >= '3.10'", 33 - "version": "==4.13.0" 34 - }, 35 - "atproto": { 36 - "hashes": [ 37 - "sha256:027c6ed98746a9e6f1bb24bc18db84b80b386037709ff3af9ef927dce3dd4938", 38 - "sha256:ea53dea57454c9e56318b5d25ceb35854d60ba238b38b0e5ca79aa1a2df85846" 39 - ], 40 - "index": "pypi", 41 - "markers": "python_version < '3.15' and python_version >= '3.9'", 42 - "version": "==0.0.65" 43 - }, 44 - "certifi": { 45 - "hashes": [ 46 - "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", 47 - "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" 48 - ], 49 - "markers": "python_version >= '3.7'", 50 - "version": "==2026.2.25" 51 - }, 52 - "cffi": { 53 - "hashes": [ 54 - "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", 55 - "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", 56 - "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", 57 - "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", 58 - "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", 59 - "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2", 60 - "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", 61 - "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", 62 - "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65", 63 - "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", 64 - "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", 65 - "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", 66 - "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", 67 - "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a", 68 - "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", 69 - "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", 70 - "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", 71 - "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", 72 - "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", 73 - "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", 74 - "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", 75 - "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", 76 - "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", 77 - "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", 78 - "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165", 79 - "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", 80 - "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", 81 - "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c", 82 - "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", 83 - "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", 84 - "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", 85 - "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", 86 - "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63", 87 - "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", 88 - "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", 89 - "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", 90 - "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", 91 - "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", 92 - "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", 93 - "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", 94 - "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", 95 - "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", 96 - "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", 97 - "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", 98 - "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", 99 - "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", 100 - "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322", 101 - "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", 102 - "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", 103 - "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", 104 - "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", 105 - "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", 106 - "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", 107 - "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", 108 - "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", 109 - "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", 110 - "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", 111 - "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", 112 - "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", 113 - "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", 114 - "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9", 115 - "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", 116 - "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", 117 - "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", 118 - "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", 119 - "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", 120 - "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f", 121 - "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", 122 - "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", 123 - "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", 124 - "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", 125 - "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", 126 - "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", 127 - "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", 128 - "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", 129 - "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", 130 - "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7", 131 - "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", 132 - "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534", 133 - "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", 134 - "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", 135 - "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", 136 - "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", 137 - "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf" 138 - ], 139 - "markers": "python_version >= '3.9'", 140 - "version": "==2.0.0" 141 - }, 142 - "click": { 143 - "hashes": [ 144 - "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", 145 - "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6" 146 - ], 147 - "markers": "python_version >= '3.10'", 148 - "version": "==8.3.1" 149 - }, 150 - "cryptography": { 151 - "hashes": [ 152 - "sha256:02fad249cb0e090b574e30b276a3da6a149e04ee2f049725b1f69e7b8351ec70", 153 - "sha256:063b67749f338ca9c5a0b7fe438a52c25f9526b851e24e6c9310e7195aad3b4d", 154 - "sha256:12cae594e9473bca1a7aceb90536060643128bb274fcea0fc459ab90f7d1ae7a", 155 - "sha256:12f0fa16cc247b13c43d56d7b35287ff1569b5b1f4c5e87e92cc4fcc00cd10c0", 156 - "sha256:22259338084d6ae497a19bae5d4c66b7ca1387d3264d1c2c0e72d9e9b6a77b97", 157 - "sha256:26031f1e5ca62fcb9d1fcb34b2b60b390d1aacaa15dc8b895a9ed00968b97b30", 158 - "sha256:27550628a518c5c6c903d84f637fbecf287f6cb9ced3804838a1295dc1fd0759", 159 - "sha256:2b417edbe8877cda9022dde3a008e2deb50be9c407eef034aeeb3a8b11d9db3c", 160 - "sha256:2ea0f37e9a9cf0df2952893ad145fd9627d326a59daec9b0802480fa3bcd2ead", 161 - "sha256:2ef9e69886cbb137c2aef9772c2e7138dc581fad4fcbcf13cc181eb5a3ab6275", 162 - "sha256:341359d6c9e68834e204ceaf25936dffeafea3829ab80e9503860dcc4f4dac58", 163 - "sha256:380343e0653b1c9d7e1f55b52aaa2dbb2fdf2730088d48c43ca1c7c0abb7cc2f", 164 - "sha256:3c21d92ed15e9cfc6eb64c1f5a0326db22ca9c2566ca46d845119b45b4400361", 165 - "sha256:3dfa6567f2e9e4c5dceb8ccb5a708158a2a871052fa75c8b78cb0977063f1507", 166 - "sha256:456b3215172aeefb9284550b162801d62f5f264a081049a3e94307fe20792cfa", 167 - "sha256:4668298aef7cddeaf5c6ecc244c2302a2b8e40f384255505c22875eebb47888b", 168 - "sha256:50575a76e2951fe7dbd1f56d181f8c5ceeeb075e9ff88e7ad997d2f42af06e7b", 169 - "sha256:639301950939d844a9e1c4464d7e07f902fe9a7f6b215bb0d4f28584729935d8", 170 - "sha256:64235194bad039a10bb6d2d930ab3323baaec67e2ce36215fd0952fad0930ca8", 171 - "sha256:6617f67b1606dfd9fe4dbfa354a9508d4a6d37afe30306fe6c101b7ce3274b72", 172 - "sha256:67177e8a9f421aa2d3a170c3e56eca4e0128883cf52a071a7cbf53297f18b175", 173 - "sha256:6728c49e3b2c180ef26f8e9f0a883a2c585638db64cf265b49c9ba10652d430e", 174 - "sha256:6739d56300662c468fddb0e5e291f9b4d084bead381667b9e654c7dd81705124", 175 - "sha256:69cf0056d6947edc6e6760e5f17afe4bea06b56a9ac8a06de9d2bd6b532d4f3a", 176 - "sha256:760997a4b950ff00d418398ad73fbc91aa2894b5c1db7ccb45b4f68b42a63b3c", 177 - "sha256:79e865c642cfc5c0b3eb12af83c35c5aeff4fa5c672dc28c43721c2c9fdd2f0f", 178 - "sha256:7e6142674f2a9291463e5e150090b95a8519b2fb6e6aaec8917dd8d094ce750d", 179 - "sha256:7f417f034f91dcec1cb6c5c35b07cdbb2ef262557f701b4ecd803ee8cefed4f4", 180 - "sha256:7f6690b6c55e9c5332c0b59b9c8a3fb232ebf059094c17f9019a51e9827df91c", 181 - "sha256:8927ccfbe967c7df312ade694f987e7e9e22b2425976ddbf28271d7e58845290", 182 - "sha256:8ce35b77aaf02f3b59c90b2c8a05c73bac12cea5b4e8f3fbece1f5fddea5f0ca", 183 - "sha256:8e7304c4f4e9490e11efe56af6713983460ee0780f16c63f219984dab3af9d2d", 184 - "sha256:90e5f0a7b3be5f40c3a0a0eafb32c681d8d2c181fc2a1bdabe9b3f611d9f6b1a", 185 - "sha256:97c8115b27e19e592a05c45d0dd89c57f81f841cc9880e353e0d3bf25b2139ed", 186 - "sha256:9a693028b9cbe51b5a1136232ee8f2bc242e4e19d456ded3fa7c86e43c713b4a", 187 - "sha256:9a9c42a2723999a710445bc0d974e345c32adfd8d2fac6d8a251fa829ad31cfb", 188 - "sha256:a3e84d5ec9ba01f8fd03802b2147ba77f0c8f2617b2aff254cedd551844209c8", 189 - "sha256:aad75154a7ac9039936d50cf431719a2f8d4ed3d3c277ac03f3339ded1a5e707", 190 - "sha256:b12c6b1e1651e42ab5de8b1e00dc3b6354fdfd778e7fa60541ddacc27cd21410", 191 - "sha256:b928a3ca837c77a10e81a814a693f2295200adb3352395fad024559b7be7a736", 192 - "sha256:bcb87663e1f7b075e48c3be3ecb5f0b46c8fc50b50a97cf264e7f60242dca3f2", 193 - "sha256:c797e2517cb7880f8297e2c0f43bb910e91381339336f75d2c1c2cbf811b70b4", 194 - "sha256:c89eb37fae9216985d8734c1afd172ba4927f5a05cfd9bf0e4863c6d5465b013", 195 - "sha256:cdcd3edcbc5d55757e5f5f3d330dd00007ae463a7e7aa5bf132d1f22a4b62b19", 196 - "sha256:d24c13369e856b94892a89ddf70b332e0b70ad4a5c43cf3e9cb71d6d7ffa1f7b", 197 - "sha256:d4e4aadb7fc1f88687f47ca20bb7227981b03afaae69287029da08096853b738", 198 - "sha256:d9528b535a6c4f8ff37847144b8986a9a143585f0540fbcb1a98115b543aa463", 199 - "sha256:ed3775295fb91f70b4027aeba878d79b3e55c0b3e97eaa4de71f8f23a9f2eb77", 200 - "sha256:ed418c37d095aeddf5336898a132fba01091f0ac5844e3e8018506f014b6d2c4" 201 - ], 202 - "markers": "python_version >= '3.8' and python_full_version not in '3.9.0, 3.9.1'", 203 - "version": "==46.0.6" 204 - }, 205 - "dnspython": { 206 - "hashes": [ 207 - "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", 208 - "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f" 209 - ], 210 - "markers": "python_version >= '3.10'", 211 - "version": "==2.8.0" 212 - }, 213 - "h11": { 214 - "hashes": [ 215 - "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", 216 - "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86" 217 - ], 218 - "markers": "python_version >= '3.8'", 219 - "version": "==0.16.0" 220 - }, 221 - "httpcore": { 222 - "hashes": [ 223 - "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", 224 - "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8" 225 - ], 226 - "markers": "python_version >= '3.8'", 227 - "version": "==1.0.9" 228 - }, 229 - "httpx": { 230 - "hashes": [ 231 - "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", 232 - "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" 233 - ], 234 - "markers": "python_version >= '3.8'", 235 - "version": "==0.28.1" 236 - }, 237 - "idna": { 238 - "hashes": [ 239 - "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", 240 - "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" 241 - ], 242 - "markers": "python_version >= '3.8'", 243 - "version": "==3.11" 244 - }, 245 - "iniconfig": { 246 - "hashes": [ 247 - "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", 248 - "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12" 249 - ], 250 - "markers": "python_version >= '3.10'", 251 - "version": "==2.3.0" 252 - }, 253 - "libipld": { 254 - "hashes": [ 255 - "sha256:02f00a19e6a557bfed2ce6911d541f96708d73ca457b709793885336adf91431", 256 - "sha256:047d95641c95360adb6627447d6cbc048fcd9768f4a827078842d7d99cb79b77", 257 - "sha256:06f766cec75f3d78339caa3ce3c6977e290e1a97f37e5f4ba358da2e77340196", 258 - "sha256:071de5acf902e9a21d761572755afc8403cbaadd4b8199e7504ad52ee45b6b5e", 259 - "sha256:082321d5ba84d9bb4e9f2577278040db2b4f624b131402735ea7eca13febedec", 260 - "sha256:08261503b7307c6d9acbd3b2a221da9294b457204dcefce446f627893abb077e", 261 - "sha256:08c8aadfebf9db9a547bd14ab4e5d438ee3f0a003eb4554bbecedaebbaaa0bbe", 262 - "sha256:0dc2db1485703f7c6cf4ff9da0fe7a7d4ee883f92a35d68197c2294a3c3efd17", 263 - "sha256:0fae0158971bf97aa6662e5f9cb5f497c35d5196336047ca4a9ebc6492b1f582", 264 - "sha256:13cb6c68ec55a8802704241210cca44e09eaf4c0e9bd6823e191e56f7f038f05", 265 - "sha256:1767f287c4137521f6b2dfa30583030b128174515dc4ddc481598b570de72ca4", 266 - "sha256:196a8fcd86ae0c8096cea85ff308edf315d77fbb677ef3dd9eff0be9da526499", 267 - "sha256:1a7de390a3eb897d3194f6c96067c21338fbe6e0fc1145ab6b51af276aa7a08e", 268 - "sha256:1d791227d505a3aab9f5bc0df9baafacae825f9fd4cd01f157252efe15536b10", 269 - "sha256:1d7f564d13a6983a20baef873a7966df28aa27a86ccc574456b4ebc7d31fdd2d", 270 - "sha256:249b74fcd3ae8bb6d0c9b3e0ec23a75db60f7b40f8b07ef378dfc9227c921ef5", 271 - "sha256:2ac45e3aef416fe2eccbe84e562d81714416790bfd0756a1aa49ba895d4c7010", 272 - "sha256:2e8608367317210baa57caa89b504db05c1623d8418e5a94276bcf36059cef65", 273 - "sha256:3344f30d47dcab9cba41dd8f2243874af91939e38e3c31f20d586383ca74296e", 274 - "sha256:36be4ce9cb417eedec253eda9f55b92f29a35cbfcb24d108b496c72934fea7a2", 275 - "sha256:36fe9cd1b5a75a315cab30091579242d05df39692f773f7d8221250503753e3a", 276 - "sha256:37ea7cb7afb94277e4e095bcc0ae888ed4b6e0fe8082c41dccd6e9487ccfd729", 277 - "sha256:3aa8ae124db8fe724199e7fd16c2bd72dcdd2f10572be28dcacf0eb7613af026", 278 - "sha256:3dbed6b1f2559c4ba8b898043a96c763a16063a1810cc1378cfdc92bcbdbb7e6", 279 - "sha256:3f033e98c9e95e8448c97bbc904271908076974d790a895abade2ae89433715e", 280 - "sha256:4140f030eb3cfff17d04b9481f13aaed0b2910d1371fe7489394120ed1d09ae5", 281 - "sha256:435643314f8a11d207c5e25536d3f6876a3efa337886faea7e5116e1d8b67bc6", 282 - "sha256:4402e21ac3b5c754e1562b448175d35113fb39d7bb938dfa4e095a9629ebb8dd", 283 - "sha256:4443d047fd1a9679534a87a6ee35c3a10793d4453801281341bb1e8390087c69", 284 - "sha256:4446cae7584a446b58de66942f89f155d95c2cbfb9ad215af359086824d4e3b9", 285 - "sha256:44ca1ba44cb801686557e9544d248e013a2d5d1ab9fed796f090bb0d51d8f4ef", 286 - "sha256:4596509ef4c2f00df2d0914e8efc632e4eb84bf837e57a8f53036dcf4d0d3169", 287 - "sha256:499345f7ce4ec6da1d35c4bf5c9f8aab9324f5c9e508db3065073fec2d4e4bde", 288 - "sha256:5393886a7e387751904681ecfa7e5912471b46043f044baa041a2b4772e4f839", 289 - "sha256:57ec5b9ffc608a438f41f359996982291382365c4a593b1bce30bbec7a63771a", 290 - "sha256:5947e99b40e923170094a3313c9f3629c6ed475465ba95eadce6cdcf08f1f65a", 291 - "sha256:5a50cbf5b3b73164fbb88169573ed3e824024c12fbc5f9efd87fb5c8f236ccc1", 292 - "sha256:5c9f6e91da0f7dcdd3276eefe3f31b2ec659ed279f5e595e6f44efa337a18b2b", 293 - "sha256:5e3e9be4bdeb90dbc537a53f8d06e8b2c703f4b7868f9316958e1bbde526a143", 294 - "sha256:5f0929edbbd283a203e0a74d1794ad171cf4f5fc11453bddc366615c4b97043c", 295 - "sha256:627035693460bae559d2e7f46bc577a27504d6e38e8715fcf9a8d905f6b1c72d", 296 - "sha256:634d176664cf295360712157b5c5a83539da2f4416f3e0491340064d49e74fd8", 297 - "sha256:63bc6858d73c324e29d74155bdb339e14330a88bb1a8cc8fdc295048337dca09", 298 - "sha256:67c2e2a6604fe8b5aa8960c31989dfb84275693ba411d5139cdb87b2855bf009", 299 - "sha256:6979074fd5bfeeda75653df39875f566fefc5d9f3bb6e786742f55d7a7f9bf38", 300 - "sha256:6c2817982506d1ccda516da7d6cc2662b58a363fc84a163bea297ff61b789106", 301 - "sha256:6f09281bebc3c4d397a58606663ee915290702db0323366f9f1bd30b8b4a3fc1", 302 - "sha256:717c4630c4b1ad81c6896291cd93bcaca4ddc3f66412d81459e2641a505ec04a", 303 - "sha256:72b59693a1ac0962ef24c660e8d34dc25c41a1f1da1da54badb7442a498fc9a4", 304 - "sha256:76731ebebd824fa45e51cc85506b108aa5da7322e43864909895f1779e9e4b41", 305 - "sha256:7b8e7100bffbe579b7c92a3c6a8852ce333e0de171e696a2063e1e39ec9cc50a", 306 - "sha256:7e85ccd9136110e63943d95232b193c893e369c406273d235160e5cc4b39c9ce", 307 - "sha256:829772d79337fc330c9c129295309d27c86785b78d947e3561e45ccfe67c519d", 308 - "sha256:847d6f481f8e8e10347479490db824cc568689e7bc1a9f5e5aa67235494dcdf6", 309 - "sha256:8494fe4235b053883209aa9c6a5d128f18efde7d6d0eceb51d2dcb029dffbc33", 310 - "sha256:88ac549eb6c56287785ad20d0e7785d3e8b153b6a322fd5d7edf0e7fda2b182e", 311 - "sha256:8be484f1dc5525453e17f07f02202180c708213f2b6ea06d3b9247a5702e0229", 312 - "sha256:8d7cd1e7e88b0fbc8f4aa267bdea2d10452c9dd0e1aafa82a5e0751427f222b0", 313 - "sha256:8db7127528af6393c02da6317a9188fb05dd13feb7557ec5be320208402f6537", 314 - "sha256:908630dc28b16a517cf323293f0843f481b0872649cba7d4cfdbc6eb258f5674", 315 - "sha256:91b02da059a6ae7f783efa826f640ab1ca5eb5dd370bfd3f41071693a363c4fb", 316 - "sha256:95a2c4f507c88c01a797ec97ce10603bea684c03208227703e007485dc631971", 317 - "sha256:981f870427c6f2ece983825b439c18718e5aaf8121a1659624e896ee905ab18e", 318 - "sha256:9a1d84c630961cff188deaa2129c86d69f5779c8d02046fbe0c629ef162bc3df", 319 - "sha256:9cb4e0cd56d66c2b751eef7288aba919a8a73f320c8f8b7060d522fdffb3cd5b", 320 - "sha256:a48bc2f7845825143a36f6a305680823a2816488593024803064d0803e3cee35", 321 - "sha256:a81fbf42a8edf094c7f8ebd77eb14d8cc7c3d6b3b51d786d47ecb4c6763da2fe", 322 - "sha256:ad07c8574d59088ed8bcec7cd21544a50f51a324290e77b0b042a0e4c1ed1b07", 323 - "sha256:ad6f8fd51a4472a8c2ae8e5c2b3fb274ea29876b9284d86456a203e41793952c", 324 - "sha256:b040dab7eb04b0ff730e68840f40eb225c9f14e73ad21238b76c7b8ded3ad99d", 325 - "sha256:b155c02626b194439f4b519a53985aedc8637ae56cf640ea6acf6172a37465de", 326 - "sha256:b3404a11e7e7803f7bc87a819e694e2568828c1f13a5f7fce74d3240d5a07aba", 327 - "sha256:b3d16a2d3588244702ea671373de2984e20d44936c9d6d457570e4d8b33dddcf", 328 - "sha256:b438d42efc857768db97f2a5ca8114b933e73b827d91344ec9dac6734687f060", 329 - "sha256:b69f2accac94f2599e4c012d9b53fa786863156d9a9401000edf148af81e5be5", 330 - "sha256:bf0c82b53b595cd91c3920081acd73b287c5aeb81e756e6b1a636a10e01eaaa3", 331 - "sha256:bf7f553e13916b67572c8ae8ea1b3227d709dfc4d98699a0451027174dc3739a", 332 - "sha256:c17ae8593e33bbb3c377974cd046be03453e0a317b5c723b9375fc00491ac5dd", 333 - "sha256:c1f3ed8f70b215a294b5c6830e91af48acde96b3c8a6cae13304291f8240b939", 334 - "sha256:c4a0538187b8a2dfc9507d83ff6e9de150802f81c67d22c043e4036653ca048e", 335 - "sha256:c8957b49c946d4ddd70f37bfe289494fab9088529db452f1cfcce31501369917", 336 - "sha256:ca53a59670b113be3b57910c3132d003fd4571f2c83f75bbfc758f5ff3288708", 337 - "sha256:d1549bfab54a1f422ec48d3141c9ec643444d8e80135b2a6e8ec8e109df05ff3", 338 - "sha256:d5cd74d2e17435869c21400cb587e788785bf7f565897c0e651f82e69bc0da27", 339 - "sha256:d689891c00251c22439ccfa4a445cee77cfa68b9e703fdf7ffe7abe4de56da86", 340 - "sha256:d6ed1bbdd5380a23ca84d4460c65f46d85f12ca860ef801212806ffe5ad497fa", 341 - "sha256:d9433e7c0ee73f30bc6849363660f8e7fda97fae5e3f0cf261e54af86dfa681d", 342 - "sha256:d9f8849acfb2e13d10aa4e8095c6eb65db7f431d3a38c60760de0f0abebcd58d", 343 - "sha256:e35a8735b8a4bdd09b9edfbf1ae36e9ba9a804de50c99352c9a06aa3da109a62", 344 - "sha256:e52f5111d7d06838993d7c35256cb3e19143239c602cda177273788b0cb5ffc5", 345 - "sha256:e7627f371682160cae818f817eb846bc8c267a5daa028748a7c73103d8df00eb", 346 - "sha256:edbfe93ae92609436471a83a80219e3ab07d79496d39ef161d4111eb47ea8184", 347 - "sha256:f11e053f954fe8efc37ee1d71ff3c20844551d1b2468388612876ecac500ccc3", 348 - "sha256:f46179c722baf74c627c01c0bf85be7fcbde66bbf7c5f8c1bbb57bd3a17b861b", 349 - "sha256:f78507f2f458239e4e7fe2f984c59c5f5060f1ec401e8f38cd2b59fc85d7d8fb", 350 - "sha256:fa67924c14b481f3f2c3d8a173d755955c2363d889ffc78dadb8d6abcaa7fe3c", 351 - "sha256:fd0877ef4a1bd6e42ba52659769b5b766583c67b3cfb4e7143f9d10b81fb7a74" 352 - ], 353 - "markers": "python_version >= '3.8'", 354 - "version": "==3.3.2" 355 - }, 356 - "markdown-it-py": { 357 - "hashes": [ 358 - "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", 359 - "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3" 360 - ], 361 - "markers": "python_version >= '3.10'", 362 - "version": "==4.0.0" 363 - }, 364 - "mdurl": { 365 - "hashes": [ 366 - "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", 367 - "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" 368 - ], 369 - "markers": "python_version >= '3.7'", 370 - "version": "==0.1.2" 371 - }, 372 - "packaging": { 373 - "hashes": [ 374 - "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", 375 - "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529" 376 - ], 377 - "markers": "python_version >= '3.8'", 378 - "version": "==26.0" 379 - }, 380 - "pluggy": { 381 - "hashes": [ 382 - "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", 383 - "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" 384 - ], 385 - "markers": "python_version >= '3.9'", 386 - "version": "==1.6.0" 387 - }, 388 - "pycparser": { 389 - "hashes": [ 390 - "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", 391 - "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992" 392 - ], 393 - "markers": "python_version >= '3.10'", 394 - "version": "==3.0" 395 - }, 396 - "pydantic": { 397 - "hashes": [ 398 - "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", 399 - "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d" 400 - ], 401 - "markers": "python_version >= '3.9'", 402 - "version": "==2.12.5" 403 - }, 404 - "pydantic-core": { 405 - "hashes": [ 406 - "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", 407 - "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", 408 - "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504", 409 - "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", 410 - "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", 411 - "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", 412 - "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", 413 - "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", 414 - "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", 415 - "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", 416 - "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", 417 - "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", 418 - "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", 419 - "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", 420 - "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", 421 - "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", 422 - "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", 423 - "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", 424 - "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", 425 - "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", 426 - "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", 427 - "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", 428 - "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", 429 - "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", 430 - "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5", 431 - "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", 432 - "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", 433 - "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", 434 - "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", 435 - "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", 436 - "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", 437 - "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5", 438 - "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", 439 - "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", 440 - "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", 441 - "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", 442 - "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", 443 - "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", 444 - "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", 445 - "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", 446 - "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", 447 - "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", 448 - "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", 449 - "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", 450 - "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", 451 - "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", 452 - "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", 453 - "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", 454 - "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", 455 - "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", 456 - "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", 457 - "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", 458 - "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", 459 - "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", 460 - "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", 461 - "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", 462 - "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3", 463 - "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", 464 - "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3", 465 - "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", 466 - "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", 467 - "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", 468 - "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", 469 - "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60", 470 - "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", 471 - "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", 472 - "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", 473 - "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", 474 - "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460", 475 - "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", 476 - "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf", 477 - "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", 478 - "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", 479 - "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", 480 - "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", 481 - "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", 482 - "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", 483 - "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", 484 - "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", 485 - "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d", 486 - "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", 487 - "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", 488 - "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", 489 - "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", 490 - "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", 491 - "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", 492 - "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", 493 - "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", 494 - "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", 495 - "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", 496 - "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", 497 - "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", 498 - "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", 499 - "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", 500 - "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", 501 - "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", 502 - "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", 503 - "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", 504 - "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", 505 - "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", 506 - "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", 507 - "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", 508 - "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", 509 - "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", 510 - "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b", 511 - "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", 512 - "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", 513 - "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", 514 - "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", 515 - "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82", 516 - "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", 517 - "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", 518 - "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", 519 - "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", 520 - "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5", 521 - "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", 522 - "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", 523 - "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", 524 - "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", 525 - "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425", 526 - "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52" 527 - ], 528 - "markers": "python_version >= '3.9'", 529 - "version": "==2.41.5" 530 - }, 531 - "pygments": { 532 - "hashes": [ 533 - "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", 534 - "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" 535 - ], 536 - "markers": "python_version >= '3.8'", 537 - "version": "==2.19.2" 538 - }, 539 - "pytest": { 540 - "hashes": [ 541 - "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", 542 - "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11" 543 - ], 544 - "index": "pypi", 545 - "markers": "python_version >= '3.10'", 546 - "version": "==9.0.2" 547 - }, 548 - "rich": { 549 - "hashes": [ 550 - "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", 551 - "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b" 552 - ], 553 - "markers": "python_full_version >= '3.8.0'", 554 - "version": "==14.3.3" 555 - }, 556 - "shellingham": { 557 - "hashes": [ 558 - "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", 559 - "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" 560 - ], 561 - "markers": "python_version >= '3.7'", 562 - "version": "==1.5.4" 563 - }, 564 - "typer": { 565 - "hashes": [ 566 - "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", 567 - "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d" 568 - ], 569 - "index": "pypi", 570 - "markers": "python_version >= '3.9'", 571 - "version": "==0.21.1" 572 - }, 573 - "typing-extensions": { 574 - "hashes": [ 575 - "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", 576 - "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" 577 - ], 578 - "markers": "python_version >= '3.9'", 579 - "version": "==4.15.0" 580 - }, 581 - "typing-inspection": { 582 - "hashes": [ 583 - "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", 584 - "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464" 585 - ], 586 - "markers": "python_version >= '3.9'", 587 - "version": "==0.4.2" 588 - }, 589 - "websockets": { 590 - "hashes": [ 591 - "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", 592 - "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", 593 - "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", 594 - "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", 595 - "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", 596 - "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", 597 - "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", 598 - "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", 599 - "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", 600 - "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880", 601 - "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123", 602 - "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", 603 - "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", 604 - "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed", 605 - "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", 606 - "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411", 607 - "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", 608 - "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", 609 - "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", 610 - "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", 611 - "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb", 612 - "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e", 613 - "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee", 614 - "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f", 615 - "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", 616 - "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", 617 - "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", 618 - "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", 619 - "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", 620 - "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", 621 - "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", 622 - "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", 623 - "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", 624 - "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5", 625 - "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", 626 - "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", 627 - "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", 628 - "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9", 629 - "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", 630 - "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", 631 - "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", 632 - "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", 633 - "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940", 634 - "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", 635 - "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", 636 - "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", 637 - "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", 638 - "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b", 639 - "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a", 640 - "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054", 641 - "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", 642 - "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", 643 - "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", 644 - "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4", 645 - "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", 646 - "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", 647 - "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", 648 - "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b", 649 - "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", 650 - "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770", 651 - "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", 652 - "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", 653 - "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", 654 - "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", 655 - "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", 656 - "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", 657 - "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", 658 - "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", 659 - "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7" 660 - ], 661 - "markers": "python_version >= '3.9'", 662 - "version": "==15.0.1" 663 - } 664 - }, 665 - "develop": {} 666 - }
+6 -22
README.md
··· 6 6 7 7 ``` 8 8 git submodule update --init --recursive 9 - pipenv install 10 - ``` 11 - 12 - **Testing:** 13 - 14 - ``` 15 - pipenv run python -m pytest 9 + npm install 16 10 ``` 17 11 18 12 ## Schema Generation 19 13 20 - The `schema/` folder contains scripts to generate a GraphQL schema from Lexicon. Standard ATProto definitions are initialized in the `deps/atproto` folder. 14 + This folder contains scripts to generate a GraphQL schema from Lexicon. Standard ATProto definitions are initialized in the `deps/atproto` folder. 21 15 22 16 Example usage: 23 17 24 18 ``` 25 - pipenv run python schema/generate_lexicon_schema.py \ 19 + npx tsx src/generateLexiconSchema.ts \ 26 20 app.bsky.actor.getProfile \ 27 21 com.atproto.server.getSession \ 28 - -o schema/schema-generated.graphql 22 + -o schema-generated.graphql 29 23 ``` 30 24 31 25 This will generate schema definitions for the `getProfile` and `getSession` procedures and recursively import all their referenced types, e.g. ··· 73 67 ### Building 74 68 75 69 ```bash 76 - cd server 77 - cargo run --release 70 + npm run server 78 71 ``` 79 72 80 - The server will start on `http://localhost:8080` by default. 81 - 82 - ### Environment Configuration 83 - 84 - Copy `.env.example` to `.env` and configure as needed for your deployment. 85 - 86 - | Variable | Default | Description | 87 - |----------|---------|-------------| 88 - | `HOST` | `0.0.0.0` | Host to bind the server to | 89 - | `PORT` | `8080` | Port to listen on | 73 + The server will start on `http://localhost:8000`. 90 74 91 75 ## License 92 76
js/package-lock.json package-lock.json
js/package.json package.json
js/public/index.html public/index.html
js/schema-generated.graphql schema-generated.graphql
js/src/generateLexiconSchema.ts src/generateLexiconSchema.ts
js/src/server/server.js src/server/server.js
js/tsconfig.json tsconfig.json
schema/__init__.py

This is a binary file and will not be displayed.

-466
schema/generate_lexicon_schema.py
··· 1 - """Convert Lexicon definitions to GraphQL""" 2 - 3 - import os 4 - import re 5 - import sys 6 - import traceback 7 - from pathlib import Path 8 - from typing import Annotated, TypeAlias 9 - 10 - from atproto_lexicon.models import ( 11 - LexArray, 12 - LexBlob, 13 - LexDefinition, 14 - LexObject, 15 - LexPrimitive, 16 - LexRef, 17 - LexRefUnion, 18 - LexRefVariant, 19 - LexString, 20 - LexXrpcQuery, 21 - ) 22 - from atproto_lexicon.parser import lexicon_parse_file 23 - from typer import Argument, Option, run 24 - 25 - 26 - def normalize_type_name(s: str) -> str: 27 - """ 28 - Normalize type name to PascalCase 29 - """ 30 - # Convert to PascalCase 31 - return s[0].upper() + s[1:] if s else s 32 - 33 - 34 - class LexiconPath: 35 - _segments: list[str] 36 - 37 - def __init__(self, path: str | None = None) -> None: 38 - if path is None: 39 - self._segments = [] 40 - else: 41 - self._segments = path.split(".") 42 - 43 - @property 44 - def segments(self): 45 - return self._segments[:] 46 - 47 - def dot_path(self): 48 - return ".".join(self._segments) 49 - 50 - def file_path(self): 51 - return "/".join(self._segments) 52 - 53 - 54 - # Constants 55 - BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 56 - LEXICON_DIR = os.path.join(BASE_DIR, "../deps/atproto/lexicons") 57 - 58 - TYPE_MAPPING = { 59 - "string": "String", 60 - "integer": "Int", 61 - "number": "Float", 62 - "boolean": "Boolean", 63 - "bytes": "String", 64 - } 65 - 66 - FORMAT_MAPPING = { 67 - "did": "ID", 68 - "handle": "ID", 69 - "uri": "String", 70 - "cid": "String", 71 - "datetime": "String", 72 - "date": "String", 73 - "time": "String", 74 - "at-identifier": "ID", 75 - } 76 - 77 - SKIP_FIELDS = {"debug"} # Fields to skip in GraphQL output 78 - 79 - 80 - def resolve_lexicon_path(lexicon_path: LexiconPath) -> str: 81 - """ 82 - Resolve a lexicon ID to its file path 83 - """ 84 - dir_parts = lexicon_path.segments 85 - 86 - # Construct path: app.bsky.actor.getProfile -> app/bsky/actor/getProfile.json 87 - file_path = os.path.join(LEXICON_DIR, *dir_parts[:-1], f"{dir_parts[-1]}.json") 88 - 89 - if not os.path.exists(file_path): 90 - raise FileNotFoundError(f"Lexicon file not found: {file_path}") 91 - 92 - return file_path 93 - 94 - 95 - def normalize_reference(base: str, ref: str) -> str: 96 - """ 97 - Normalize a reference like '#profileViewDetailed' 98 - """ 99 - if "#" in base and ref[0] == "#": 100 - return base.split("#")[0] + ref 101 - elif "#" not in base and ref[0] == "#": 102 - return base + ref 103 - else: 104 - return ref 105 - 106 - 107 - def resolve_reference(ref: str) -> LexDefinition | None: 108 - if "#" in ref: 109 - lexicon_id, type_name = ref.split("#", 1) 110 - else: 111 - lexicon_id = ref 112 - type_name = "main" 113 - try: 114 - lexicon_path = resolve_lexicon_path(LexiconPath(lexicon_id)) 115 - 116 - # Use structured parsing instead of JSON 117 - lexicon_structured_data = lexicon_parse_file(lexicon_path) 118 - 119 - # Find the type definition in the structured data 120 - if not lexicon_structured_data: 121 - return None 122 - 123 - defs = lexicon_structured_data.defs 124 - 125 - # Check if the type_name is in defs directly (as dict key) 126 - if type_name in defs: 127 - return defs[type_name] 128 - 129 - return None 130 - except Exception as e: 131 - print(f"Warning: Could not resolve reference {ref}: {e}", file=sys.stderr) 132 - return None 133 - 134 - 135 - def lex_type_to_graphql_type( 136 - base: str, 137 - lex_type: LexRefVariant | LexPrimitive | LexBlob | LexObject | LexArray, 138 - is_required: bool = False, 139 - ) -> str: 140 - """ 141 - Convert Lexicon type to GraphQL type 142 - """ 143 - if isinstance(lex_type, LexArray): 144 - items_type = lex_type.items 145 - item_type = lex_type_to_graphql_type(base, items_type, True) 146 - output = f"[{item_type}]" 147 - elif isinstance(lex_type, LexRef): 148 - # For reference types, we use the type name directly 149 - ref = normalize_reference(base, lex_type.ref) or "" 150 - # Convert to GraphQL naming convention - camelCase to PascalCase 151 - type_name = f"Lexicon_{ref.replace('#', '.').replace('.', '_')}" 152 - output = type_name 153 - elif isinstance(lex_type, LexString): 154 - if lex_type.format in FORMAT_MAPPING: 155 - output = FORMAT_MAPPING[lex_type.format] 156 - else: 157 - output = "String" 158 - elif lex_type.type in TYPE_MAPPING: 159 - output = TYPE_MAPPING[lex_type.type] 160 - else: 161 - output = "Unknown" 162 - 163 - nullable_indicator = "!" if is_required else "" 164 - return f"{output}{nullable_indicator}" 165 - 166 - 167 - TypeDef: TypeAlias = LexObject | LexString 168 - TypeDefs: TypeAlias = dict[str, TypeDef] 169 - 170 - 171 - def to_upper_snake_case(s: str) -> str: 172 - return re.sub(r"[^a-zA-Z0-9]+", "_", s).upper() 173 - 174 - 175 - def lex_object_definition_to_graphql(type_name: str, type_def: TypeDef) -> str: 176 - """ 177 - Convert a LexObject definition from lexicon to GraphQL 178 - """ 179 - 180 - if isinstance(type_def, LexString): 181 - # Enums 182 - graphql_lines = [ 183 - f"# {type_name}\nenum Lexicon_{type_name.replace('#', '_').replace('.', '_')} {{" 184 - ] 185 - 186 - for field_name in type_def.known_values or []: 187 - graphql_lines.append(f" {to_upper_snake_case(field_name)}") 188 - else: 189 - # Struct/object definitions 190 - graphql_lines = [ 191 - f"# {type_name}\ntype Lexicon_{type_name.replace('#', '_').replace('.', '_')} {{" 192 - ] 193 - 194 - properties = type_def.properties 195 - required_fields = set(type_def.required or []) 196 - 197 - for field_name, field_def in properties.items(): 198 - # Skip debug field as per requirements 199 - if field_name in SKIP_FIELDS: 200 - continue 201 - 202 - # Skip ref unions(?) 203 - if isinstance(field_def, LexRefUnion): 204 - continue 205 - 206 - # Skip "unknown" fields 207 - if field_def.type == "unknown": 208 - continue 209 - 210 - is_required = field_name in required_fields 211 - graphql_type = lex_type_to_graphql_type(type_name, field_def, is_required) 212 - graphql_lines.append(f" {field_name}: {graphql_type}") 213 - 214 - graphql_lines.append("}") 215 - return "\n".join(graphql_lines) 216 - 217 - 218 - # Build the nested types from the outside in 219 - # For app.bsky.actor.getProfile, we need: 220 - # 1. type LexiconApp { bsky: LexiconAppBsky! } 221 - # 2. type LexiconAppBsky { actor: LexiconAppBskyActor! } 222 - # 3. type LexiconAppBskyActor { getProfile(...): ... } 223 - def output_lexicon_namespaces( 224 - namespaces: dict[str, str], root: LexiconPath 225 - ) -> list[str]: 226 - lines: list[str] = [] 227 - chunks: list[str] = [] 228 - root_len = len(root.segments) 229 - while len(namespaces): 230 - lexicon_path = LexiconPath(next(iter(namespaces))) 231 - if root_len == len(lexicon_path.segments) - 1: 232 - # Done, output the type 233 - lines.append(namespaces.pop(lexicon_path.dot_path())) 234 - else: 235 - next_segment = lexicon_path.segments[root_len] 236 - next_path = ( 237 - f"{root.dot_path()}.{next_segment}" if root_len > 0 else next_segment 238 - ) 239 - 240 - group: dict[str, str] = dict() 241 - for path in list(namespaces.keys()): 242 - if path.startswith(f"{next_path}."): 243 - group[path] = namespaces.pop(path) 244 - chunks += output_lexicon_namespaces(group, LexiconPath(next_path)) 245 - 246 - lines.append( 247 - f"{next_segment}: {'_'.join(['Lexicon'] + LexiconPath(next_path).segments)}!" 248 - ) 249 - 250 - content = " " + "\n ".join(lines) 251 - chunks.append(f"type {'_'.join(['Lexicon'] + root.segments)} {{\n{content}\n}}\n") 252 - return chunks 253 - 254 - 255 - def generate_lexicon_structure( 256 - lexicon_path: LexiconPath, 257 - ) -> tuple[str, TypeDefs]: 258 - """ 259 - Generate the nested Lexicon structure for a lexicon endpoint 260 - Returns (graphql_type, set(refs)) 261 - """ 262 - 263 - method_name = lexicon_path.segments[-1] 264 - 265 - try: 266 - # Structured parsing of the Lexicon .json file 267 - lexicon_structured_data = lexicon_parse_file(resolve_lexicon_path(lexicon_path)) 268 - 269 - if not lexicon_structured_data: 270 - return ("", dict()) 271 - 272 - defs = lexicon_structured_data.defs 273 - main_def = defs["main"] 274 - assert isinstance(main_def, LexXrpcQuery) 275 - 276 - # Build the method definition 277 - referenced_types: set[str] = set() 278 - object_definitions: TypeDefs = dict() 279 - 280 - # Add parameters as fields 281 - method_fields: list[str] = [] 282 - if main_def.parameters: 283 - params = main_def.parameters 284 - required_fields = params.required or [] 285 - for field_name, field_def in params.properties.items(): 286 - # Convert the structured field definition to dict for get_graphql_type 287 - is_required = field_name in required_fields 288 - graphql_type = lex_type_to_graphql_type( 289 - lexicon_path.dot_path(), field_def, is_required 290 - ) 291 - method_fields.append(f"{field_name}: {graphql_type}") 292 - 293 - # Sweep up refs 294 - if isinstance(field_def, LexRef): 295 - referenced_types.add(field_def.ref) 296 - 297 - method_params = f"({', '.join(method_fields)})" if len(method_fields) else "" 298 - 299 - return_type = None 300 - 301 - if main_def.output: 302 - output_schema = main_def.output.schema_ 303 - if isinstance(output_schema, LexRef): 304 - # Use the output type as return type 305 - return_type = lex_type_to_graphql_type( 306 - lexicon_path.dot_path(), output_schema 307 - ) 308 - 309 - # Sweep up refs 310 - referenced_types.add(output_schema.ref) 311 - elif isinstance(output_schema, LexObject): 312 - # Handle inline object definitions for return type 313 - output_type = f"Lexicon_{'_'.join(lexicon_path.segments)}Output" 314 - return_type = output_type 315 - object_definitions[lexicon_path.dot_path() + "Output"] = output_schema 316 - 317 - # Resolve references 318 - for ref in referenced_types: 319 - ref = normalize_reference(lexicon_path.dot_path(), ref) 320 - ref_def = resolve_reference(ref) 321 - if isinstance(ref_def, TypeDef): 322 - object_definitions[ref] = ref_def 323 - 324 - if return_type: 325 - method_def = f"{method_name}{method_params}: {return_type}" 326 - else: 327 - method_def = f"{method_name}{method_params}" 328 - 329 - return (method_def, object_definitions) 330 - except Exception as e: 331 - print( 332 - f"Error processing lexicon {'.'.join(lexicon_path.segments)}: {e}", 333 - file=sys.stderr, 334 - ) 335 - traceback.print_exc() 336 - return ("", dict()) 337 - 338 - 339 - def generate_definitions(lexicon_ids: list[str]) -> list[str]: 340 - chunks: list[str] = [] 341 - lexicon_fields: dict[str, str] = dict() 342 - object_definitions: TypeDefs = dict() 343 - for lexicon_id in lexicon_ids: 344 - lexicon_path = LexiconPath(lexicon_id) 345 - 346 - # Generate main lexicon structure 347 - method_type, collected_object_definitions = generate_lexicon_structure( 348 - lexicon_path 349 - ) 350 - lexicon_fields[lexicon_path.dot_path()] = method_type 351 - object_definitions.update(collected_object_definitions) 352 - 353 - # Walk output types for more refs 354 - final_definitions: TypeDefs = dict() 355 - new_definitions: TypeDefs = dict() 356 - while len(object_definitions): 357 - for obj_name, obj_def in object_definitions.items(): 358 - if isinstance(obj_def, LexObject): 359 - for field_def in obj_def.properties.values(): 360 - # Export refs 361 - if isinstance(field_def, LexRef): 362 - ref = normalize_reference(obj_name, field_def.ref) 363 - ref_def = resolve_reference(ref) 364 - if isinstance(ref_def, TypeDef): 365 - new_definitions[ref] = ref_def 366 - continue 367 - elif isinstance(field_def, LexArray) and isinstance( 368 - field_def.items, LexRef 369 - ): 370 - ref = normalize_reference(obj_name, field_def.items.ref) 371 - ref_def = resolve_reference(ref) 372 - if isinstance(ref_def, LexObject) or isinstance( 373 - ref_def, LexString 374 - ): 375 - new_definitions[ref] = ref_def 376 - continue 377 - 378 - final_definitions[obj_name] = obj_def 379 - 380 - # Reset object_definitions to only be ones we haven't seen yet. 381 - object_definitions = dict() 382 - for obj_key, obj_def in new_definitions.items(): 383 - if obj_key not in final_definitions: 384 - object_definitions[obj_key] = obj_def 385 - object_definitions = final_definitions 386 - 387 - # Generate types for all output types 388 - for name, type in object_definitions.items(): 389 - chunks.append(lex_object_definition_to_graphql(name, type) + "\n\n") 390 - 391 - # Generate Lexicon structs iteratively. 392 - chunks += output_lexicon_namespaces(lexicon_fields, LexiconPath()) 393 - 394 - return chunks 395 - 396 - 397 - def read_schema_files(schema_files: list[str] | None) -> str: 398 - """Read content from schema files or folders recursively.""" 399 - if not schema_files: 400 - return "" 401 - 402 - output = "" 403 - for schema_file in schema_files: 404 - path = Path(schema_file) 405 - if path.is_file(): 406 - # If it's a single file, read it 407 - with open(str(path), "r") as f: 408 - content = f.read() 409 - output += "\n" + content + "\n" 410 - elif path.is_dir(): 411 - # If it's a directory, recursively read all .graphql files 412 - for graphql_file in path.rglob("*.graphql"): 413 - with open(str(graphql_file), "r") as f: 414 - content = f.read() 415 - output += "\n" + content + "\n" 416 - return output 417 - 418 - 419 - def main( 420 - lexicon_ids: Annotated[ 421 - list[str], 422 - Argument( 423 - ..., 424 - help="List of lexicon identifiers to generate definitions for", 425 - ), 426 - ], 427 - output: Annotated[ 428 - str, 429 - Option( 430 - "--output", 431 - "-o", 432 - help="Output file path (default: stdout)", 433 - ), 434 - ], 435 - append_schema: Annotated[ 436 - list[str] | None, 437 - Option( 438 - "--append-schema", 439 - "-a", 440 - help="Additional GraphQL schema files or folders to append. Can be used multiple times.", 441 - ), 442 - ] = None, 443 - ) -> None: 444 - """Generate GraphQL schema from lexicon_ids and source files.""" 445 - 446 - output_content: str = "" 447 - 448 - # Append additional schemas if provided via --append-schema 449 - if append_schema: 450 - additional_schemas = read_schema_files(append_schema) 451 - output_content += additional_schemas 452 - 453 - # Append the new schema. 454 - output_content += "\n\n".join(generate_definitions(lexicon_ids)) 455 - 456 - # Write to output file 457 - if output: 458 - output_path: str = output 459 - with open(output_path, "w") as f: 460 - _ = f.write(output_content) 461 - else: 462 - print(output) 463 - 464 - 465 - if __name__ == "__main__": 466 - run(main)
-14
server/.env.example
··· 1 - # GraphQL Server Configuration 2 - # Copy this file to .env and modify as needed 3 - 4 - # Server host (default: 0.0.0.0 for all interfaces) 5 - HOST=0.0.0.0 6 - 7 - # Server port (default: 8080) 8 - PORT=8080 9 - 10 - # Database connection string (if using database) 11 - # DATABASE_URL=postgres://user:password@localhost:5432/mothball 12 - 13 - # Logging level (debug, info, warn, error) 14 - # RUST_LOG=info
-3
server/.gitmodules
··· 1 - [submodule "deps/atproto"] 2 - path = deps/atproto 3 - url = https://github.com/bluesky-social/atproto.git
-6
server/.rules
··· 1 - # Mothball (Backend) 2 - 3 - This repo is for Mothball, an app for selling items locally. 4 - 5 - - The repo is written in Rust. 6 - - The primary frameworks are `axum` for powering the web server, `juniper` for powering the GraphQL engine.
-1486
server/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 = "android_system_properties" 7 - version = "0.1.5" 8 - source = "registry+https://github.com/rust-lang/crates.io-index" 9 - checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 10 - dependencies = [ 11 - "libc", 12 - ] 13 - 14 - [[package]] 15 - name = "arcstr" 16 - version = "1.2.0" 17 - source = "registry+https://github.com/rust-lang/crates.io-index" 18 - checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" 19 - 20 - [[package]] 21 - name = "async-trait" 22 - version = "0.1.89" 23 - source = "registry+https://github.com/rust-lang/crates.io-index" 24 - checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" 25 - dependencies = [ 26 - "proc-macro2", 27 - "quote", 28 - "syn", 29 - ] 30 - 31 - [[package]] 32 - name = "atomic-waker" 33 - version = "1.1.2" 34 - source = "registry+https://github.com/rust-lang/crates.io-index" 35 - checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 36 - 37 - [[package]] 38 - name = "auto_enums" 39 - version = "0.8.7" 40 - source = "registry+https://github.com/rust-lang/crates.io-index" 41 - checksum = "9c170965892137a3a9aeb000b4524aa3cc022a310e709d848b6e1cdce4ab4781" 42 - dependencies = [ 43 - "derive_utils", 44 - "proc-macro2", 45 - "quote", 46 - "syn", 47 - ] 48 - 49 - [[package]] 50 - name = "autocfg" 51 - version = "1.5.0" 52 - source = "registry+https://github.com/rust-lang/crates.io-index" 53 - checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 54 - 55 - [[package]] 56 - name = "axum" 57 - version = "0.8.7" 58 - source = "registry+https://github.com/rust-lang/crates.io-index" 59 - checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" 60 - dependencies = [ 61 - "axum-core", 62 - "bytes", 63 - "form_urlencoded", 64 - "futures-util", 65 - "http", 66 - "http-body", 67 - "http-body-util", 68 - "hyper", 69 - "hyper-util", 70 - "itoa", 71 - "matchit", 72 - "memchr", 73 - "mime", 74 - "percent-encoding", 75 - "pin-project-lite", 76 - "serde_core", 77 - "serde_json", 78 - "serde_path_to_error", 79 - "serde_urlencoded", 80 - "sync_wrapper", 81 - "tokio", 82 - "tower", 83 - "tower-layer", 84 - "tower-service", 85 - "tracing", 86 - ] 87 - 88 - [[package]] 89 - name = "axum-core" 90 - version = "0.5.5" 91 - source = "registry+https://github.com/rust-lang/crates.io-index" 92 - checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" 93 - dependencies = [ 94 - "bytes", 95 - "futures-core", 96 - "http", 97 - "http-body", 98 - "http-body-util", 99 - "mime", 100 - "pin-project-lite", 101 - "sync_wrapper", 102 - "tower-layer", 103 - "tower-service", 104 - "tracing", 105 - ] 106 - 107 - [[package]] 108 - name = "bitflags" 109 - version = "2.10.0" 110 - source = "registry+https://github.com/rust-lang/crates.io-index" 111 - checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" 112 - 113 - [[package]] 114 - name = "bumpalo" 115 - version = "3.19.1" 116 - source = "registry+https://github.com/rust-lang/crates.io-index" 117 - checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" 118 - 119 - [[package]] 120 - name = "bytes" 121 - version = "1.11.0" 122 - source = "registry+https://github.com/rust-lang/crates.io-index" 123 - checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" 124 - 125 - [[package]] 126 - name = "castaway" 127 - version = "0.2.4" 128 - source = "registry+https://github.com/rust-lang/crates.io-index" 129 - checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" 130 - dependencies = [ 131 - "rustversion", 132 - ] 133 - 134 - [[package]] 135 - name = "cc" 136 - version = "1.2.49" 137 - source = "registry+https://github.com/rust-lang/crates.io-index" 138 - checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" 139 - dependencies = [ 140 - "find-msvc-tools", 141 - "shlex", 142 - ] 143 - 144 - [[package]] 145 - name = "cfg-if" 146 - version = "1.0.4" 147 - source = "registry+https://github.com/rust-lang/crates.io-index" 148 - checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 149 - 150 - [[package]] 151 - name = "chrono" 152 - version = "0.4.42" 153 - source = "registry+https://github.com/rust-lang/crates.io-index" 154 - checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" 155 - dependencies = [ 156 - "iana-time-zone", 157 - "js-sys", 158 - "num-traits", 159 - "wasm-bindgen", 160 - "windows-link", 161 - ] 162 - 163 - [[package]] 164 - name = "compact_str" 165 - version = "0.9.0" 166 - source = "registry+https://github.com/rust-lang/crates.io-index" 167 - checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" 168 - dependencies = [ 169 - "castaway", 170 - "cfg-if", 171 - "itoa", 172 - "rustversion", 173 - "ryu", 174 - "static_assertions", 175 - ] 176 - 177 - [[package]] 178 - name = "convert_case" 179 - version = "0.10.0" 180 - source = "registry+https://github.com/rust-lang/crates.io-index" 181 - checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" 182 - dependencies = [ 183 - "unicode-segmentation", 184 - ] 185 - 186 - [[package]] 187 - name = "core-foundation-sys" 188 - version = "0.8.7" 189 - source = "registry+https://github.com/rust-lang/crates.io-index" 190 - checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 191 - 192 - [[package]] 193 - name = "derive_more" 194 - version = "2.1.0" 195 - source = "registry+https://github.com/rust-lang/crates.io-index" 196 - checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" 197 - dependencies = [ 198 - "derive_more-impl", 199 - ] 200 - 201 - [[package]] 202 - name = "derive_more-impl" 203 - version = "2.1.0" 204 - source = "registry+https://github.com/rust-lang/crates.io-index" 205 - checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" 206 - dependencies = [ 207 - "convert_case", 208 - "proc-macro2", 209 - "quote", 210 - "rustc_version", 211 - "syn", 212 - "unicode-xid", 213 - ] 214 - 215 - [[package]] 216 - name = "derive_utils" 217 - version = "0.15.0" 218 - source = "registry+https://github.com/rust-lang/crates.io-index" 219 - checksum = "ccfae181bab5ab6c5478b2ccb69e4c68a02f8c3ec72f6616bfec9dbc599d2ee0" 220 - dependencies = [ 221 - "proc-macro2", 222 - "quote", 223 - "syn", 224 - ] 225 - 226 - [[package]] 227 - name = "displaydoc" 228 - version = "0.2.5" 229 - source = "registry+https://github.com/rust-lang/crates.io-index" 230 - checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 231 - dependencies = [ 232 - "proc-macro2", 233 - "quote", 234 - "syn", 235 - ] 236 - 237 - [[package]] 238 - name = "dotenv" 239 - version = "0.15.0" 240 - source = "registry+https://github.com/rust-lang/crates.io-index" 241 - checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" 242 - 243 - [[package]] 244 - name = "either" 245 - version = "1.15.0" 246 - source = "registry+https://github.com/rust-lang/crates.io-index" 247 - checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 248 - 249 - [[package]] 250 - name = "equivalent" 251 - version = "1.0.2" 252 - source = "registry+https://github.com/rust-lang/crates.io-index" 253 - checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 254 - 255 - [[package]] 256 - name = "find-msvc-tools" 257 - version = "0.1.5" 258 - source = "registry+https://github.com/rust-lang/crates.io-index" 259 - checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" 260 - 261 - [[package]] 262 - name = "fnv" 263 - version = "1.0.7" 264 - source = "registry+https://github.com/rust-lang/crates.io-index" 265 - checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 266 - 267 - [[package]] 268 - name = "form_urlencoded" 269 - version = "1.2.2" 270 - source = "registry+https://github.com/rust-lang/crates.io-index" 271 - checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 272 - dependencies = [ 273 - "percent-encoding", 274 - ] 275 - 276 - [[package]] 277 - name = "futures" 278 - version = "0.3.31" 279 - source = "registry+https://github.com/rust-lang/crates.io-index" 280 - checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 281 - dependencies = [ 282 - "futures-channel", 283 - "futures-core", 284 - "futures-executor", 285 - "futures-io", 286 - "futures-sink", 287 - "futures-task", 288 - "futures-util", 289 - ] 290 - 291 - [[package]] 292 - name = "futures-channel" 293 - version = "0.3.31" 294 - source = "registry+https://github.com/rust-lang/crates.io-index" 295 - checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 296 - dependencies = [ 297 - "futures-core", 298 - "futures-sink", 299 - ] 300 - 301 - [[package]] 302 - name = "futures-core" 303 - version = "0.3.31" 304 - source = "registry+https://github.com/rust-lang/crates.io-index" 305 - checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 306 - 307 - [[package]] 308 - name = "futures-executor" 309 - version = "0.3.31" 310 - source = "registry+https://github.com/rust-lang/crates.io-index" 311 - checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 312 - dependencies = [ 313 - "futures-core", 314 - "futures-task", 315 - "futures-util", 316 - ] 317 - 318 - [[package]] 319 - name = "futures-io" 320 - version = "0.3.31" 321 - source = "registry+https://github.com/rust-lang/crates.io-index" 322 - checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 323 - 324 - [[package]] 325 - name = "futures-macro" 326 - version = "0.3.31" 327 - source = "registry+https://github.com/rust-lang/crates.io-index" 328 - checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 329 - dependencies = [ 330 - "proc-macro2", 331 - "quote", 332 - "syn", 333 - ] 334 - 335 - [[package]] 336 - name = "futures-sink" 337 - version = "0.3.31" 338 - source = "registry+https://github.com/rust-lang/crates.io-index" 339 - checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 340 - 341 - [[package]] 342 - name = "futures-task" 343 - version = "0.3.31" 344 - source = "registry+https://github.com/rust-lang/crates.io-index" 345 - checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 346 - 347 - [[package]] 348 - name = "futures-util" 349 - version = "0.3.31" 350 - source = "registry+https://github.com/rust-lang/crates.io-index" 351 - checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 352 - dependencies = [ 353 - "futures-channel", 354 - "futures-core", 355 - "futures-io", 356 - "futures-macro", 357 - "futures-sink", 358 - "futures-task", 359 - "memchr", 360 - "pin-project-lite", 361 - "pin-utils", 362 - "slab", 363 - ] 364 - 365 - [[package]] 366 - name = "getrandom" 367 - version = "0.3.4" 368 - source = "registry+https://github.com/rust-lang/crates.io-index" 369 - checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" 370 - dependencies = [ 371 - "cfg-if", 372 - "libc", 373 - "r-efi", 374 - "wasip2", 375 - ] 376 - 377 - [[package]] 378 - name = "hashbrown" 379 - version = "0.16.1" 380 - source = "registry+https://github.com/rust-lang/crates.io-index" 381 - checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 382 - 383 - [[package]] 384 - name = "http" 385 - version = "1.4.0" 386 - source = "registry+https://github.com/rust-lang/crates.io-index" 387 - checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" 388 - dependencies = [ 389 - "bytes", 390 - "itoa", 391 - ] 392 - 393 - [[package]] 394 - name = "http-body" 395 - version = "1.0.1" 396 - source = "registry+https://github.com/rust-lang/crates.io-index" 397 - checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 398 - dependencies = [ 399 - "bytes", 400 - "http", 401 - ] 402 - 403 - [[package]] 404 - name = "http-body-util" 405 - version = "0.1.3" 406 - source = "registry+https://github.com/rust-lang/crates.io-index" 407 - checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 408 - dependencies = [ 409 - "bytes", 410 - "futures-core", 411 - "http", 412 - "http-body", 413 - "pin-project-lite", 414 - ] 415 - 416 - [[package]] 417 - name = "httparse" 418 - version = "1.10.1" 419 - source = "registry+https://github.com/rust-lang/crates.io-index" 420 - checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 421 - 422 - [[package]] 423 - name = "httpdate" 424 - version = "1.0.3" 425 - source = "registry+https://github.com/rust-lang/crates.io-index" 426 - checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 427 - 428 - [[package]] 429 - name = "hyper" 430 - version = "1.8.1" 431 - source = "registry+https://github.com/rust-lang/crates.io-index" 432 - checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" 433 - dependencies = [ 434 - "atomic-waker", 435 - "bytes", 436 - "futures-channel", 437 - "futures-core", 438 - "http", 439 - "http-body", 440 - "httparse", 441 - "httpdate", 442 - "itoa", 443 - "pin-project-lite", 444 - "pin-utils", 445 - "smallvec", 446 - "tokio", 447 - ] 448 - 449 - [[package]] 450 - name = "hyper-util" 451 - version = "0.1.19" 452 - source = "registry+https://github.com/rust-lang/crates.io-index" 453 - checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" 454 - dependencies = [ 455 - "bytes", 456 - "futures-core", 457 - "http", 458 - "http-body", 459 - "hyper", 460 - "pin-project-lite", 461 - "tokio", 462 - "tower-service", 463 - ] 464 - 465 - [[package]] 466 - name = "iana-time-zone" 467 - version = "0.1.64" 468 - source = "registry+https://github.com/rust-lang/crates.io-index" 469 - checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" 470 - dependencies = [ 471 - "android_system_properties", 472 - "core-foundation-sys", 473 - "iana-time-zone-haiku", 474 - "js-sys", 475 - "log", 476 - "wasm-bindgen", 477 - "windows-core", 478 - ] 479 - 480 - [[package]] 481 - name = "iana-time-zone-haiku" 482 - version = "0.1.2" 483 - source = "registry+https://github.com/rust-lang/crates.io-index" 484 - checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 485 - dependencies = [ 486 - "cc", 487 - ] 488 - 489 - [[package]] 490 - name = "icu_collections" 491 - version = "2.1.1" 492 - source = "registry+https://github.com/rust-lang/crates.io-index" 493 - checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" 494 - dependencies = [ 495 - "displaydoc", 496 - "potential_utf", 497 - "yoke", 498 - "zerofrom", 499 - "zerovec", 500 - ] 501 - 502 - [[package]] 503 - name = "icu_locale_core" 504 - version = "2.1.1" 505 - source = "registry+https://github.com/rust-lang/crates.io-index" 506 - checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" 507 - dependencies = [ 508 - "displaydoc", 509 - "litemap", 510 - "tinystr", 511 - "writeable", 512 - "zerovec", 513 - ] 514 - 515 - [[package]] 516 - name = "icu_normalizer" 517 - version = "2.1.1" 518 - source = "registry+https://github.com/rust-lang/crates.io-index" 519 - checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" 520 - dependencies = [ 521 - "icu_collections", 522 - "icu_normalizer_data", 523 - "icu_properties", 524 - "icu_provider", 525 - "smallvec", 526 - "zerovec", 527 - ] 528 - 529 - [[package]] 530 - name = "icu_normalizer_data" 531 - version = "2.1.1" 532 - source = "registry+https://github.com/rust-lang/crates.io-index" 533 - checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" 534 - 535 - [[package]] 536 - name = "icu_properties" 537 - version = "2.1.2" 538 - source = "registry+https://github.com/rust-lang/crates.io-index" 539 - checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" 540 - dependencies = [ 541 - "icu_collections", 542 - "icu_locale_core", 543 - "icu_properties_data", 544 - "icu_provider", 545 - "zerotrie", 546 - "zerovec", 547 - ] 548 - 549 - [[package]] 550 - name = "icu_properties_data" 551 - version = "2.1.2" 552 - source = "registry+https://github.com/rust-lang/crates.io-index" 553 - checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" 554 - 555 - [[package]] 556 - name = "icu_provider" 557 - version = "2.1.1" 558 - source = "registry+https://github.com/rust-lang/crates.io-index" 559 - checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" 560 - dependencies = [ 561 - "displaydoc", 562 - "icu_locale_core", 563 - "writeable", 564 - "yoke", 565 - "zerofrom", 566 - "zerotrie", 567 - "zerovec", 568 - ] 569 - 570 - [[package]] 571 - name = "idna" 572 - version = "1.1.0" 573 - source = "registry+https://github.com/rust-lang/crates.io-index" 574 - checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 575 - dependencies = [ 576 - "idna_adapter", 577 - "smallvec", 578 - "utf8_iter", 579 - ] 580 - 581 - [[package]] 582 - name = "idna_adapter" 583 - version = "1.2.1" 584 - source = "registry+https://github.com/rust-lang/crates.io-index" 585 - checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 586 - dependencies = [ 587 - "icu_normalizer", 588 - "icu_properties", 589 - ] 590 - 591 - [[package]] 592 - name = "indexmap" 593 - version = "2.12.1" 594 - source = "registry+https://github.com/rust-lang/crates.io-index" 595 - checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" 596 - dependencies = [ 597 - "equivalent", 598 - "hashbrown", 599 - "serde", 600 - "serde_core", 601 - ] 602 - 603 - [[package]] 604 - name = "itertools" 605 - version = "0.14.0" 606 - source = "registry+https://github.com/rust-lang/crates.io-index" 607 - checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" 608 - dependencies = [ 609 - "either", 610 - ] 611 - 612 - [[package]] 613 - name = "itoa" 614 - version = "1.0.15" 615 - source = "registry+https://github.com/rust-lang/crates.io-index" 616 - checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 617 - 618 - [[package]] 619 - name = "js-sys" 620 - version = "0.3.83" 621 - source = "registry+https://github.com/rust-lang/crates.io-index" 622 - checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" 623 - dependencies = [ 624 - "once_cell", 625 - "wasm-bindgen", 626 - ] 627 - 628 - [[package]] 629 - name = "juniper" 630 - version = "0.17.0" 631 - source = "registry+https://github.com/rust-lang/crates.io-index" 632 - checksum = "4feeb43439e89bc0cf5d86340374c828fc2b651de4750a970d6de5a4915a0d76" 633 - dependencies = [ 634 - "arcstr", 635 - "async-trait", 636 - "auto_enums", 637 - "compact_str", 638 - "derive_more", 639 - "fnv", 640 - "futures", 641 - "indexmap", 642 - "itertools", 643 - "juniper_codegen", 644 - "ref-cast", 645 - "serde", 646 - "static_assertions", 647 - ] 648 - 649 - [[package]] 650 - name = "juniper_axum" 651 - version = "0.3.0" 652 - source = "registry+https://github.com/rust-lang/crates.io-index" 653 - checksum = "d749d056510f6d762ceca1ae6bb53d50fd77019e5be65fe4bf2eca305a18b8ba" 654 - dependencies = [ 655 - "axum", 656 - "bytes", 657 - "juniper", 658 - "juniper_graphql_ws", 659 - "serde", 660 - "serde_json", 661 - ] 662 - 663 - [[package]] 664 - name = "juniper_codegen" 665 - version = "0.17.0" 666 - source = "registry+https://github.com/rust-lang/crates.io-index" 667 - checksum = "8634f500d6d2ec5c91c115b83e15d998d9ea05645aaa43f7afec09e660c483ba" 668 - dependencies = [ 669 - "derive_more", 670 - "proc-macro2", 671 - "quote", 672 - "syn", 673 - "url", 674 - ] 675 - 676 - [[package]] 677 - name = "juniper_graphql_ws" 678 - version = "0.5.0" 679 - source = "registry+https://github.com/rust-lang/crates.io-index" 680 - checksum = "02f74a1d6d28f29edd4e72db014229efef9b3c3baa5cdf64ebc76b82ee146fa5" 681 - dependencies = [ 682 - "derive_more", 683 - "juniper", 684 - "juniper_subscriptions", 685 - "serde", 686 - "tokio", 687 - ] 688 - 689 - [[package]] 690 - name = "juniper_subscriptions" 691 - version = "0.18.0" 692 - source = "registry+https://github.com/rust-lang/crates.io-index" 693 - checksum = "0aeaaedf8fe890b09a712224de8bf509477194fdeb35a39c32d8ada8ac754972" 694 - dependencies = [ 695 - "futures", 696 - "juniper", 697 - ] 698 - 699 - [[package]] 700 - name = "libc" 701 - version = "0.2.178" 702 - source = "registry+https://github.com/rust-lang/crates.io-index" 703 - checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" 704 - 705 - [[package]] 706 - name = "litemap" 707 - version = "0.8.1" 708 - source = "registry+https://github.com/rust-lang/crates.io-index" 709 - checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 710 - 711 - [[package]] 712 - name = "lock_api" 713 - version = "0.4.14" 714 - source = "registry+https://github.com/rust-lang/crates.io-index" 715 - checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" 716 - dependencies = [ 717 - "scopeguard", 718 - ] 719 - 720 - [[package]] 721 - name = "log" 722 - version = "0.4.29" 723 - source = "registry+https://github.com/rust-lang/crates.io-index" 724 - checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 725 - 726 - [[package]] 727 - name = "matchit" 728 - version = "0.8.4" 729 - source = "registry+https://github.com/rust-lang/crates.io-index" 730 - checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" 731 - 732 - [[package]] 733 - name = "memchr" 734 - version = "2.7.6" 735 - source = "registry+https://github.com/rust-lang/crates.io-index" 736 - checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" 737 - 738 - [[package]] 739 - name = "mime" 740 - version = "0.3.17" 741 - source = "registry+https://github.com/rust-lang/crates.io-index" 742 - checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 743 - 744 - [[package]] 745 - name = "mio" 746 - version = "1.1.1" 747 - source = "registry+https://github.com/rust-lang/crates.io-index" 748 - checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" 749 - dependencies = [ 750 - "libc", 751 - "wasi", 752 - "windows-sys 0.61.2", 753 - ] 754 - 755 - [[package]] 756 - name = "mothball-server" 757 - version = "0.1.0" 758 - dependencies = [ 759 - "axum", 760 - "chrono", 761 - "dotenv", 762 - "juniper", 763 - "juniper_axum", 764 - "serde", 765 - "serde_json", 766 - "tokio", 767 - "uuid", 768 - ] 769 - 770 - [[package]] 771 - name = "num-traits" 772 - version = "0.2.19" 773 - source = "registry+https://github.com/rust-lang/crates.io-index" 774 - checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 775 - dependencies = [ 776 - "autocfg", 777 - ] 778 - 779 - [[package]] 780 - name = "once_cell" 781 - version = "1.21.3" 782 - source = "registry+https://github.com/rust-lang/crates.io-index" 783 - checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 784 - 785 - [[package]] 786 - name = "parking_lot" 787 - version = "0.12.5" 788 - source = "registry+https://github.com/rust-lang/crates.io-index" 789 - checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" 790 - dependencies = [ 791 - "lock_api", 792 - "parking_lot_core", 793 - ] 794 - 795 - [[package]] 796 - name = "parking_lot_core" 797 - version = "0.9.12" 798 - source = "registry+https://github.com/rust-lang/crates.io-index" 799 - checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" 800 - dependencies = [ 801 - "cfg-if", 802 - "libc", 803 - "redox_syscall", 804 - "smallvec", 805 - "windows-link", 806 - ] 807 - 808 - [[package]] 809 - name = "percent-encoding" 810 - version = "2.3.2" 811 - source = "registry+https://github.com/rust-lang/crates.io-index" 812 - checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 813 - 814 - [[package]] 815 - name = "pin-project-lite" 816 - version = "0.2.16" 817 - source = "registry+https://github.com/rust-lang/crates.io-index" 818 - checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 819 - 820 - [[package]] 821 - name = "pin-utils" 822 - version = "0.1.0" 823 - source = "registry+https://github.com/rust-lang/crates.io-index" 824 - checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 825 - 826 - [[package]] 827 - name = "potential_utf" 828 - version = "0.1.4" 829 - source = "registry+https://github.com/rust-lang/crates.io-index" 830 - checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" 831 - dependencies = [ 832 - "zerovec", 833 - ] 834 - 835 - [[package]] 836 - name = "proc-macro2" 837 - version = "1.0.103" 838 - source = "registry+https://github.com/rust-lang/crates.io-index" 839 - checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" 840 - dependencies = [ 841 - "unicode-ident", 842 - ] 843 - 844 - [[package]] 845 - name = "quote" 846 - version = "1.0.42" 847 - source = "registry+https://github.com/rust-lang/crates.io-index" 848 - checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" 849 - dependencies = [ 850 - "proc-macro2", 851 - ] 852 - 853 - [[package]] 854 - name = "r-efi" 855 - version = "5.3.0" 856 - source = "registry+https://github.com/rust-lang/crates.io-index" 857 - checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 858 - 859 - [[package]] 860 - name = "redox_syscall" 861 - version = "0.5.18" 862 - source = "registry+https://github.com/rust-lang/crates.io-index" 863 - checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" 864 - dependencies = [ 865 - "bitflags", 866 - ] 867 - 868 - [[package]] 869 - name = "ref-cast" 870 - version = "1.0.25" 871 - source = "registry+https://github.com/rust-lang/crates.io-index" 872 - checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" 873 - dependencies = [ 874 - "ref-cast-impl", 875 - ] 876 - 877 - [[package]] 878 - name = "ref-cast-impl" 879 - version = "1.0.25" 880 - source = "registry+https://github.com/rust-lang/crates.io-index" 881 - checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" 882 - dependencies = [ 883 - "proc-macro2", 884 - "quote", 885 - "syn", 886 - ] 887 - 888 - [[package]] 889 - name = "rustc_version" 890 - version = "0.4.1" 891 - source = "registry+https://github.com/rust-lang/crates.io-index" 892 - checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 893 - dependencies = [ 894 - "semver", 895 - ] 896 - 897 - [[package]] 898 - name = "rustversion" 899 - version = "1.0.22" 900 - source = "registry+https://github.com/rust-lang/crates.io-index" 901 - checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 902 - 903 - [[package]] 904 - name = "ryu" 905 - version = "1.0.20" 906 - source = "registry+https://github.com/rust-lang/crates.io-index" 907 - checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 908 - 909 - [[package]] 910 - name = "scopeguard" 911 - version = "1.2.0" 912 - source = "registry+https://github.com/rust-lang/crates.io-index" 913 - checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 914 - 915 - [[package]] 916 - name = "semver" 917 - version = "1.0.27" 918 - source = "registry+https://github.com/rust-lang/crates.io-index" 919 - checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" 920 - 921 - [[package]] 922 - name = "serde" 923 - version = "1.0.228" 924 - source = "registry+https://github.com/rust-lang/crates.io-index" 925 - checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 926 - dependencies = [ 927 - "serde_core", 928 - "serde_derive", 929 - ] 930 - 931 - [[package]] 932 - name = "serde_core" 933 - version = "1.0.228" 934 - source = "registry+https://github.com/rust-lang/crates.io-index" 935 - checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 936 - dependencies = [ 937 - "serde_derive", 938 - ] 939 - 940 - [[package]] 941 - name = "serde_derive" 942 - version = "1.0.228" 943 - source = "registry+https://github.com/rust-lang/crates.io-index" 944 - checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 945 - dependencies = [ 946 - "proc-macro2", 947 - "quote", 948 - "syn", 949 - ] 950 - 951 - [[package]] 952 - name = "serde_json" 953 - version = "1.0.145" 954 - source = "registry+https://github.com/rust-lang/crates.io-index" 955 - checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" 956 - dependencies = [ 957 - "itoa", 958 - "memchr", 959 - "ryu", 960 - "serde", 961 - "serde_core", 962 - ] 963 - 964 - [[package]] 965 - name = "serde_path_to_error" 966 - version = "0.1.20" 967 - source = "registry+https://github.com/rust-lang/crates.io-index" 968 - checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" 969 - dependencies = [ 970 - "itoa", 971 - "serde", 972 - "serde_core", 973 - ] 974 - 975 - [[package]] 976 - name = "serde_urlencoded" 977 - version = "0.7.1" 978 - source = "registry+https://github.com/rust-lang/crates.io-index" 979 - checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 980 - dependencies = [ 981 - "form_urlencoded", 982 - "itoa", 983 - "ryu", 984 - "serde", 985 - ] 986 - 987 - [[package]] 988 - name = "shlex" 989 - version = "1.3.0" 990 - source = "registry+https://github.com/rust-lang/crates.io-index" 991 - checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 992 - 993 - [[package]] 994 - name = "signal-hook-registry" 995 - version = "1.4.7" 996 - source = "registry+https://github.com/rust-lang/crates.io-index" 997 - checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" 998 - dependencies = [ 999 - "libc", 1000 - ] 1001 - 1002 - [[package]] 1003 - name = "slab" 1004 - version = "0.4.11" 1005 - source = "registry+https://github.com/rust-lang/crates.io-index" 1006 - checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 1007 - 1008 - [[package]] 1009 - name = "smallvec" 1010 - version = "1.15.1" 1011 - source = "registry+https://github.com/rust-lang/crates.io-index" 1012 - checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1013 - 1014 - [[package]] 1015 - name = "socket2" 1016 - version = "0.6.1" 1017 - source = "registry+https://github.com/rust-lang/crates.io-index" 1018 - checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" 1019 - dependencies = [ 1020 - "libc", 1021 - "windows-sys 0.60.2", 1022 - ] 1023 - 1024 - [[package]] 1025 - name = "stable_deref_trait" 1026 - version = "1.2.1" 1027 - source = "registry+https://github.com/rust-lang/crates.io-index" 1028 - checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 1029 - 1030 - [[package]] 1031 - name = "static_assertions" 1032 - version = "1.1.0" 1033 - source = "registry+https://github.com/rust-lang/crates.io-index" 1034 - checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1035 - 1036 - [[package]] 1037 - name = "syn" 1038 - version = "2.0.111" 1039 - source = "registry+https://github.com/rust-lang/crates.io-index" 1040 - checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" 1041 - dependencies = [ 1042 - "proc-macro2", 1043 - "quote", 1044 - "unicode-ident", 1045 - ] 1046 - 1047 - [[package]] 1048 - name = "sync_wrapper" 1049 - version = "1.0.2" 1050 - source = "registry+https://github.com/rust-lang/crates.io-index" 1051 - checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1052 - 1053 - [[package]] 1054 - name = "synstructure" 1055 - version = "0.13.2" 1056 - source = "registry+https://github.com/rust-lang/crates.io-index" 1057 - checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1058 - dependencies = [ 1059 - "proc-macro2", 1060 - "quote", 1061 - "syn", 1062 - ] 1063 - 1064 - [[package]] 1065 - name = "tinystr" 1066 - version = "0.8.2" 1067 - source = "registry+https://github.com/rust-lang/crates.io-index" 1068 - checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" 1069 - dependencies = [ 1070 - "displaydoc", 1071 - "zerovec", 1072 - ] 1073 - 1074 - [[package]] 1075 - name = "tokio" 1076 - version = "1.48.0" 1077 - source = "registry+https://github.com/rust-lang/crates.io-index" 1078 - checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" 1079 - dependencies = [ 1080 - "bytes", 1081 - "libc", 1082 - "mio", 1083 - "parking_lot", 1084 - "pin-project-lite", 1085 - "signal-hook-registry", 1086 - "socket2", 1087 - "tokio-macros", 1088 - "windows-sys 0.61.2", 1089 - ] 1090 - 1091 - [[package]] 1092 - name = "tokio-macros" 1093 - version = "2.6.0" 1094 - source = "registry+https://github.com/rust-lang/crates.io-index" 1095 - checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" 1096 - dependencies = [ 1097 - "proc-macro2", 1098 - "quote", 1099 - "syn", 1100 - ] 1101 - 1102 - [[package]] 1103 - name = "tower" 1104 - version = "0.5.2" 1105 - source = "registry+https://github.com/rust-lang/crates.io-index" 1106 - checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 1107 - dependencies = [ 1108 - "futures-core", 1109 - "futures-util", 1110 - "pin-project-lite", 1111 - "sync_wrapper", 1112 - "tokio", 1113 - "tower-layer", 1114 - "tower-service", 1115 - "tracing", 1116 - ] 1117 - 1118 - [[package]] 1119 - name = "tower-layer" 1120 - version = "0.3.3" 1121 - source = "registry+https://github.com/rust-lang/crates.io-index" 1122 - checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1123 - 1124 - [[package]] 1125 - name = "tower-service" 1126 - version = "0.3.3" 1127 - source = "registry+https://github.com/rust-lang/crates.io-index" 1128 - checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1129 - 1130 - [[package]] 1131 - name = "tracing" 1132 - version = "0.1.44" 1133 - source = "registry+https://github.com/rust-lang/crates.io-index" 1134 - checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" 1135 - dependencies = [ 1136 - "log", 1137 - "pin-project-lite", 1138 - "tracing-core", 1139 - ] 1140 - 1141 - [[package]] 1142 - name = "tracing-core" 1143 - version = "0.1.36" 1144 - source = "registry+https://github.com/rust-lang/crates.io-index" 1145 - checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" 1146 - dependencies = [ 1147 - "once_cell", 1148 - ] 1149 - 1150 - [[package]] 1151 - name = "unicode-ident" 1152 - version = "1.0.22" 1153 - source = "registry+https://github.com/rust-lang/crates.io-index" 1154 - checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 1155 - 1156 - [[package]] 1157 - name = "unicode-segmentation" 1158 - version = "1.12.0" 1159 - source = "registry+https://github.com/rust-lang/crates.io-index" 1160 - checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 1161 - 1162 - [[package]] 1163 - name = "unicode-xid" 1164 - version = "0.2.6" 1165 - source = "registry+https://github.com/rust-lang/crates.io-index" 1166 - checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 1167 - 1168 - [[package]] 1169 - name = "url" 1170 - version = "2.5.7" 1171 - source = "registry+https://github.com/rust-lang/crates.io-index" 1172 - checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 1173 - dependencies = [ 1174 - "form_urlencoded", 1175 - "idna", 1176 - "percent-encoding", 1177 - "serde", 1178 - ] 1179 - 1180 - [[package]] 1181 - name = "utf8_iter" 1182 - version = "1.0.4" 1183 - source = "registry+https://github.com/rust-lang/crates.io-index" 1184 - checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1185 - 1186 - [[package]] 1187 - name = "uuid" 1188 - version = "1.19.0" 1189 - source = "registry+https://github.com/rust-lang/crates.io-index" 1190 - checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" 1191 - dependencies = [ 1192 - "getrandom", 1193 - "js-sys", 1194 - "wasm-bindgen", 1195 - ] 1196 - 1197 - [[package]] 1198 - name = "wasi" 1199 - version = "0.11.1+wasi-snapshot-preview1" 1200 - source = "registry+https://github.com/rust-lang/crates.io-index" 1201 - checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 1202 - 1203 - [[package]] 1204 - name = "wasip2" 1205 - version = "1.0.1+wasi-0.2.4" 1206 - source = "registry+https://github.com/rust-lang/crates.io-index" 1207 - checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" 1208 - dependencies = [ 1209 - "wit-bindgen", 1210 - ] 1211 - 1212 - [[package]] 1213 - name = "wasm-bindgen" 1214 - version = "0.2.106" 1215 - source = "registry+https://github.com/rust-lang/crates.io-index" 1216 - checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" 1217 - dependencies = [ 1218 - "cfg-if", 1219 - "once_cell", 1220 - "rustversion", 1221 - "wasm-bindgen-macro", 1222 - "wasm-bindgen-shared", 1223 - ] 1224 - 1225 - [[package]] 1226 - name = "wasm-bindgen-macro" 1227 - version = "0.2.106" 1228 - source = "registry+https://github.com/rust-lang/crates.io-index" 1229 - checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" 1230 - dependencies = [ 1231 - "quote", 1232 - "wasm-bindgen-macro-support", 1233 - ] 1234 - 1235 - [[package]] 1236 - name = "wasm-bindgen-macro-support" 1237 - version = "0.2.106" 1238 - source = "registry+https://github.com/rust-lang/crates.io-index" 1239 - checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" 1240 - dependencies = [ 1241 - "bumpalo", 1242 - "proc-macro2", 1243 - "quote", 1244 - "syn", 1245 - "wasm-bindgen-shared", 1246 - ] 1247 - 1248 - [[package]] 1249 - name = "wasm-bindgen-shared" 1250 - version = "0.2.106" 1251 - source = "registry+https://github.com/rust-lang/crates.io-index" 1252 - checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" 1253 - dependencies = [ 1254 - "unicode-ident", 1255 - ] 1256 - 1257 - [[package]] 1258 - name = "windows-core" 1259 - version = "0.62.2" 1260 - source = "registry+https://github.com/rust-lang/crates.io-index" 1261 - checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" 1262 - dependencies = [ 1263 - "windows-implement", 1264 - "windows-interface", 1265 - "windows-link", 1266 - "windows-result", 1267 - "windows-strings", 1268 - ] 1269 - 1270 - [[package]] 1271 - name = "windows-implement" 1272 - version = "0.60.2" 1273 - source = "registry+https://github.com/rust-lang/crates.io-index" 1274 - checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" 1275 - dependencies = [ 1276 - "proc-macro2", 1277 - "quote", 1278 - "syn", 1279 - ] 1280 - 1281 - [[package]] 1282 - name = "windows-interface" 1283 - version = "0.59.3" 1284 - source = "registry+https://github.com/rust-lang/crates.io-index" 1285 - checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" 1286 - dependencies = [ 1287 - "proc-macro2", 1288 - "quote", 1289 - "syn", 1290 - ] 1291 - 1292 - [[package]] 1293 - name = "windows-link" 1294 - version = "0.2.1" 1295 - source = "registry+https://github.com/rust-lang/crates.io-index" 1296 - checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 1297 - 1298 - [[package]] 1299 - name = "windows-result" 1300 - version = "0.4.1" 1301 - source = "registry+https://github.com/rust-lang/crates.io-index" 1302 - checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 1303 - dependencies = [ 1304 - "windows-link", 1305 - ] 1306 - 1307 - [[package]] 1308 - name = "windows-strings" 1309 - version = "0.5.1" 1310 - source = "registry+https://github.com/rust-lang/crates.io-index" 1311 - checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 1312 - dependencies = [ 1313 - "windows-link", 1314 - ] 1315 - 1316 - [[package]] 1317 - name = "windows-sys" 1318 - version = "0.60.2" 1319 - source = "registry+https://github.com/rust-lang/crates.io-index" 1320 - checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 1321 - dependencies = [ 1322 - "windows-targets", 1323 - ] 1324 - 1325 - [[package]] 1326 - name = "windows-sys" 1327 - version = "0.61.2" 1328 - source = "registry+https://github.com/rust-lang/crates.io-index" 1329 - checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 1330 - dependencies = [ 1331 - "windows-link", 1332 - ] 1333 - 1334 - [[package]] 1335 - name = "windows-targets" 1336 - version = "0.53.5" 1337 - source = "registry+https://github.com/rust-lang/crates.io-index" 1338 - checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 1339 - dependencies = [ 1340 - "windows-link", 1341 - "windows_aarch64_gnullvm", 1342 - "windows_aarch64_msvc", 1343 - "windows_i686_gnu", 1344 - "windows_i686_gnullvm", 1345 - "windows_i686_msvc", 1346 - "windows_x86_64_gnu", 1347 - "windows_x86_64_gnullvm", 1348 - "windows_x86_64_msvc", 1349 - ] 1350 - 1351 - [[package]] 1352 - name = "windows_aarch64_gnullvm" 1353 - version = "0.53.1" 1354 - source = "registry+https://github.com/rust-lang/crates.io-index" 1355 - checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 1356 - 1357 - [[package]] 1358 - name = "windows_aarch64_msvc" 1359 - version = "0.53.1" 1360 - source = "registry+https://github.com/rust-lang/crates.io-index" 1361 - checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 1362 - 1363 - [[package]] 1364 - name = "windows_i686_gnu" 1365 - version = "0.53.1" 1366 - source = "registry+https://github.com/rust-lang/crates.io-index" 1367 - checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 1368 - 1369 - [[package]] 1370 - name = "windows_i686_gnullvm" 1371 - version = "0.53.1" 1372 - source = "registry+https://github.com/rust-lang/crates.io-index" 1373 - checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 1374 - 1375 - [[package]] 1376 - name = "windows_i686_msvc" 1377 - version = "0.53.1" 1378 - source = "registry+https://github.com/rust-lang/crates.io-index" 1379 - checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 1380 - 1381 - [[package]] 1382 - name = "windows_x86_64_gnu" 1383 - version = "0.53.1" 1384 - source = "registry+https://github.com/rust-lang/crates.io-index" 1385 - checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 1386 - 1387 - [[package]] 1388 - name = "windows_x86_64_gnullvm" 1389 - version = "0.53.1" 1390 - source = "registry+https://github.com/rust-lang/crates.io-index" 1391 - checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 1392 - 1393 - [[package]] 1394 - name = "windows_x86_64_msvc" 1395 - version = "0.53.1" 1396 - source = "registry+https://github.com/rust-lang/crates.io-index" 1397 - checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 1398 - 1399 - [[package]] 1400 - name = "wit-bindgen" 1401 - version = "0.46.0" 1402 - source = "registry+https://github.com/rust-lang/crates.io-index" 1403 - checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 1404 - 1405 - [[package]] 1406 - name = "writeable" 1407 - version = "0.6.2" 1408 - source = "registry+https://github.com/rust-lang/crates.io-index" 1409 - checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 1410 - 1411 - [[package]] 1412 - name = "yoke" 1413 - version = "0.8.1" 1414 - source = "registry+https://github.com/rust-lang/crates.io-index" 1415 - checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" 1416 - dependencies = [ 1417 - "stable_deref_trait", 1418 - "yoke-derive", 1419 - "zerofrom", 1420 - ] 1421 - 1422 - [[package]] 1423 - name = "yoke-derive" 1424 - version = "0.8.1" 1425 - source = "registry+https://github.com/rust-lang/crates.io-index" 1426 - checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" 1427 - dependencies = [ 1428 - "proc-macro2", 1429 - "quote", 1430 - "syn", 1431 - "synstructure", 1432 - ] 1433 - 1434 - [[package]] 1435 - name = "zerofrom" 1436 - version = "0.1.6" 1437 - source = "registry+https://github.com/rust-lang/crates.io-index" 1438 - checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 1439 - dependencies = [ 1440 - "zerofrom-derive", 1441 - ] 1442 - 1443 - [[package]] 1444 - name = "zerofrom-derive" 1445 - version = "0.1.6" 1446 - source = "registry+https://github.com/rust-lang/crates.io-index" 1447 - checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 1448 - dependencies = [ 1449 - "proc-macro2", 1450 - "quote", 1451 - "syn", 1452 - "synstructure", 1453 - ] 1454 - 1455 - [[package]] 1456 - name = "zerotrie" 1457 - version = "0.2.3" 1458 - source = "registry+https://github.com/rust-lang/crates.io-index" 1459 - checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" 1460 - dependencies = [ 1461 - "displaydoc", 1462 - "yoke", 1463 - "zerofrom", 1464 - ] 1465 - 1466 - [[package]] 1467 - name = "zerovec" 1468 - version = "0.11.5" 1469 - source = "registry+https://github.com/rust-lang/crates.io-index" 1470 - checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" 1471 - dependencies = [ 1472 - "yoke", 1473 - "zerofrom", 1474 - "zerovec-derive", 1475 - ] 1476 - 1477 - [[package]] 1478 - name = "zerovec-derive" 1479 - version = "0.11.2" 1480 - source = "registry+https://github.com/rust-lang/crates.io-index" 1481 - checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" 1482 - dependencies = [ 1483 - "proc-macro2", 1484 - "quote", 1485 - "syn", 1486 - ]
-15
server/Cargo.toml
··· 1 - [package] 2 - name = "mothball-server" 3 - version = "0.1.0" 4 - edition = "2021" 5 - 6 - [dependencies] 7 - axum = "0.8" 8 - juniper = "0.17" 9 - juniper_axum = "0.3" 10 - serde = { version = "1.0", features = ["derive"] } 11 - serde_json = "1.0" 12 - tokio = { version = "1.0", features = ["full"] } 13 - dotenv = "0.15" 14 - chrono = "0.4" 15 - uuid = { version = "1.0", features = ["v4"] }
-35
server/Dockerfile
··· 1 - # Dockerfile for Mothball GraphQL Server 2 - # Multi-stage build to keep the final image small 3 - 4 - # Stage 1: Build the Rust application 5 - FROM rust:1.60-slim as builder 6 - 7 - WORKDIR /app 8 - 9 - # Copy the entire project 10 - COPY . . 11 - 12 - # Build the application in release mode 13 - RUN cargo build --release 14 - 15 - # Stage 2: Create the final lightweight image 16 - FROM debian:bullseye-slim 17 - 18 - # Install only the essential dependencies 19 - RUN apt-get update && \ 20 - apt-get install -y ca-certificates && \ 21 - rm -rf /var/lib/apt/lists/* 22 - 23 - WORKDIR /app 24 - 25 - # Copy the compiled binary from the builder stage 26 - COPY --from=builder /app/target/release/mothball-server . 27 - 28 - # Copy environment variables and static files 29 - COPY .env . 30 - 31 - # Expose the port the app runs on 32 - EXPOSE 8080 33 - 34 - # Command to run the application 35 - CMD ["./mothball-server"]
-23
server/fly.toml
··· 1 - # fly.toml app configuration 2 - # See https://fly.io/docs/reference/configuration/ for information about how to use this file. 3 - 4 - app = "mothball-server" 5 - primary_region = "iad" 6 - 7 - [build] 8 - dockerfile = "Dockerfile" 9 - 10 - [env] 11 - PRIMARY_REGION = "iad" 12 - 13 - [http_service] 14 - internal_port = 8080 15 - force_https = true 16 - auto_stop_machines = true 17 - auto_start_machines = true 18 - min_machines_running = 1 19 - 20 - [[vm]] 21 - cpu_kind = "shared" 22 - cpus = 1 23 - memory_mb = 1024
-58
server/graphql/useInventoryQuery.json
··· 1 - { 2 - "data": { 3 - "inventory": [ 4 - { 5 - "id": "ikea-desk", 6 - "title": "Large IKEA Desk - Spacious Workspace", 7 - "cost": "20.00", 8 - "images": [ 9 - "https://www.ikea.com/us/en/images/products/linnmon-adils-desk-black-brown__0974302_pe812345_s5.jpg?f=xl" 10 - ], 11 - "description": "Specifications:\n\n- Dimensions: 79\" long tabletop\n- Color: Black-brown\n- Model: LINNMON with ADILS legs\n- Condition: Used, good overall state\n\nThis versatile desk has been a reliable workspace for multiple years. Ideal for various activities including:\n\n- Computer setup\n- Crafting\n- Project work\n- Organizational tasks\n\nSlight cosmetic wear, minor surface imperfections.\n\nPricing:\n\n- Retail replacement cost: Approximately $100\n- Selling price: $30\n\nFlexible payment options available.", 12 - "location": "Portland, OR", 13 - "condition": "Used - Good", 14 - "category": "Furniture", 15 - "posted_at": "2024-01-15" 16 - }, 17 - { 18 - "id": "orbi-router", 19 - "title": "Orbi Router", 20 - "cost": "0", 21 - "images": ["https://www.netgear.com/support/cloudimage/1/11/123573"], 22 - "description": "This is an orbi wireless router. Normally it comes with satellites but\nthis one does not.", 23 - "location": "Portland, OR", 24 - "condition": "Used - Good", 25 - "category": "Electronics", 26 - "posted_at": "2024-01-18" 27 - }, 28 - { 29 - "id": "arris-router", 30 - "title": "Arris Router", 31 - "cost": "10.00", 32 - "images": [ 33 - "https://m.media-amazon.com/images/I/71gmmM9G8CL._AC_SY879_.jpg" 34 - ], 35 - "description": "This is an Arris SURFBoard router.", 36 - "location": "Portland, OR", 37 - "condition": "Used - Good", 38 - "category": "Electronics", 39 - "posted_at": "2024-01-20" 40 - }, 41 - { 42 - "id": "dell-soundbar", 43 - "title": "Dell Stereo SoundBar - AC511M", 44 - "cost": "10.00", 45 - "images": [ 46 - "https://m.media-amazon.com/images/I/71MiidZgcfL._AC_SX679_.jpg", 47 - "https://m.media-amazon.com/images/I/71VKkGixWWL._AC_SX679_.jpg" 48 - ], 49 - "description": "- Until you hear it you'll hardly notice it's there Dell Stereo Soundbar can give you the sound you want without big speakers and Long cables.Total usb ports:1\n- USB powered the Dell Stereo Soundbar is simplicity itself Just Plug in to an available USB port on your monitor or laptop No extra software Installation No power cord No Batteries required\n- An included Soundbar mount offers Easy attachment to the monitor allowing you to enjoy clear Stereo sound without losing desk space", 50 - "location": "Portland, OR", 51 - "condition": "Used - Good", 52 - "category": "Electronics", 53 - "posted_at": "2024-01-22" 54 - } 55 - ] 56 - }, 57 - "errors": [] 58 - }
-167
server/graphql/useMessagesQuery.json
··· 1 - { 2 - "data": { 3 - "chats": [ 4 - { 5 - "id": "chat:1", 6 - "sender": "John Doe", 7 - "avatar": "JD", 8 - "unread": true, 9 - "messages": [ 10 - { 11 - "id": "chat:1:1", 12 - "sender": "them", 13 - "text": "Hi, I'm interested in your vintage lamp. Is it still available?", 14 - "time": "2:30 PM" 15 - }, 16 - { 17 - "id": "chat:1:2", 18 - "sender": "me", 19 - "text": "Yes, the vintage lamp is still available. Would you like more details about it?", 20 - "time": "2:31 PM" 21 - }, 22 - { 23 - "id": "chat:1:3", 24 - "sender": "them", 25 - "text": "Absolutely! How old is it and what's the condition?", 26 - "time": "2:35 PM" 27 - }, 28 - { 29 - "id": "chat:1:4", 30 - "sender": "me", 31 - "text": "The lamp is from the 1960s and in excellent condition. The base has a small chip but the shade is perfect.", 32 - "time": "2:38 PM" 33 - } 34 - ] 35 - }, 36 - { 37 - "id": "chat:2", 38 - "sender": "Sarah Johnson", 39 - "avatar": "SJ", 40 - "unread": true, 41 - "messages": [ 42 - { 43 - "id": "chat:2:1", 44 - "sender": "them", 45 - "text": "Can we negotiate the price on your records collection?", 46 - "time": "1:15 PM" 47 - }, 48 - { 49 - "id": "chat:2:2", 50 - "sender": "me", 51 - "text": "Of course! What price were you thinking?", 52 - "time": "1:17 PM" 53 - }, 54 - { 55 - "id": "chat:2:3", 56 - "sender": "them", 57 - "text": "I was thinking around $150 for the whole collection. Is that doable?", 58 - "time": "1:20 PM" 59 - }, 60 - { 61 - "id": "chat:2:4", 62 - "sender": "me", 63 - "text": "I could do $175, but that's my final offer. The records are in near mint condition.", 64 - "time": "1:22 PM" 65 - } 66 - ] 67 - }, 68 - { 69 - "id": "chat:3", 70 - "sender": "Michael Brown", 71 - "avatar": "MB", 72 - "unread": false, 73 - "messages": [ 74 - { 75 - "id": "chat:3:1", 76 - "sender": "them", 77 - "text": "Thanks for the vintage camera! Can we arrange pickup tomorrow?", 78 - "time": "Yesterday" 79 - }, 80 - { 81 - "id": "chat:3:2", 82 - "sender": "me", 83 - "text": "That sounds great! Would 2 PM work for you?", 84 - "time": "Yesterday" 85 - }, 86 - { 87 - "id": "chat:3:3", 88 - "sender": "them", 89 - "text": "Yes, 2 PM is perfect. What's your address?", 90 - "time": "Yesterday" 91 - }, 92 - { 93 - "id": "chat:3:4", 94 - "sender": "me", 95 - "text": "I'm at 123 Main Street, Apt 4B. Just ring the buzzer for Brown.", 96 - "time": "Yesterday" 97 - } 98 - ] 99 - }, 100 - { 101 - "id": "chat:4", 102 - "sender": "Alex Wilson", 103 - "avatar": "AW", 104 - "unread": false, 105 - "messages": [ 106 - { 107 - "id": "chat:4:1", 108 - "sender": "them", 109 - "text": "I'm looking for similar items like your sound system.", 110 - "time": "Monday" 111 - }, 112 - { 113 - "id": "chat:4:2", 114 - "sender": "me", 115 - "text": "What specifically are you looking for? I might know where to find similar items.", 116 - "time": "Monday" 117 - }, 118 - { 119 - "id": "chat:4:3", 120 - "sender": "them", 121 - "text": "Vinyl record players and mid-century modern speakers.", 122 - "time": "Monday" 123 - }, 124 - { 125 - "id": "chat:4:4", 126 - "sender": "me", 127 - "text": "I know a great shop downtown that specializes in exactly that. Want me to text you the address?", 128 - "time": "Monday" 129 - } 130 - ] 131 - }, 132 - { 133 - "id": "chat:5", 134 - "sender": "Emily Davis", 135 - "avatar": "ED", 136 - "unread": false, 137 - "messages": [ 138 - { 139 - "id": "chat:5:1", 140 - "sender": "them", 141 - "text": "Can you provide more details about your furniture pieces?", 142 - "time": "Last week" 143 - }, 144 - { 145 - "id": "chat:5:2", 146 - "sender": "me", 147 - "text": "Sure! The dining table is solid oak with a glass top, and the chairs are original mid-century design.", 148 - "time": "Last week" 149 - }, 150 - { 151 - "id": "chat:5:3", 152 - "sender": "them", 153 - "text": "Are the chairs comfortable? I have back problems so seating is important to me.", 154 - "time": "Last week" 155 - }, 156 - { 157 - "id": "chat:5:4", 158 - "sender": "me", 159 - "text": "Yes, they're very comfortable! The cushions are original and still in great shape. I can send you photos if you'd like.", 160 - "time": "Last week" 161 - } 162 - ] 163 - } 164 - ] 165 - }, 166 - "errors": [] 167 - }
-7
server/graphql/useProfileQuery.json
··· 1 - { 2 - "data": { 3 - }, 4 - "errors": [ 5 - {"description":"This query should not make it to the server!"} 6 - ] 7 - }
-206
server/src/main.rs
··· 1 - use axum::{ 2 - response::Html, 3 - routing::{get, on, MethodFilter}, 4 - Extension, Router, 5 - }; 6 - use dotenv::dotenv; 7 - use juniper::{graphql_object, EmptyMutation, EmptySubscription, RootNode}; 8 - use juniper_axum::{graphiql, graphql}; 9 - use serde::Deserialize; 10 - use std::env; 11 - use std::net::SocketAddr; 12 - use std::sync::Arc; 13 - use uuid::Uuid; 14 - 15 - // Define our GraphQL schema types 16 - #[derive(juniper::GraphQLObject, Deserialize, Debug)] 17 - struct Me { 18 - id: String, 19 - } 20 - 21 - #[derive(juniper::GraphQLObject, Deserialize, Debug)] 22 - struct ProfileViewDetailed { 23 - id: String, 24 - did: String, 25 - handle: String, 26 - display_name: Option<String>, 27 - description: Option<String>, 28 - pronouns: Option<String>, 29 - website: Option<String>, 30 - avatar: Option<String>, 31 - banner: Option<String>, 32 - followers_count: Option<i32>, 33 - follows_count: Option<i32>, 34 - posts_count: Option<i32>, 35 - } 36 - 37 - #[derive(juniper::GraphQLObject, Deserialize, Debug)] 38 - struct InventoryItem { 39 - id: String, 40 - title: String, 41 - cost: String, 42 - images: Vec<String>, 43 - description: String, 44 - location: Option<String>, 45 - condition: Option<String>, 46 - category: Option<String>, 47 - posted_at: String, 48 - } 49 - 50 - #[derive(juniper::GraphQLEnum, Deserialize, Debug)] 51 - enum Sender { 52 - #[graphql(name = "them")] 53 - #[serde(alias = "them")] 54 - Them, 55 - 56 - #[graphql(name = "me")] 57 - #[serde(alias = "me")] 58 - Me, 59 - } 60 - 61 - #[derive(juniper::GraphQLObject, Deserialize, Debug)] 62 - struct Message { 63 - id: String, 64 - sender: Sender, 65 - text: String, 66 - time: String, 67 - } 68 - 69 - #[derive(juniper::GraphQLObject, Deserialize, Debug)] 70 - struct Chat { 71 - id: String, 72 - unread: bool, 73 - sender: String, 74 - avatar: Option<String>, 75 - messages: Vec<Message>, 76 - } 77 - 78 - /** 79 - * Inventory Placeholder Query 80 - */ 81 - 82 - const USE_INVENTORY_QUERY: &'static str = include_str!("../graphql/useInventoryQuery.json"); 83 - 84 - #[derive(Deserialize, Debug)] 85 - pub struct InventoryQueryRoot { 86 - inventory: Vec<InventoryItem>, 87 - } 88 - 89 - #[derive(Deserialize, Debug)] 90 - pub struct InventoryQuery { 91 - data: InventoryQueryRoot, 92 - } 93 - 94 - /** 95 - * Chat Placeholder Query 96 - */ 97 - 98 - const USE_CHAT_QUERY: &'static str = include_str!("../graphql/useMessagesQuery.json"); 99 - 100 - #[derive(Deserialize, Debug)] 101 - pub struct ChatQueryRoot { 102 - chats: Vec<Chat>, 103 - } 104 - 105 - #[derive(Deserialize, Debug)] 106 - pub struct ChatQuery { 107 - data: ChatQueryRoot, 108 - } 109 - 110 - /** 111 - * Schema root 112 - */ 113 - 114 - // Define our GraphQL schema queries 115 - #[derive(Clone, Copy, Debug)] 116 - pub struct Query; 117 - 118 - #[graphql_object] 119 - impl Query { 120 - async fn me(&self) -> Option<Me> { 121 - Some(Me { 122 - id: Uuid::new_v4().to_string(), 123 - }) 124 - } 125 - 126 - async fn profile_view_detailed(&self) -> Option<ProfileViewDetailed> { 127 - Some(ProfileViewDetailed { 128 - id: Uuid::new_v4().to_string(), 129 - did: "did:example:123456789abcdefghi".to_string(), 130 - handle: "testuser".to_string(), 131 - display_name: Some("Test User".to_string()), 132 - description: Some("Hello, I'm a test user!".to_string()), 133 - pronouns: Some("they/them".to_string()), 134 - website: Some("https://example.com".to_string()), 135 - avatar: Some("https://example.com/avatar.jpg".to_string()), 136 - banner: Some("https://example.com/banner.jpg".to_string()), 137 - followers_count: Some(42), 138 - follows_count: Some(15), 139 - posts_count: Some(7), 140 - }) 141 - } 142 - 143 - async fn inventory(&self) -> Vec<InventoryItem> { 144 - let a = serde_json::from_str(USE_INVENTORY_QUERY) 145 - .map(|q: InventoryQuery| q.data.inventory) 146 - .unwrap_or(vec![]); 147 - dbg!(&serde_json::from_str::<InventoryQuery>(USE_INVENTORY_QUERY).err()); 148 - return a; 149 - } 150 - 151 - async fn chats(&self) -> Vec<Chat> { 152 - let a = serde_json::from_str(USE_CHAT_QUERY) 153 - .map(|q: ChatQuery| q.data.chats) 154 - .unwrap_or(vec![]); 155 - dbg!(&serde_json::from_str::<ChatQuery>(USE_CHAT_QUERY).err()); 156 - return a; 157 - } 158 - } 159 - 160 - pub type Schema = RootNode<Query, EmptyMutation, EmptySubscription>; 161 - 162 - async fn homepage() -> Html<String> { 163 - Html( 164 - "<html><h1>Mothball GraphQL API</h1>\ 165 - <div>Visit <a href=\"/graphiql\">GraphiQL</a> for the web-based IDE</div>\ 166 - <div>Access the API directly at <a href=\"/graphql\">/graphql</a></div>\ 167 - </html>" 168 - .to_string(), 169 - ) 170 - } 171 - 172 - #[tokio::main] 173 - async fn main() { 174 - dotenv().ok(); 175 - 176 - // Load environment variables 177 - let host = env::var("HOST").unwrap_or_else(|_| "0.0.0.0".to_string()); 178 - let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string()); 179 - 180 - println!("Starting Mothball GraphQL server on {}:{}", host, port); 181 - 182 - let schema = Schema::new(Query, EmptyMutation::new(), EmptySubscription::new()); 183 - 184 - let app = Router::new() 185 - .route( 186 - "/graphql", 187 - on( 188 - MethodFilter::GET.or(MethodFilter::POST), 189 - graphql::<Arc<Schema>>, 190 - ), 191 - ) 192 - .route("/graphiql", get(graphiql("/graphql", "/subscriptions"))) 193 - .route("/", get(homepage)) 194 - .layer(Extension(Arc::new(schema))); 195 - 196 - let addr = format!("{}:{}", host, port) 197 - .parse::<SocketAddr>() 198 - .expect("Invalid socket address"); 199 - 200 - let listener = tokio::net::TcpListener::bind(addr) 201 - .await 202 - .unwrap_or_else(|e| panic!("failed to listen on {addr}: {e}")); 203 - axum::serve(listener, app) 204 - .await 205 - .unwrap_or_else(|e| panic!("failed to run `axum::serve`: {e}")); 206 - }
-13
tests/conftest.py
··· 1 - """Test configuration and fixtures for the schema generation tests.""" 2 - 3 - import os 4 - import sys 5 - from pathlib import Path 6 - 7 - # Add the project root to the Python path so we can import modules 8 - sys.path.insert(0, str(Path(__file__).parent.parent)) 9 - 10 - 11 - def pytest_configure(config): 12 - """Add custom markers if needed.""" 13 - pass
-115
tests/test_schema_generation.py
··· 1 - """Test for schema generation consistency.""" 2 - 3 - import os 4 - import tempfile 5 - from pathlib import Path 6 - from typing import List 7 - 8 - from schema.generate_lexicon_schema import generate_definitions, main 9 - 10 - # Constant for the expected output file 11 - EXPECTED_OUTPUT_FILE = "schema/schema-generated.graphql" 12 - 13 - 14 - def test_schema_generation_consistency(): 15 - """ 16 - Test that running the generate_lexicon_schema.py script produces consistent output. 17 - This test ensures that the generated schema doesn't change unexpectedly. 18 - """ 19 - # Expected lexicon IDs from the command line 20 - lexicon_ids = ["app.bsky.actor.getProfile", "com.atproto.server.getSession"] 21 - 22 - # Generate the expected output using the function directly 23 - generated_content = "\n\n".join(generate_definitions(lexicon_ids)) 24 - 25 - # Read the expected file if it exists 26 - expected_file_path = Path(EXPECTED_OUTPUT_FILE) 27 - if expected_file_path.exists(): 28 - with open(expected_file_path, "r") as f: 29 - expected_content = f.read() 30 - 31 - # Compare the generated content with the expected content 32 - assert generated_content == expected_content, ( 33 - "Generated schema content does not match the expected file. " 34 - "This could mean the schema has changed or the test needs to be updated." 35 - ) 36 - 37 - else: 38 - # If the expected file doesn't exist, create it with the current output 39 - with open(expected_file_path, "w") as f: 40 - f.write(generated_content) 41 - print(f"Created new expected output file: {expected_file_path}") 42 - 43 - 44 - def test_main_function_output(): 45 - """ 46 - Test the main function by running it with the specified lexicon IDs 47 - and verifying the output is consistent. 48 - """ 49 - # Expected lexicon IDs from the command line 50 - lexicon_ids = ["app.bsky.actor.getProfile", "com.atproto.server.getSession"] 51 - 52 - # Create a temporary file for testing 53 - with tempfile.NamedTemporaryFile( 54 - mode="w", suffix=".graphql", delete=False 55 - ) as tmp_file: 56 - tmp_path = tmp_file.name 57 - 58 - try: 59 - # Run the main function with the lexicon IDs and output to temp file 60 - main(lexicon_ids=lexicon_ids, output=tmp_path, append_schema=None) 61 - 62 - # Read the generated content 63 - with open(tmp_path, "r") as f: 64 - generated_content = f.read() 65 - 66 - # Read the expected file if it exists 67 - expected_file_path = Path(EXPECTED_OUTPUT_FILE) 68 - if expected_file_path.exists(): 69 - with open(expected_file_path, "r") as f: 70 - expected_content = f.read() 71 - 72 - # Compare the generated content with the expected content 73 - assert generated_content == expected_content, ( 74 - "Generated schema content does not match the expected file. " 75 - "This could mean the schema has changed or the test needs to be updated." 76 - ) 77 - else: 78 - # If the expected file doesn't exist, create it with the current output 79 - with open(expected_file_path, "w") as f: 80 - f.write(generated_content) 81 - print(f"Created new expected output file: {expected_file_path}") 82 - 83 - finally: 84 - # Clean up the temporary file 85 - if os.path.exists(tmp_path): 86 - os.unlink(tmp_path) 87 - 88 - 89 - def test_generate_definitions_function(): 90 - """ 91 - Test the generate_definitions function directly to ensure it produces consistent output. 92 - """ 93 - # Expected lexicon IDs from the command line 94 - lexicon_ids = ["app.bsky.actor.getProfile", "com.atproto.server.getSession"] 95 - 96 - # Generate definitions using the function 97 - generated_chunks = generate_definitions(lexicon_ids) 98 - generated_content = "\n\n".join(generated_chunks) 99 - 100 - # Read the expected file if it exists 101 - expected_file_path = Path(EXPECTED_OUTPUT_FILE) 102 - if expected_file_path.exists(): 103 - with open(expected_file_path, "r") as f: 104 - expected_content = f.read() 105 - 106 - # Compare the generated content with the expected content 107 - assert generated_content == expected_content, ( 108 - "Generated schema content does not match the expected file. " 109 - "This could mean the schema has changed or the test needs to be updated." 110 - ) 111 - else: 112 - # If the expected file doesn't exist, create it with the current output 113 - with open(expected_file_path, "w") as f: 114 - f.write(generated_content) 115 - print(f"Created new expected output file: {expected_file_path}")