Compare changes

Choose any two refs to compare.

Changed files
+4758 -1436
.claude
crates
jacquard
jacquard-api
src
app_bsky
actor
bookmark
feed
graph
labeler
notification
unspecced
video
chat_bsky
com_atproto
tools_ozone
jacquard-common
jacquard-derive
jacquard-lexicon
nix
modules
-13
.claude/settings.local.json
··· 1 - { 2 - "permissions": { 3 - "allow": [ 4 - "WebSearch", 5 - "WebFetch(domain:atproto.com)", 6 - "WebFetch(domain:github.com)", 7 - "WebFetch(domain:raw.githubusercontent.com)", 8 - "WebFetch(domain:docs.rs)" 9 - ], 10 - "deny": [], 11 - "ask": [] 12 - } 13 - }
-151
CLAUDE.md
··· 1 - # CLAUDE.md 2 - 3 - This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 - 5 - ## Project Overview 6 - 7 - Jacquard is a suite of Rust crates for the AT Protocol (atproto/Bluesky). The project emphasizes spec-compliant, validated, performant baseline types with minimal boilerplate. Key design goals: 8 - 9 - - Validated AT Protocol types including typed at:// URIs 10 - - Custom lexicon extension support 11 - - Lexicon `Value` type for working with unknown atproto data (dag-cbor or json) 12 - - Using as much or as little of the crates as needed 13 - 14 - ## Workspace Structure 15 - 16 - This is a Cargo workspace with several crates: 17 - 18 - - **jacquard**: Main library crate with XRPC client and public API surface (re-exports jacquard-api and jacquard-common) 19 - - **jacquard-common**: Core AT Protocol types (DIDs, handles, at-URIs, NSIDs, TIDs, CIDs, etc.) and the `CowStr` type for efficient string handling 20 - - **jacquard-lexicon**: Lexicon parsing and Rust code generation from lexicon schemas 21 - - **jacquard-api**: Generated API bindings from lexicon schemas (implementation detail, not directly used by consumers) 22 - - **jacquard-derive**: Attribute macros (`#[lexicon]`, `#[open_union]`) for lexicon structures 23 - 24 - ## Development Commands 25 - 26 - ### Using Nix (preferred) 27 - ```bash 28 - # Enter dev shell 29 - nix develop 30 - 31 - # Build 32 - nix build 33 - 34 - # Run 35 - nix develop -c cargo run 36 - ``` 37 - 38 - ### Using Cargo/Just 39 - ```bash 40 - # Build 41 - cargo build 42 - 43 - # Run tests 44 - cargo test 45 - 46 - # Run specific test 47 - cargo test <test_name> 48 - 49 - # Run specific package tests 50 - cargo test -p <package_name> 51 - 52 - # Run 53 - cargo run 54 - 55 - # Auto-recompile and run 56 - just watch [ARGS] 57 - 58 - # Format and lint all 59 - just pre-commit-all 60 - 61 - # Generate API bindings from lexicon schemas 62 - cargo run -p jacquard-lexicon --bin jacquard-codegen -- -i <input_dir> -o <output_dir> [-r <root_module>] 63 - # Example: 64 - cargo run -p jacquard-lexicon --bin jacquard-codegen -- -i crates/jacquard-lexicon/tests/fixtures/lexicons/atproto/lexicons -o crates/jacquard-api/src -r crate 65 - ``` 66 - 67 - ## String Type Pattern 68 - 69 - The codebase uses a consistent pattern for validated string types. Each type should have: 70 - 71 - ### Constructors 72 - - `new()`: Construct from a string slice with appropriate lifetime (borrows) 73 - - `new_owned()`: Construct from `impl AsRef<str>`, taking ownership 74 - - `new_static()`: Construct from `&'static str` using `SmolStr`/`CowStr`'s static constructor (no allocation) 75 - - `raw()`: Same as `new()` but panics instead of returning `Result` 76 - - `unchecked()`: Same as `new()` but doesn't validate (marked `unsafe`) 77 - - `as_str()`: Return string slice 78 - 79 - ### Traits 80 - All string types should implement: 81 - - `Serialize` + `Deserialize` (custom impl for latter, sometimes for former) 82 - - `FromStr`, `Display` 83 - - `Debug`, `PartialEq`, `Eq`, `Hash`, `Clone` 84 - - `From<T> for String`, `CowStr`, `SmolStr` 85 - - `From<String>`, `From<CowStr>`, `From<SmolStr>`, or `TryFrom` if likely to fail 86 - - `AsRef<str>` 87 - - `Deref` with `Target = str` (usually) 88 - 89 - ### Implementation Details 90 - - Use `#[repr(transparent)]` when possible (exception: at-uri type and components) 91 - - Use `SmolStr` directly as inner type if most instances will be under 24 bytes 92 - - Use `CowStr` for longer strings to allow borrowing from input 93 - - Implement `IntoStatic` trait to take ownership of string types 94 - 95 - ## Code Style 96 - 97 - - Avoid comments for self-documenting code 98 - - Comments should not detail fixes when refactoring 99 - - Professional writing within source code and comments only 100 - - Prioritize long-term maintainability over implementation speed 101 - 102 - ## Testing 103 - 104 - - Write test cases for all critical code 105 - - Tests can be run per-package or workspace-wide 106 - - Use `cargo test <name>` to run specific tests 107 - - Current test coverage: 89 tests in jacquard-common 108 - 109 - ## Lexicon Code Generation 110 - 111 - The `jacquard-codegen` binary generates Rust types from AT Protocol Lexicon schemas: 112 - 113 - - Generates structs with `#[lexicon]` attribute for forward compatibility (captures unknown fields in `extra_data`) 114 - - Generates enums with `#[open_union]` attribute for handling unknown variants (unless marked `closed` in lexicon) 115 - - Resolves local refs (e.g., `#image` becomes `Image<'a>`) 116 - - Extracts doc comments from lexicon `description` fields 117 - - Adds header comments with `@generated` marker and lexicon NSID 118 - - Handles XRPC queries, procedures, subscriptions, and errors 119 - - Generates proper module tree with Rust 2018 style 120 - - **XrpcRequest trait**: Implemented directly on params/input structs (not marker types), with GATs for Output<'de> and Err<'de> 121 - - **IntoStatic trait**: All generated types implement `IntoStatic` to convert borrowed types to owned ('static) variants 122 - - **Collection trait**: Implemented on record types directly, with const NSID 123 - 124 - ## Current State & Next Steps 125 - 126 - ### Completed 127 - - โœ… Comprehensive validation tests for all core string types (handle, DID, NSID, TID, record key, AT-URI, datetime, language, identifier) 128 - - โœ… Validated implementations against AT Protocol specs and TypeScript reference implementation 129 - - โœ… String type interface standardization (Language now has `new_static()`, Datetime has full conversion traits) 130 - - โœ… Data serialization: Full serialize/deserialize for `Data<'_>`, `Array`, `Object` with format-specific handling (JSON vs CBOR) 131 - - โœ… CidLink wrapper type with automatic `{"$link": "cid"}` serialization in JSON 132 - - โœ… Integration test with real Bluesky thread data validates round-trip correctness 133 - - โœ… Lexicon code generation with forward compatibility and proper lifetime handling 134 - - โœ… IntoStatic implementations for all generated types (structs, enums, unions) 135 - - โœ… XrpcRequest trait with GATs, implemented on params/input types directly 136 - - โœ… HttpClient and XrpcClient traits with generic send_xrpc implementation 137 - - โœ… Response wrapper with parse() (borrowed) and into_output() (owned) methods 138 - - โœ… Structured error types (ClientError, TransportError, EncodeError, DecodeError, HttpError, AuthError) 139 - 140 - ### Next Steps 141 - 1. **Concrete HttpClient Implementation**: Implement HttpClient for reqwest::Client and potentially other HTTP clients 142 - 2. **Error Handling Improvements**: Add XRPC error parsing, better HTTP status code handling, structured error responses 143 - 3. **Authentication**: Session management, token refresh, DPoP support 144 - 4. **Body Encoding**: Support for non-JSON encodings (CBOR, multipart, etc.) in procedures 145 - 5. **Lexicon Resolution**: Fetch lexicons from web sources (atproto authorities, git repositories) and parse into corpus 146 - 6. **Custom Lexicon Support**: Allow users to plug in their own generated lexicons alongside jacquard-api types in the client/server layer 147 - 7. **Public API**: Design the main API surface in `jacquard` that re-exports and wraps generated types 148 - 8. **DID Document Support**: Parsing, validation, and resolution of DID documents 149 - 9. **OAuth Implementation**: OAuth flow support for authentication 150 - 10. **Examples & Documentation**: Create examples and improve documentation 151 - 11. **Testing**: Comprehensive tests for generated code and round-trip serialization
+62 -2
Cargo.lock
··· 187 187 ] 188 188 189 189 [[package]] 190 + name = "bon" 191 + version = "3.7.2" 192 + source = "registry+https://github.com/rust-lang/crates.io-index" 193 + checksum = "c2529c31017402be841eb45892278a6c21a000c0a17643af326c73a73f83f0fb" 194 + dependencies = [ 195 + "bon-macros", 196 + "rustversion", 197 + ] 198 + 199 + [[package]] 200 + name = "bon-macros" 201 + version = "3.7.2" 202 + source = "registry+https://github.com/rust-lang/crates.io-index" 203 + checksum = "d82020dadcb845a345591863adb65d74fa8dc5c18a0b6d408470e13b7adc7005" 204 + dependencies = [ 205 + "darling", 206 + "ident_case", 207 + "prettyplease", 208 + "proc-macro2", 209 + "quote", 210 + "rustversion", 211 + "syn 2.0.106", 212 + ] 213 + 214 + [[package]] 190 215 name = "borsh" 191 216 version = "1.5.7" 192 217 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 589 614 checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" 590 615 dependencies = [ 591 616 "libc", 592 - "windows-sys 0.52.0", 617 + "windows-sys 0.60.2", 593 618 ] 594 619 595 620 [[package]] 621 + name = "fastrand" 622 + version = "2.3.0" 623 + source = "registry+https://github.com/rust-lang/crates.io-index" 624 + checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 625 + 626 + [[package]] 596 627 name = "find-msvc-tools" 597 628 version = "0.1.2" 598 629 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1115 1146 "http", 1116 1147 "jacquard-api", 1117 1148 "jacquard-common", 1149 + "jacquard-derive", 1118 1150 "miette", 1119 1151 "reqwest", 1120 1152 "serde", ··· 1122 1154 "serde_ipld_dagcbor", 1123 1155 "serde_json", 1124 1156 "thiserror 2.0.17", 1157 + "tokio", 1125 1158 ] 1126 1159 1127 1160 [[package]] 1128 1161 name = "jacquard-api" 1129 1162 version = "0.1.0" 1130 1163 dependencies = [ 1164 + "bon", 1131 1165 "bytes", 1132 1166 "jacquard-common", 1133 1167 "jacquard-derive", ··· 1197 1231 "serde_repr", 1198 1232 "serde_with", 1199 1233 "syn 2.0.106", 1234 + "tempfile", 1200 1235 "thiserror 2.0.17", 1201 1236 ] 1202 1237 ··· 1749 1784 "errno", 1750 1785 "libc", 1751 1786 "linux-raw-sys", 1752 - "windows-sys 0.52.0", 1787 + "windows-sys 0.60.2", 1753 1788 ] 1754 1789 1755 1790 [[package]] ··· 2138 2173 ] 2139 2174 2140 2175 [[package]] 2176 + name = "tempfile" 2177 + version = "3.23.0" 2178 + source = "registry+https://github.com/rust-lang/crates.io-index" 2179 + checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" 2180 + dependencies = [ 2181 + "fastrand", 2182 + "getrandom 0.3.3", 2183 + "once_cell", 2184 + "rustix", 2185 + "windows-sys 0.60.2", 2186 + ] 2187 + 2188 + [[package]] 2141 2189 name = "terminal_size" 2142 2190 version = "0.4.3" 2143 2191 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2267 2315 "pin-project-lite", 2268 2316 "slab", 2269 2317 "socket2", 2318 + "tokio-macros", 2270 2319 "windows-sys 0.59.0", 2320 + ] 2321 + 2322 + [[package]] 2323 + name = "tokio-macros" 2324 + version = "2.5.0" 2325 + source = "registry+https://github.com/rust-lang/crates.io-index" 2326 + checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 2327 + dependencies = [ 2328 + "proc-macro2", 2329 + "quote", 2330 + "syn 2.0.106", 2271 2331 ] 2272 2332 2273 2333 [[package]]
+34 -5
Cargo.toml
··· 8 8 version = "0.1.0" 9 9 authors = ["Orual <orual@nonbinary.computer>"] 10 10 repository = "https://tangled.org/@nonbinary.computer/jacquard" 11 - keywords = ["atproto", "at protocol", "bluesky", "api", "client"] 11 + keywords = ["atproto", "at", "bluesky", "api", "client"] 12 12 categories = ["api-bindings", "web-programming::http-client"] 13 13 readme = "README.md" 14 - documentation = "https://docs.rs/jacquard" 15 14 exclude = [".direnv"] 16 - 17 - 18 - description = "A simple Rust project using Nix" 15 + homepage = "https://tangled.org/@nonbinary.computer/jacquard" 16 + license-file = "LICENSE" 19 17 18 + description = "Simple and powerful AT Protocol client library for Rust" 20 19 21 20 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 22 21 23 22 [workspace.dependencies] 23 + # CLI 24 24 clap = { version = "4.5", features = ["derive"] } 25 + 26 + # Serialization 27 + serde = { version = "1.0", features = ["derive"] } 28 + serde_json = "1.0" 29 + serde_with = "3.14" 30 + serde_html_form = "0.2" 31 + serde_ipld_dagcbor = "0.6" 32 + serde_repr = "0.1" 33 + 34 + # Error handling 35 + miette = "7.6" 36 + thiserror = "2.0" 37 + 38 + # Data types 39 + bytes = "1.10" 40 + smol_str = { version = "0.3", features = ["serde"] } 41 + url = "2.5" 42 + 43 + # Proc macros 44 + proc-macro2 = "1.0" 45 + quote = "1.0" 46 + syn = "2.0" 47 + heck = "0.5" 48 + itertools = "0.14" 49 + prettyplease = "0.2" 50 + 51 + # HTTP 52 + http = "1.3" 53 + reqwest = { version = "0.12", default-features = false }
+369 -17
LICENSE
··· 1 - MIT License 1 + Mozilla Public License Version 2.0 2 + ================================== 3 + 4 + 1. Definitions 5 + -------------- 6 + 7 + 1.1. "Contributor" 8 + means each individual or legal entity that creates, contributes to 9 + the creation of, or owns Covered Software. 10 + 11 + 1.2. "Contributor Version" 12 + means the combination of the Contributions of others (if any) used 13 + by a Contributor and that particular Contributor's Contribution. 14 + 15 + 1.3. "Contribution" 16 + means Covered Software of a particular Contributor. 17 + 18 + 1.4. "Covered Software" 19 + means Source Code Form to which the initial Contributor has attached 20 + the notice in Exhibit A, the Executable Form of such Source Code 21 + Form, and Modifications of such Source Code Form, in each case 22 + including portions thereof. 23 + 24 + 1.5. "Incompatible With Secondary Licenses" 25 + means 26 + 27 + (a) that the initial Contributor has attached the notice described 28 + in Exhibit B to the Covered Software; or 29 + 30 + (b) that the Covered Software was made available under the terms of 31 + version 1.1 or earlier of the License, but not also under the 32 + terms of a Secondary License. 33 + 34 + 1.6. "Executable Form" 35 + means any form of the work other than Source Code Form. 36 + 37 + 1.7. "Larger Work" 38 + means a work that combines Covered Software with other material, in 39 + a separate file or files, that is not Covered Software. 40 + 41 + 1.8. "License" 42 + means this document. 43 + 44 + 1.9. "Licensable" 45 + means having the right to grant, to the maximum extent possible, 46 + whether at the time of the initial grant or subsequently, any and 47 + all of the rights conveyed by this License. 48 + 49 + 1.10. "Modifications" 50 + means any of the following: 51 + 52 + (a) any file in Source Code Form that results from an addition to, 53 + deletion from, or modification of the contents of Covered 54 + Software; or 55 + 56 + (b) any new file in Source Code Form that contains any Covered 57 + Software. 58 + 59 + 1.11. "Patent Claims" of a Contributor 60 + means any patent claim(s), including without limitation, method, 61 + process, and apparatus claims, in any patent Licensable by such 62 + Contributor that would be infringed, but for the grant of the 63 + License, by the making, using, selling, offering for sale, having 64 + made, import, or transfer of either its Contributions or its 65 + Contributor Version. 66 + 67 + 1.12. "Secondary License" 68 + means either the GNU General Public License, Version 2.0, the GNU 69 + Lesser General Public License, Version 2.1, the GNU Affero General 70 + Public License, Version 3.0, or any later versions of those 71 + licenses. 72 + 73 + 1.13. "Source Code Form" 74 + means the form of the work preferred for making modifications. 75 + 76 + 1.14. "You" (or "Your") 77 + means an individual or a legal entity exercising rights under this 78 + License. For legal entities, "You" includes any entity that 79 + controls, is controlled by, or is under common control with You. For 80 + purposes of this definition, "control" means (a) the power, direct 81 + or indirect, to cause the direction or management of such entity, 82 + whether by contract or otherwise, or (b) ownership of more than 83 + fifty percent (50%) of the outstanding shares or beneficial 84 + ownership of such entity. 85 + 86 + 2. License Grants and Conditions 87 + -------------------------------- 88 + 89 + 2.1. Grants 90 + 91 + Each Contributor hereby grants You a world-wide, royalty-free, 92 + non-exclusive license: 93 + 94 + (a) under intellectual property rights (other than patent or trademark) 95 + Licensable by such Contributor to use, reproduce, make available, 96 + modify, display, perform, distribute, and otherwise exploit its 97 + Contributions, either on an unmodified basis, with Modifications, or 98 + as part of a Larger Work; and 2 99 3 - Copyright (c) 2023 Orual 100 + (b) under Patent Claims of such Contributor to make, use, sell, offer 101 + for sale, have made, import, and otherwise transfer either its 102 + Contributions or its Contributor Version. 4 103 5 - Permission is hereby granted, free of charge, to any person obtaining a copy 6 - of this software and associated documentation files (the "Software"), to deal 7 - in the Software without restriction, including without limitation the rights 8 - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 - copies of the Software, and to permit persons to whom the Software is 10 - furnished to do so, subject to the following conditions: 104 + 2.2. Effective Date 11 105 12 - The above copyright notice and this permission notice shall be included in all 13 - copies or substantial portions of the Software. 106 + The licenses granted in Section 2.1 with respect to any Contribution 107 + become effective for each Contribution on the date the Contributor first 108 + distributes such Contribution. 14 109 15 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 - SOFTWARE. 110 + 2.3. Limitations on Grant Scope 111 + 112 + The licenses granted in this Section 2 are the only rights granted under 113 + this License. No additional rights or licenses will be implied from the 114 + distribution or licensing of Covered Software under this License. 115 + Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 + Contributor: 117 + 118 + (a) for any code that a Contributor has removed from Covered Software; 119 + or 120 + 121 + (b) for infringements caused by: (i) Your and any other third party's 122 + modifications of Covered Software, or (ii) the combination of its 123 + Contributions with other software (except as part of its Contributor 124 + Version); or 125 + 126 + (c) under Patent Claims infringed by Covered Software in the absence of 127 + its Contributions. 128 + 129 + This License does not grant any rights in the trademarks, service marks, 130 + or logos of any Contributor (except as may be necessary to comply with 131 + the notice requirements in Section 3.4). 132 + 133 + 2.4. Subsequent Licenses 134 + 135 + No Contributor makes additional grants as a result of Your choice to 136 + distribute the Covered Software under a subsequent version of this 137 + License (see Section 10.2) or under the terms of a Secondary License (if 138 + permitted under the terms of Section 3.3). 139 + 140 + 2.5. Representation 141 + 142 + Each Contributor represents that the Contributor believes its 143 + Contributions are its original creation(s) or it has sufficient rights 144 + to grant the rights to its Contributions conveyed by this License. 145 + 146 + 2.6. Fair Use 147 + 148 + This License is not intended to limit any rights You have under 149 + applicable copyright doctrines of fair use, fair dealing, or other 150 + equivalents. 151 + 152 + 2.7. Conditions 153 + 154 + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 + in Section 2.1. 156 + 157 + 3. Responsibilities 158 + ------------------- 159 + 160 + 3.1. Distribution of Source Form 161 + 162 + All distribution of Covered Software in Source Code Form, including any 163 + Modifications that You create or to which You contribute, must be under 164 + the terms of this License. You must inform recipients that the Source 165 + Code Form of the Covered Software is governed by the terms of this 166 + License, and how they can obtain a copy of this License. You may not 167 + attempt to alter or restrict the recipients' rights in the Source Code 168 + Form. 169 + 170 + 3.2. Distribution of Executable Form 171 + 172 + If You distribute Covered Software in Executable Form then: 173 + 174 + (a) such Covered Software must also be made available in Source Code 175 + Form, as described in Section 3.1, and You must inform recipients of 176 + the Executable Form how they can obtain a copy of such Source Code 177 + Form by reasonable means in a timely manner, at a charge no more 178 + than the cost of distribution to the recipient; and 179 + 180 + (b) You may distribute such Executable Form under the terms of this 181 + License, or sublicense it under different terms, provided that the 182 + license for the Executable Form does not attempt to limit or alter 183 + the recipients' rights in the Source Code Form under this License. 184 + 185 + 3.3. Distribution of a Larger Work 186 + 187 + You may create and distribute a Larger Work under terms of Your choice, 188 + provided that You also comply with the requirements of this License for 189 + the Covered Software. If the Larger Work is a combination of Covered 190 + Software with a work governed by one or more Secondary Licenses, and the 191 + Covered Software is not Incompatible With Secondary Licenses, this 192 + License permits You to additionally distribute such Covered Software 193 + under the terms of such Secondary License(s), so that the recipient of 194 + the Larger Work may, at their option, further distribute the Covered 195 + Software under the terms of either this License or such Secondary 196 + License(s). 197 + 198 + 3.4. Notices 199 + 200 + You may not remove or alter the substance of any license notices 201 + (including copyright notices, patent notices, disclaimers of warranty, 202 + or limitations of liability) contained within the Source Code Form of 203 + the Covered Software, except that You may alter any license notices to 204 + the extent required to remedy known factual inaccuracies. 205 + 206 + 3.5. Application of Additional Terms 207 + 208 + You may choose to offer, and to charge a fee for, warranty, support, 209 + indemnity or liability obligations to one or more recipients of Covered 210 + Software. However, You may do so only on Your own behalf, and not on 211 + behalf of any Contributor. You must make it absolutely clear that any 212 + such warranty, support, indemnity, or liability obligation is offered by 213 + You alone, and You hereby agree to indemnify every Contributor for any 214 + liability incurred by such Contributor as a result of warranty, support, 215 + indemnity or liability terms You offer. You may include additional 216 + disclaimers of warranty and limitations of liability specific to any 217 + jurisdiction. 218 + 219 + 4. Inability to Comply Due to Statute or Regulation 220 + --------------------------------------------------- 221 + 222 + If it is impossible for You to comply with any of the terms of this 223 + License with respect to some or all of the Covered Software due to 224 + statute, judicial order, or regulation then You must: (a) comply with 225 + the terms of this License to the maximum extent possible; and (b) 226 + describe the limitations and the code they affect. Such description must 227 + be placed in a text file included with all distributions of the Covered 228 + Software under this License. Except to the extent prohibited by statute 229 + or regulation, such description must be sufficiently detailed for a 230 + recipient of ordinary skill to be able to understand it. 231 + 232 + 5. Termination 233 + -------------- 234 + 235 + 5.1. The rights granted under this License will terminate automatically 236 + if You fail to comply with any of its terms. However, if You become 237 + compliant, then the rights granted under this License from a particular 238 + Contributor are reinstated (a) provisionally, unless and until such 239 + Contributor explicitly and finally terminates Your grants, and (b) on an 240 + ongoing basis, if such Contributor fails to notify You of the 241 + non-compliance by some reasonable means prior to 60 days after You have 242 + come back into compliance. Moreover, Your grants from a particular 243 + Contributor are reinstated on an ongoing basis if such Contributor 244 + notifies You of the non-compliance by some reasonable means, this is the 245 + first time You have received notice of non-compliance with this License 246 + from such Contributor, and You become compliant prior to 30 days after 247 + Your receipt of the notice. 248 + 249 + 5.2. If You initiate litigation against any entity by asserting a patent 250 + infringement claim (excluding declaratory judgment actions, 251 + counter-claims, and cross-claims) alleging that a Contributor Version 252 + directly or indirectly infringes any patent, then the rights granted to 253 + You by any and all Contributors for the Covered Software under Section 254 + 2.1 of this License shall terminate. 255 + 256 + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 + end user license agreements (excluding distributors and resellers) which 258 + have been validly granted by You or Your distributors under this License 259 + prior to termination shall survive termination. 260 + 261 + ************************************************************************ 262 + * * 263 + * 6. Disclaimer of Warranty * 264 + * ------------------------- * 265 + * * 266 + * Covered Software is provided under this License on an "as is" * 267 + * basis, without warranty of any kind, either expressed, implied, or * 268 + * statutory, including, without limitation, warranties that the * 269 + * Covered Software is free of defects, merchantable, fit for a * 270 + * particular purpose or non-infringing. The entire risk as to the * 271 + * quality and performance of the Covered Software is with You. * 272 + * Should any Covered Software prove defective in any respect, You * 273 + * (not any Contributor) assume the cost of any necessary servicing, * 274 + * repair, or correction. This disclaimer of warranty constitutes an * 275 + * essential part of this License. No use of any Covered Software is * 276 + * authorized under this License except under this disclaimer. * 277 + * * 278 + ************************************************************************ 279 + 280 + ************************************************************************ 281 + * * 282 + * 7. Limitation of Liability * 283 + * -------------------------- * 284 + * * 285 + * Under no circumstances and under no legal theory, whether tort * 286 + * (including negligence), contract, or otherwise, shall any * 287 + * Contributor, or anyone who distributes Covered Software as * 288 + * permitted above, be liable to You for any direct, indirect, * 289 + * special, incidental, or consequential damages of any character * 290 + * including, without limitation, damages for lost profits, loss of * 291 + * goodwill, work stoppage, computer failure or malfunction, or any * 292 + * and all other commercial damages or losses, even if such party * 293 + * shall have been informed of the possibility of such damages. This * 294 + * limitation of liability shall not apply to liability for death or * 295 + * personal injury resulting from such party's negligence to the * 296 + * extent applicable law prohibits such limitation. Some * 297 + * jurisdictions do not allow the exclusion or limitation of * 298 + * incidental or consequential damages, so this exclusion and * 299 + * limitation may not apply to You. * 300 + * * 301 + ************************************************************************ 302 + 303 + 8. Litigation 304 + ------------- 305 + 306 + Any litigation relating to this License may be brought only in the 307 + courts of a jurisdiction where the defendant maintains its principal 308 + place of business and such litigation shall be governed by laws of that 309 + jurisdiction, without reference to its conflict-of-law provisions. 310 + Nothing in this Section shall prevent a party's ability to bring 311 + cross-claims or counter-claims. 312 + 313 + 9. Miscellaneous 314 + ---------------- 315 + 316 + This License represents the complete agreement concerning the subject 317 + matter hereof. If any provision of this License is held to be 318 + unenforceable, such provision shall be reformed only to the extent 319 + necessary to make it enforceable. Any law or regulation which provides 320 + that the language of a contract shall be construed against the drafter 321 + shall not be used to construe this License against a Contributor. 322 + 323 + 10. Versions of the License 324 + --------------------------- 325 + 326 + 10.1. New Versions 327 + 328 + Mozilla Foundation is the license steward. Except as provided in Section 329 + 10.3, no one other than the license steward has the right to modify or 330 + publish new versions of this License. Each version will be given a 331 + distinguishing version number. 332 + 333 + 10.2. Effect of New Versions 334 + 335 + You may distribute the Covered Software under the terms of the version 336 + of the License under which You originally received the Covered Software, 337 + or under the terms of any subsequent version published by the license 338 + steward. 339 + 340 + 10.3. Modified Versions 341 + 342 + If you create software not governed by this License, and you want to 343 + create a new license for such software, you may create and use a 344 + modified version of this License if you rename the license and remove 345 + any references to the name of the license steward (except to note that 346 + such modified license differs from this License). 347 + 348 + 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 + Licenses 350 + 351 + If You choose to distribute Source Code Form that is Incompatible With 352 + Secondary Licenses under the terms of this version of the License, the 353 + notice described in Exhibit B of this License must be attached. 354 + 355 + Exhibit A - Source Code Form License Notice 356 + ------------------------------------------- 357 + 358 + This Source Code Form is subject to the terms of the Mozilla Public 359 + License, v. 2.0. If a copy of the MPL was not distributed with this 360 + file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 + 362 + If it is not possible or desirable to put the notice in a particular 363 + file, then You may include the notice in a location (such as a LICENSE 364 + file in a relevant directory) where a recipient would be likely to look 365 + for such a notice. 366 + 367 + You may add additional accurate notices of copyright ownership. 368 + 369 + Exhibit B - "Incompatible With Secondary Licenses" Notice 370 + --------------------------------------------------------- 371 + 372 + This Source Code Form is "Incompatible With Secondary Licenses", as 373 + defined by the Mozilla Public License, v. 2.0.
+74 -26
README.md
··· 2 2 3 3 A suite of Rust crates for the AT Protocol. 4 4 5 + [![Crates.io](https://img.shields.io/crates/v/jacquard.svg)](https://crates.io/crates/jacquard) [![Documentation](https://docs.rs/jacquard/badge.svg)](https://docs.rs/jacquard) [![License](https://img.shields.io/crates/l/jacquard.svg)](./LICENSE) 6 + 5 7 ## Goals 6 8 7 9 - Validated, spec-compliant, easy to work with, and performant baseline types (including typed at:// uris) ··· 13 15 - didDoc type with helper methods for getting handles, multikey, and PDS endpoint 14 16 - use as much or as little from the crates as you need 15 17 18 + 19 + ## Example 20 + 21 + Dead simple api client. Logs in, prints the latest 5 posts from your timeline. 22 + 23 + ```rust 24 + use clap::Parser; 25 + use jacquard::CowStr; 26 + use jacquard::api::app_bsky::feed::get_timeline::GetTimeline; 27 + use jacquard::api::com_atproto::server::create_session::CreateSession; 28 + use jacquard::client::{AuthenticatedClient, Session, XrpcClient}; 29 + use miette::IntoDiagnostic; 30 + 31 + #[derive(Parser, Debug)] 32 + #[command(author, version, about = "Jacquard - AT Protocol client demo")] 33 + struct Args { 34 + /// Username/handle (e.g., alice.mosphere.at) 35 + #[arg(short, long)] 36 + username: CowStr<'static>, 37 + 38 + /// PDS URL (e.g., https://bsky.social) 39 + #[arg(long, default_value = "https://bsky.social")] 40 + pds: CowStr<'static>, 41 + 42 + /// App password 43 + #[arg(short, long)] 44 + password: CowStr<'static>, 45 + } 46 + 47 + #[tokio::main] 48 + async fn main() -> miette::Result<()> { 49 + let args = Args::parse(); 50 + 51 + // Create HTTP client 52 + let mut client = AuthenticatedClient::new(reqwest::Client::new(), args.pds); 53 + 54 + // Create session 55 + let session = Session::from( 56 + client 57 + .send( 58 + CreateSession::new() 59 + .identifier(args.username) 60 + .password(args.password) 61 + .build(), 62 + ) 63 + .await? 64 + .into_output()?, 65 + ); 66 + 67 + println!("logged in as {} ({})", session.handle, session.did); 68 + client.set_session(session); 69 + 70 + // Fetch timeline 71 + println!("\nfetching timeline..."); 72 + let timeline = client 73 + .send(GetTimeline::new().limit(5).build()) 74 + .await? 75 + .into_output()?; 76 + 77 + println!("\ntimeline ({} posts):", timeline.feed.len()); 78 + for (i, post) in timeline.feed.iter().enumerate() { 79 + println!("\n{}. by {}", i + 1, post.post.author.handle); 80 + println!( 81 + " {}", 82 + serde_json::to_string_pretty(&post.post.record).into_diagnostic()? 83 + ); 84 + } 85 + 86 + Ok(()) 87 + } 88 + ``` 89 + 16 90 ## Development 17 91 18 92 This repo uses [Flakes](https://nixos.asia/en/flakes) from the get-go. ··· 29 103 ``` 30 104 31 105 There's also a [`justfile`](https://just.systems/) for Makefile-esque commands to be run inside of the devShell, and you can generally `cargo ...` or `just ...` whatever just fine if you don't want to use Nix and have the prerequisites installed. 32 - 33 - 34 - 35 - ### String types 36 - Something of a note to self. Developing a pattern with the string types (may macro-ify at some point). Each needs: 37 - - new(): constructing from a string slice with the right lifetime that borrows 38 - - new_owned(): constructing from an impl AsRef<str>, taking ownership 39 - - new_static(): construction from a &'static str, using SmolStr's/CowStr's new_static() constructor to not allocate 40 - - raw(): same as new() but panics instead of erroring 41 - - unchecked(): same as new() but doesn't validate. marked unsafe. 42 - - as_str(): does what it says on the tin 43 - #### Traits: 44 - - Serialize + Deserialize (custom impl for latter, sometimes for former) 45 - - FromStr 46 - - Display 47 - - Debug, PartialEq, Eq, Hash, Clone 48 - - From<T> for String, CowStr, SmolStr, 49 - - From<String>, From<CowStr>, From<SmolStr>, or TryFrom if likely enough to fail in practice to make panics common 50 - - AsRef<str> 51 - - Deref with Target = str (usually) 52 - 53 - Use `#[repr(transparent)]` as much as possible. Main exception is at-uri type and components. 54 - Use SmolStr directly as the inner type if most or all of the instances will be under 24 bytes, save lifetime headaches. 55 - Use CowStr for longer to allow for borrowing from input. 56 - 57 - TODO: impl IntoStatic trait to take ownership of string types
+27 -16
crates/jacquard/Cargo.toml
··· 1 1 [package] 2 - authors.workspace = true 3 - # If you change the name here, you must also do it in flake.nix (and run `cargo generate-lockfile` afterwards) 4 2 name = "jacquard" 5 - description = "A simple Rust project using Nix" 3 + description.workspace = true 4 + edition.workspace = true 6 5 version.workspace = true 7 - edition.workspace = true 6 + authors.workspace = true 7 + repository.workspace = true 8 + keywords.workspace = true 9 + categories.workspace = true 10 + readme.workspace = true 11 + exclude.workspace = true 12 + license-file.workspace = true 8 13 9 - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 + [features] 15 + default = ["api_all"] 16 + derive = ["dep:jacquard-derive"] 17 + api = ["jacquard-api/com_atproto"] 18 + api_all = ["api", "jacquard-api/app_bsky", "jacquard-api/chat_bsky", "jacquard-api/tools_ozone"] 10 19 11 20 [lib] 12 21 name = "jacquard" ··· 17 26 path = "src/main.rs" 18 27 19 28 [dependencies] 20 - bytes = "1.10" 21 - clap = { workspace = true } 22 - http = "1.3.1" 29 + bytes.workspace = true 30 + clap.workspace = true 31 + http.workspace = true 23 32 jacquard-api = { version = "0.1.0", path = "../jacquard-api" } 24 - jacquard-common = { path = "../jacquard-common" } 25 - miette = "7.6.0" 26 - reqwest = { version = "0.12.23", default-features = false, features = ["charset", "http2", "json", "system-proxy", "gzip", "rustls-tls"] } 27 - serde = { version = "1.0", features = ["derive"] } 28 - serde_html_form = "0.2" 29 - serde_ipld_dagcbor = "0.6.4" 30 - serde_json = "1.0" 31 - thiserror = "2.0" 33 + jacquard-common = { version = "0.1.0", path = "../jacquard-common" } 34 + jacquard-derive = { version = "0.1.0", path = "../jacquard-derive", optional = true } 35 + miette.workspace = true 36 + reqwest = { workspace = true, features = ["charset", "http2", "json", "system-proxy", "gzip", "rustls-tls"] } 37 + serde.workspace = true 38 + serde_html_form.workspace = true 39 + serde_ipld_dagcbor.workspace = true 40 + serde_json.workspace = true 41 + thiserror.workspace = true 42 + tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
+25 -16
crates/jacquard/src/client/error.rs
··· 1 + //! Error types for XRPC client operations 2 + 1 3 use bytes::Bytes; 2 4 3 - /// Client error type 5 + /// Client error type wrapping all possible error conditions 4 6 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 5 7 pub enum ClientError { 6 8 /// HTTP transport error ··· 44 46 ), 45 47 } 46 48 49 + /// Transport-level errors that occur during HTTP communication 47 50 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 48 51 pub enum TransportError { 52 + /// Failed to establish connection to server 49 53 #[error("Connection error: {0}")] 50 54 Connect(String), 51 55 56 + /// Request timed out 52 57 #[error("Request timeout")] 53 58 Timeout, 54 59 60 + /// Request construction failed (malformed URI, headers, etc.) 55 61 #[error("Invalid request: {0}")] 56 62 InvalidRequest(String), 57 63 64 + /// Other transport error 58 65 #[error("Transport error: {0}")] 59 66 Other(Box<dyn std::error::Error + Send + Sync>), 60 67 } 61 68 62 - #[derive(Debug, thiserror::Error, miette::Diagnostic)] 63 - pub enum EncodeError { 64 - #[error("Failed to serialize query: {0}")] 65 - Query( 66 - #[from] 67 - #[source] 68 - serde_html_form::ser::Error, 69 - ), 70 - #[error("Failed to serialize JSON: {0}")] 71 - Json( 72 - #[from] 73 - #[source] 74 - serde_json::Error, 75 - ), 76 - } 69 + // Re-export EncodeError from common 70 + pub use jacquard_common::types::xrpc::EncodeError; 77 71 72 + /// Response deserialization errors 78 73 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 79 74 pub enum DecodeError { 75 + /// JSON deserialization failed 80 76 #[error("Failed to deserialize JSON: {0}")] 81 77 Json( 82 78 #[from] 83 79 #[source] 84 80 serde_json::Error, 85 81 ), 82 + /// CBOR deserialization failed (local I/O) 86 83 #[error("Failed to deserialize CBOR: {0}")] 87 84 CborLocal( 88 85 #[from] 89 86 #[source] 90 87 serde_ipld_dagcbor::DecodeError<std::io::Error>, 91 88 ), 89 + /// CBOR deserialization failed (remote/reqwest) 92 90 #[error("Failed to deserialize CBOR: {0}")] 93 91 CborRemote( 94 92 #[from] ··· 97 95 ), 98 96 } 99 97 98 + /// HTTP error response (non-200 status codes outside of XRPC error handling) 100 99 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 101 100 pub struct HttpError { 101 + /// HTTP status code 102 102 pub status: http::StatusCode, 103 + /// Response body if available 103 104 pub body: Option<Bytes>, 104 105 } 105 106 ··· 115 116 } 116 117 } 117 118 119 + /// Authentication and authorization errors 118 120 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 119 121 pub enum AuthError { 122 + /// Access token has expired (use refresh token to get a new one) 120 123 #[error("Access token expired")] 121 124 TokenExpired, 122 125 126 + /// Access token is invalid or malformed 123 127 #[error("Invalid access token")] 124 128 InvalidToken, 125 129 130 + /// Token refresh request failed 126 131 #[error("Token refresh failed")] 127 132 RefreshFailed, 128 133 134 + /// Request requires authentication but none was provided 129 135 #[error("No authentication provided")] 130 136 NotAuthenticated, 137 + 138 + /// Other authentication error 131 139 #[error("Authentication error: {0:?}")] 132 140 Other(http::HeaderValue), 133 141 } 134 142 143 + /// Result type for client operations 135 144 pub type Result<T> = std::result::Result<T, ClientError>; 136 145 137 146 impl From<reqwest::Error> for TransportError {
+117 -12
crates/jacquard/src/client/response.rs
··· 1 + //! XRPC response parsing and error handling 2 + 1 3 use bytes::Bytes; 4 + use http::StatusCode; 2 5 use jacquard_common::IntoStatic; 6 + use jacquard_common::smol_str::SmolStr; 3 7 use jacquard_common::types::xrpc::XrpcRequest; 8 + use serde::Deserialize; 4 9 use std::marker::PhantomData; 5 10 11 + use super::error::AuthError; 12 + 6 13 /// XRPC response wrapper that owns the response buffer 7 14 /// 8 15 /// Allows borrowing from the buffer when parsing to avoid unnecessary allocations. 16 + /// Supports both borrowed parsing (with `parse()`) and owned parsing (with `into_output()`). 9 17 pub struct Response<R: XrpcRequest> { 10 18 buffer: Bytes, 19 + status: StatusCode, 11 20 _marker: PhantomData<R>, 12 21 } 13 22 14 23 impl<R: XrpcRequest> Response<R> { 15 - /// Create a new response from a buffer 16 - pub fn new(buffer: Bytes) -> Self { 24 + /// Create a new response from a buffer and status code 25 + pub fn new(buffer: Bytes, status: StatusCode) -> Self { 17 26 Self { 18 27 buffer, 28 + status, 19 29 _marker: PhantomData, 20 30 } 21 31 } 22 32 33 + /// Get the HTTP status code 34 + pub fn status(&self) -> StatusCode { 35 + self.status 36 + } 37 + 23 38 /// Parse the response, borrowing from the internal buffer 24 39 pub fn parse(&self) -> Result<R::Output<'_>, XrpcError<R::Err<'_>>> { 25 40 // Use a helper to make lifetime inference work ··· 35 50 serde_json::from_slice(buffer) 36 51 } 37 52 38 - let output = parse_output::<R>(&self.buffer); 39 - if let Ok(output) = output { 40 - Ok(output) 41 - } else { 42 - // Try to parse as error 53 + // 200: parse as output 54 + if self.status.is_success() { 55 + match parse_output::<R>(&self.buffer) { 56 + Ok(output) => Ok(output), 57 + Err(e) => Err(XrpcError::Decode(e)), 58 + } 59 + // 400: try typed XRPC error, fallback to generic error 60 + } else if self.status.as_u16() == 400 { 43 61 match parse_error::<R>(&self.buffer) { 44 62 Ok(error) => Err(XrpcError::Xrpc(error)), 63 + Err(_) => { 64 + // Fallback to generic error (InvalidRequest, ExpiredToken, etc.) 65 + match serde_json::from_slice::<GenericXrpcError>(&self.buffer) { 66 + Ok(generic) => { 67 + // Map auth-related errors to AuthError 68 + match generic.error.as_str() { 69 + "ExpiredToken" => Err(XrpcError::Auth(AuthError::TokenExpired)), 70 + "InvalidToken" => Err(XrpcError::Auth(AuthError::InvalidToken)), 71 + _ => Err(XrpcError::Generic(generic)), 72 + } 73 + } 74 + Err(e) => Err(XrpcError::Decode(e)), 75 + } 76 + } 77 + } 78 + // 401: always auth error 79 + } else { 80 + match serde_json::from_slice::<GenericXrpcError>(&self.buffer) { 81 + Ok(generic) => match generic.error.as_str() { 82 + "ExpiredToken" => Err(XrpcError::Auth(AuthError::TokenExpired)), 83 + "InvalidToken" => Err(XrpcError::Auth(AuthError::InvalidToken)), 84 + _ => Err(XrpcError::Auth(AuthError::NotAuthenticated)), 85 + }, 45 86 Err(e) => Err(XrpcError::Decode(e)), 46 87 } 47 88 } ··· 66 107 serde_json::from_slice(buffer) 67 108 } 68 109 69 - let output = parse_output::<R>(&self.buffer); 70 - if let Ok(output) = output { 71 - Ok(output.into_static()) 72 - } else { 73 - // Try to parse as error 110 + // 200: parse as output 111 + if self.status.is_success() { 112 + match parse_output::<R>(&self.buffer) { 113 + Ok(output) => Ok(output.into_static()), 114 + Err(e) => Err(XrpcError::Decode(e)), 115 + } 116 + // 400: try typed XRPC error, fallback to generic error 117 + } else if self.status.as_u16() == 400 { 74 118 match parse_error::<R>(&self.buffer) { 75 119 Ok(error) => Err(XrpcError::Xrpc(error.into_static())), 120 + Err(_) => { 121 + // Fallback to generic error (InvalidRequest, ExpiredToken, etc.) 122 + match serde_json::from_slice::<GenericXrpcError>(&self.buffer) { 123 + Ok(generic) => { 124 + // Map auth-related errors to AuthError 125 + match generic.error.as_ref() { 126 + "ExpiredToken" => Err(XrpcError::Auth(AuthError::TokenExpired)), 127 + "InvalidToken" => Err(XrpcError::Auth(AuthError::InvalidToken)), 128 + _ => Err(XrpcError::Generic(generic)), 129 + } 130 + } 131 + Err(e) => Err(XrpcError::Decode(e)), 132 + } 133 + } 134 + } 135 + // 401: always auth error 136 + } else { 137 + match serde_json::from_slice::<GenericXrpcError>(&self.buffer) { 138 + Ok(generic) => match generic.error.as_ref() { 139 + "ExpiredToken" => Err(XrpcError::Auth(AuthError::TokenExpired)), 140 + "InvalidToken" => Err(XrpcError::Auth(AuthError::InvalidToken)), 141 + _ => Err(XrpcError::Auth(AuthError::NotAuthenticated)), 142 + }, 76 143 Err(e) => Err(XrpcError::Decode(e)), 77 144 } 78 145 } ··· 84 151 } 85 152 } 86 153 154 + /// Generic XRPC error format for untyped errors like InvalidRequest 155 + /// 156 + /// Used when the error doesn't match the endpoint's specific error enum 157 + #[derive(Debug, Clone, Deserialize)] 158 + pub struct GenericXrpcError { 159 + /// Error code (e.g., "InvalidRequest") 160 + pub error: SmolStr, 161 + /// Optional error message with details 162 + pub message: Option<SmolStr>, 163 + } 164 + 165 + impl std::fmt::Display for GenericXrpcError { 166 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 167 + if let Some(msg) = &self.message { 168 + write!(f, "{}: {}", self.error, msg) 169 + } else { 170 + write!(f, "{}", self.error) 171 + } 172 + } 173 + } 174 + 175 + impl std::error::Error for GenericXrpcError {} 176 + 177 + /// XRPC-specific errors returned from endpoints 178 + /// 179 + /// Represents errors returned in the response body 180 + /// Type parameter `E` is the endpoint's specific error enum type. 87 181 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 88 182 pub enum XrpcError<E: std::error::Error + IntoStatic> { 183 + /// Typed XRPC error from the endpoint's specific error enum 89 184 #[error("XRPC error: {0}")] 90 185 Xrpc(E), 186 + 187 + /// Authentication error (ExpiredToken, InvalidToken, etc.) 188 + #[error("Authentication error: {0}")] 189 + Auth(#[from] AuthError), 190 + 191 + /// Generic XRPC error not in the endpoint's error enum (e.g., InvalidRequest) 192 + #[error("XRPC error: {0}")] 193 + Generic(GenericXrpcError), 194 + 195 + /// Failed to decode the response body 91 196 #[error("Failed to decode response: {0}")] 92 197 Decode(#[from] serde_json::Error), 93 198 }
+189 -27
crates/jacquard/src/client.rs
··· 1 + //! XRPC client implementation for AT Protocol 2 + //! 3 + //! This module provides HTTP and XRPC client traits along with an authenticated 4 + //! client implementation that manages session tokens. 5 + 1 6 mod error; 2 7 mod response; 3 8 4 9 use std::fmt::Display; 5 10 use std::future::Future; 6 11 7 - pub use error::{ClientError, Result}; 8 12 use bytes::Bytes; 13 + pub use error::{ClientError, Result}; 9 14 use http::{ 10 15 HeaderName, HeaderValue, Request, 11 16 header::{AUTHORIZATION, CONTENT_TYPE, InvalidHeaderValue}, 12 17 }; 13 18 pub use response::Response; 14 - use serde::Serialize; 19 + 20 + use jacquard_common::{ 21 + CowStr, IntoStatic, 22 + types::{ 23 + string::{Did, Handle}, 24 + xrpc::{XrpcMethod, XrpcRequest}, 25 + }, 26 + }; 27 + 28 + /// Implement HttpClient for reqwest::Client 29 + impl HttpClient for reqwest::Client { 30 + type Error = reqwest::Error; 15 31 16 - use jacquard_common::{CowStr, types::xrpc::{XrpcMethod, XrpcRequest}}; 32 + async fn send_http( 33 + &self, 34 + request: Request<Vec<u8>>, 35 + ) -> core::result::Result<http::Response<Vec<u8>>, Self::Error> { 36 + // Convert http::Request to reqwest::Request 37 + let (parts, body) = request.into_parts(); 17 38 39 + let mut req = self.request(parts.method, parts.uri.to_string()).body(body); 40 + 41 + // Copy headers 42 + for (name, value) in parts.headers.iter() { 43 + req = req.header(name.as_str(), value.as_bytes()); 44 + } 45 + 46 + // Send request 47 + let resp = req.send().await?; 48 + 49 + // Convert reqwest::Response to http::Response 50 + let mut builder = http::Response::builder().status(resp.status()); 51 + 52 + // Copy headers 53 + for (name, value) in resp.headers().iter() { 54 + builder = builder.header(name.as_str(), value.as_bytes()); 55 + } 56 + 57 + // Read body 58 + let body = resp.bytes().await?.to_vec(); 59 + 60 + Ok(builder.body(body).expect("Failed to build response")) 61 + } 62 + } 63 + 64 + /// HTTP client trait for sending raw HTTP requests 18 65 pub trait HttpClient { 66 + /// Error type returned by the HTTP client 19 67 type Error: std::error::Error + Display + Send + Sync + 'static; 20 68 /// Send an HTTP request and return the response. 21 69 fn send_http( ··· 23 71 request: Request<Vec<u8>>, 24 72 ) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, Self::Error>>; 25 73 } 26 - /// XRPC client trait 74 + /// XRPC client trait for AT Protocol RPC calls 27 75 pub trait XrpcClient: HttpClient { 76 + /// Get the base URI for XRPC requests (e.g., "https://bsky.social") 28 77 fn base_uri(&self) -> CowStr<'_>; 78 + /// Get the authorization token for XRPC requests 29 79 #[allow(unused_variables)] 30 80 fn authorization_token( 31 81 &self, ··· 52 102 53 103 pub(crate) const NSID_REFRESH_SESSION: &str = "com.atproto.server.refreshSession"; 54 104 105 + /// Authorization token types for XRPC requests 55 106 pub enum AuthorizationToken<'s> { 107 + /// Bearer token (access JWT, refresh JWT to refresh the session) 56 108 Bearer(CowStr<'s>), 109 + /// DPoP token (proof-of-possession) for OAuth 57 110 Dpop(CowStr<'s>), 58 111 } 59 112 ··· 68 121 } 69 122 } 70 123 71 - /// HTTP headers which can be used in XPRC requests. 124 + /// HTTP headers commonly used in XRPC requests 72 125 pub enum Header { 126 + /// Content-Type header 73 127 ContentType, 128 + /// Authorization header 74 129 Authorization, 130 + /// `atproto-proxy` header - specifies which service (app server or other atproto service) the user's PDS should forward requests to as appropriate. 131 + /// 132 + /// See: <https://atproto.com/specs/xrpc#service-proxying> 75 133 AtprotoProxy, 134 + /// `atproto-accept-labelers` header used by clients to request labels from specific labelers to be included and applied in the response. See [label](https://atproto.com/specs/label) specification for details. 76 135 AtprotoAcceptLabelers, 77 136 } 78 137 ··· 98 157 99 158 // Add query parameters for Query methods 100 159 if let XrpcMethod::Query = R::METHOD { 101 - if let Ok(qs) = serde_html_form::to_string(&request) { 102 - if !qs.is_empty() { 103 - uri.push('?'); 104 - uri.push_str(&qs); 105 - } 160 + let qs = serde_html_form::to_string(&request).map_err(error::EncodeError::from)?; 161 + if !qs.is_empty() { 162 + uri.push('?'); 163 + uri.push_str(&qs); 106 164 } 107 165 } 108 166 ··· 139 197 } 140 198 141 199 // Serialize body for procedures 142 - let body = if let XrpcMethod::Procedure(encoding) = R::METHOD { 143 - if encoding == "application/json" { 144 - serde_json::to_vec(&request).map_err(error::EncodeError::Json)? 145 - } else { 146 - // For other encodings, we'd need different serialization 147 - vec![] 148 - } 200 + let body = if let XrpcMethod::Procedure(_) = R::METHOD { 201 + request.encode_body()? 149 202 } else { 150 203 vec![] 151 204 }; 152 205 206 + // TODO: make this not panic 153 207 let http_request = builder.body(body).expect("Failed to build HTTP request"); 154 208 155 209 // Send HTTP request 156 - let http_response = client.send_http(http_request).await.map_err(|e| { 157 - error::TransportError::Other(Box::new(e)) 158 - })?; 210 + let http_response = client 211 + .send_http(http_request) 212 + .await 213 + .map_err(|e| error::TransportError::Other(Box::new(e)))?; 214 + 215 + let status = http_response.status(); 216 + let buffer = Bytes::from(http_response.into_body()); 159 217 160 - // Check status 161 - if !http_response.status().is_success() { 218 + // XRPC errors come as 400/401 with structured error bodies 219 + // Other error status codes (404, 500, etc.) are generic HTTP errors 220 + if !status.is_success() && !matches!(status.as_u16(), 400 | 401) { 162 221 return Err(ClientError::Http(error::HttpError { 163 - status: http_response.status(), 164 - body: Some(Bytes::from(http_response.body().clone())), 222 + status, 223 + body: Some(buffer), 165 224 })); 166 225 } 167 226 168 - // Convert to Response 169 - let buffer = Bytes::from(http_response.into_body()); 170 - Ok(Response::new(buffer)) 227 + // Response will parse XRPC errors for 400/401, or output for 2xx 228 + Ok(Response::new(buffer, status)) 229 + } 230 + 231 + /// Session information from `com.atproto.server.createSession` 232 + /// 233 + /// Contains the access and refresh tokens along with user identity information. 234 + #[derive(Debug, Clone)] 235 + pub struct Session { 236 + /// Access token (JWT) used for authenticated requests 237 + pub access_jwt: CowStr<'static>, 238 + /// Refresh token (JWT) used to obtain new access tokens 239 + pub refresh_jwt: CowStr<'static>, 240 + /// User's DID (Decentralized Identifier) 241 + pub did: Did<'static>, 242 + /// User's handle (e.g., "alice.bsky.social") 243 + pub handle: Handle<'static>, 244 + } 245 + 246 + impl From<jacquard_api::com_atproto::server::create_session::CreateSessionOutput<'_>> for Session { 247 + fn from( 248 + output: jacquard_api::com_atproto::server::create_session::CreateSessionOutput<'_>, 249 + ) -> Self { 250 + Self { 251 + access_jwt: output.access_jwt.into_static(), 252 + refresh_jwt: output.refresh_jwt.into_static(), 253 + did: output.did.into_static(), 254 + handle: output.handle.into_static(), 255 + } 256 + } 257 + } 258 + 259 + /// Authenticated XRPC client wrapper that manages session tokens 260 + /// 261 + /// Wraps an HTTP client and adds automatic Bearer token authentication for XRPC requests. 262 + /// Handles both access tokens for regular requests and refresh tokens for session refresh. 263 + pub struct AuthenticatedClient<C> { 264 + client: C, 265 + base_uri: CowStr<'static>, 266 + session: Option<Session>, 267 + } 268 + 269 + impl<C> AuthenticatedClient<C> { 270 + /// Create a new authenticated client with a base URI 271 + /// 272 + /// # Example 273 + /// ```ignore 274 + /// let client = AuthenticatedClient::new( 275 + /// reqwest::Client::new(), 276 + /// CowStr::from("https://bsky.social") 277 + /// ); 278 + /// ``` 279 + pub fn new(client: C, base_uri: CowStr<'static>) -> Self { 280 + Self { 281 + client, 282 + base_uri: base_uri, 283 + session: None, 284 + } 285 + } 286 + 287 + /// Set the session obtained from `createSession` or `refreshSession` 288 + pub fn set_session(&mut self, session: Session) { 289 + self.session = Some(session); 290 + } 291 + 292 + /// Get the current session if one exists 293 + pub fn session(&self) -> Option<&Session> { 294 + self.session.as_ref() 295 + } 296 + 297 + /// Clear the current session locally 298 + /// 299 + /// Note: This only clears the local session state. To properly revoke the session 300 + /// server-side, use `com.atproto.server.deleteSession` before calling this. 301 + pub fn clear_session(&mut self) { 302 + self.session = None; 303 + } 304 + } 305 + 306 + impl<C: HttpClient> HttpClient for AuthenticatedClient<C> { 307 + type Error = C::Error; 308 + 309 + fn send_http( 310 + &self, 311 + request: Request<Vec<u8>>, 312 + ) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, Self::Error>> { 313 + self.client.send_http(request) 314 + } 315 + } 316 + 317 + impl<C: HttpClient> XrpcClient for AuthenticatedClient<C> { 318 + fn base_uri(&self) -> CowStr<'_> { 319 + self.base_uri.clone() 320 + } 321 + 322 + async fn authorization_token(&self, is_refresh: bool) -> Option<AuthorizationToken<'_>> { 323 + if is_refresh { 324 + self.session 325 + .as_ref() 326 + .map(|s| AuthorizationToken::Bearer(s.refresh_jwt.clone())) 327 + } else { 328 + self.session 329 + .as_ref() 330 + .map(|s| AuthorizationToken::Bearer(s.access_jwt.clone())) 331 + } 332 + } 171 333 }
+99 -1
crates/jacquard/src/lib.rs
··· 1 + //! # Jacquard 2 + //! 3 + //! A suite of Rust crates for the AT Protocol. 4 + //! 5 + //! 6 + //! ## Goals 7 + //! 8 + //! - Validated, spec-compliant, easy to work with, and performant baseline types (including typed at:// uris) 9 + //! - Batteries-included, but easily replaceable batteries. 10 + //! - Easy to extend with custom lexicons 11 + //! - lexicon Value type for working with unknown atproto data (dag-cbor or json) 12 + //! - order of magnitude less boilerplate than some existing crates 13 + //! - either the codegen produces code that's easy to work with, or there are good handwritten wrappers 14 + //! - didDoc type with helper methods for getting handles, multikey, and PDS endpoint 15 + //! - use as much or as little from the crates as you need 16 + //! 17 + //! 18 + //! ## Example 19 + //! 20 + //! Dead simple api client. Logs in, prints the latest 5 posts from your timeline. 21 + //! 22 + //! ```rust 23 + //! # use clap::Parser; 24 + //! # use jacquard::CowStr; 25 + //! use jacquard::api::app_bsky::feed::get_timeline::GetTimeline; 26 + //! use jacquard::api::com_atproto::server::create_session::CreateSession; 27 + //! use jacquard::client::{AuthenticatedClient, Session, XrpcClient}; 28 + //! # use miette::IntoDiagnostic; 29 + //! 30 + //! # #[derive(Parser, Debug)] 31 + //! # #[command(author, version, about = "Jacquard - AT Protocol client demo")] 32 + //! # struct Args { 33 + //! # /// Username/handle (e.g., alice.mosphere.at) 34 + //! # #[arg(short, long)] 35 + //! # username: CowStr<'static>, 36 + //! # 37 + //! # /// PDS URL (e.g., https://bsky.social) 38 + //! # #[arg(long, default_value = "https://bsky.social")] 39 + //! # pds: CowStr<'static>, 40 + //! # 41 + //! # /// App password 42 + //! # #[arg(short, long)] 43 + //! # password: CowStr<'static>, 44 + //! # } 45 + //! 46 + //! #[tokio::main] 47 + //! async fn main() -> miette::Result<()> { 48 + //! let args = Args::parse(); 49 + //! 50 + //! // Create HTTP client 51 + //! let mut client = AuthenticatedClient::new(reqwest::Client::new(), args.pds); 52 + //! 53 + //! // Create session 54 + //! let session = Session::from( 55 + //! client 56 + //! .send( 57 + //! CreateSession::new() 58 + //! .identifier(args.username) 59 + //! .password(args.password) 60 + //! .build(), 61 + //! ) 62 + //! .await? 63 + //! .into_output()?, 64 + //! ); 65 + //! 66 + //! println!("logged in as {} ({})", session.handle, session.did); 67 + //! client.set_session(session); 68 + //! 69 + //! // Fetch timeline 70 + //! println!("\nfetching timeline..."); 71 + //! let timeline = client 72 + //! .send(GetTimeline::new().limit(5).build()) 73 + //! .await? 74 + //! .into_output()?; 75 + //! 76 + //! println!("\ntimeline ({} posts):", timeline.feed.len()); 77 + //! for (i, post) in timeline.feed.iter().enumerate() { 78 + //! println!("\n{}. by {}", i + 1, post.post.author.handle); 79 + //! println!( 80 + //! " {}", 81 + //! serde_json::to_string_pretty(&post.post.record).into_diagnostic()? 82 + //! ); 83 + //! } 84 + //! 85 + //! Ok(()) 86 + //! } 87 + //! ``` 88 + //! 89 + 90 + #![warn(missing_docs)] 91 + 92 + /// XRPC client traits and basic implementation 1 93 pub mod client; 2 94 3 - // Re-export common types 95 + #[cfg(feature = "api")] 96 + /// If enabled, re-export the generated api crate 97 + pub use jacquard_api as api; 4 98 pub use jacquard_common::*; 99 + 100 + #[cfg(feature = "derive")] 101 + /// if enabled, reexport the attribute macros 102 + pub use jacquard_derive::*;
+55 -11
crates/jacquard/src/main.rs
··· 1 1 use clap::Parser; 2 - use jacquard_api::com_atproto::repo::create_record::*; 2 + use jacquard::CowStr; 3 + use jacquard::api::app_bsky::feed::get_timeline::GetTimeline; 4 + use jacquard::api::com_atproto::server::create_session::CreateSession; 5 + use jacquard::client::{AuthenticatedClient, Session, XrpcClient}; 6 + use miette::IntoDiagnostic; 3 7 4 8 #[derive(Parser, Debug)] 5 - #[command(author = "Orual", version, about)] 6 - /// Application configuration 9 + #[command(author, version, about = "Jacquard - AT Protocol client demo")] 7 10 struct Args { 8 - /// whether to be verbose 9 - #[arg(short = 'v')] 10 - verbose: bool, 11 + /// Username/handle (e.g., alice.bsky.social) 12 + #[arg(short, long)] 13 + username: CowStr<'static>, 14 + 15 + /// PDS URL (e.g., https://bsky.social) 16 + #[arg(long, default_value = "https://bsky.social")] 17 + pds: CowStr<'static>, 11 18 12 - /// an optional name to greet 13 - #[arg()] 14 - name: Option<String>, 19 + /// App password 20 + #[arg(short, long)] 21 + password: CowStr<'static>, 15 22 } 23 + #[tokio::main] 24 + async fn main() -> miette::Result<()> { 25 + let args = Args::parse(); 16 26 17 - fn main() { 18 - let client = reqwest::Client::new(); 27 + // Create HTTP client 28 + let mut client = AuthenticatedClient::new(reqwest::Client::new(), args.pds); 29 + 30 + // Create session 31 + let session = Session::from( 32 + client 33 + .send( 34 + CreateSession::new() 35 + .identifier(args.username) 36 + .password(args.password) 37 + .build(), 38 + ) 39 + .await? 40 + .into_output()?, 41 + ); 42 + 43 + println!("logged in as {} ({})", session.handle, session.did); 44 + client.set_session(session); 45 + 46 + // Fetch timeline 47 + println!("\nfetching timeline..."); 48 + let timeline = client 49 + .send(GetTimeline::new().limit(5).build()) 50 + .await? 51 + .into_output()?; 52 + 53 + println!("\ntimeline ({} posts):", timeline.feed.len()); 54 + for (i, post) in timeline.feed.iter().enumerate() { 55 + println!("\n{}. by {}", i + 1, post.post.author.handle); 56 + println!( 57 + " {}", 58 + serde_json::to_string_pretty(&post.post.record).into_diagnostic()? 59 + ); 60 + } 61 + 62 + Ok(()) 19 63 }
+8 -7
crates/jacquard-api/Cargo.toml
··· 1 1 [package] 2 2 name = "jacquard-api" 3 + description = "Generated AT Protocol API bindings for Jacquard" 3 4 edition.workspace = true 4 5 version.workspace = true 5 6 authors.workspace = true ··· 7 8 keywords.workspace = true 8 9 categories.workspace = true 9 10 readme.workspace = true 10 - documentation.workspace = true 11 11 exclude.workspace = true 12 - description.workspace = true 12 + license-file.workspace = true 13 13 14 14 [features] 15 - default = ["app_bsky", "com_atproto", "tools_ozone", "chat_bsky"] 15 + default = [ "com_atproto"] 16 16 app_bsky = [] 17 17 chat_bsky = [] 18 18 com_atproto = [] 19 19 tools_ozone = [] 20 20 21 21 [dependencies] 22 - bytes = { version = "1.10.1", features = ["serde"] } 22 + bon = "3" 23 + bytes = { workspace = true, features = ["serde"] } 23 24 jacquard-common = { version = "0.1.0", path = "../jacquard-common" } 24 25 jacquard-derive = { version = "0.1.0", path = "../jacquard-derive" } 25 - miette = "7.6.0" 26 - serde = { version = "1.0.228", features = ["derive"] } 27 - thiserror = "2.0.17" 26 + miette.workspace = true 27 + serde.workspace = true 28 + thiserror.workspace = true
+10 -1
crates/jacquard-api/src/app_bsky/actor/get_preferences.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetPreferences {} 11 20 impl jacquard_common::IntoStatic for GetPreferences {
+10 -1
crates/jacquard-api/src/app_bsky/actor/get_profile.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetProfile<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/app_bsky/actor/get_profiles.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetProfiles<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/app_bsky/actor/get_suggestions.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestions<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+17 -1
crates/jacquard-api/src/app_bsky/actor/put_preferences.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct PutPreferences<'a> { 12 21 #[serde(borrow)] 13 22 pub preferences: crate::app_bsky::actor::Preferences<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for PutPreferences<'_> {
+13 -1
crates/jacquard-api/src/app_bsky/actor/search_actors.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchActors<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 25, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 26 pub limit: std::option::Option<i64>, 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub q: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 32 #[serde(borrow)] 33 + #[builder(into)] 22 34 pub term: std::option::Option<jacquard_common::CowStr<'a>>, 23 35 } 24 36
+12 -1
crates/jacquard-api/src/app_bsky/actor/search_actors_typeahead.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchActorsTypeahead<'a> { 11 20 ///(default: 10, min: 1, max: 100) ··· 13 22 pub limit: std::option::Option<i64>, 14 23 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 24 #[serde(borrow)] 25 + #[builder(into)] 16 26 pub q: std::option::Option<jacquard_common::CowStr<'a>>, 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub term: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 } 21 32
+17 -1
crates/jacquard-api/src/app_bsky/bookmark/create_bookmark.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct CreateBookmark<'a> { 12 21 #[serde(borrow)] 13 22 pub cid: jacquard_common::types::string::Cid<'a>, 14 23 #[serde(borrow)] 15 24 pub uri: jacquard_common::types::string::AtUri<'a>, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 16 32 } 17 33 18 34 impl jacquard_common::IntoStatic for CreateBookmark<'_> {
+17 -1
crates/jacquard-api/src/app_bsky/bookmark/delete_bookmark.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteBookmark<'a> { 12 21 #[serde(borrow)] 13 22 pub uri: jacquard_common::types::string::AtUri<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for DeleteBookmark<'_> {
+11 -1
crates/jacquard-api/src/app_bsky/bookmark/get_bookmarks.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetBookmarks<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/feed/get_actor_feeds.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetActorFeeds<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/feed/get_actor_likes.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetActorLikes<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+12 -1
crates/jacquard-api/src/app_bsky/feed/get_author_feed.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetAuthorFeed<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: "posts_with_replies") 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub filter: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 ///(default: false) 21 32 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/feed/get_feed.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetFeed<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 #[serde(borrow)] 15 25 pub feed: jacquard_common::types::string::AtUri<'a>,
+10 -1
crates/jacquard-api/src/app_bsky/feed/get_feed_generator.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetFeedGenerator<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/app_bsky/feed/get_feed_generators.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetFeedGenerators<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/app_bsky/feed/get_feed_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetFeedSkeleton<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 #[serde(borrow)] 15 25 pub feed: jacquard_common::types::string::AtUri<'a>,
+11 -1
crates/jacquard-api/src/app_bsky/feed/get_likes.rs
··· 27 27 } 28 28 } 29 29 30 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 30 + #[derive( 31 + serde::Serialize, 32 + serde::Deserialize, 33 + Debug, 34 + Clone, 35 + PartialEq, 36 + Eq, 37 + bon::Builder 38 + )] 39 + #[builder(start_fn = new)] 31 40 #[serde(rename_all = "camelCase")] 32 41 pub struct GetLikes<'a> { 33 42 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 35 44 pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>, 36 45 #[serde(skip_serializing_if = "std::option::Option::is_none")] 37 46 #[serde(borrow)] 47 + #[builder(into)] 38 48 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 39 49 ///(default: 50, min: 1, max: 100) 40 50 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/feed/get_list_feed.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetListFeed<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+10 -1
crates/jacquard-api/src/app_bsky/feed/get_post_thread.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetPostThread<'a> { 11 20 ///(default: 6, min: 0, max: 1000)
+10 -1
crates/jacquard-api/src/app_bsky/feed/get_posts.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetPosts<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/app_bsky/feed/get_quotes.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetQuotes<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 13 22 pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>, 14 23 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 24 #[serde(borrow)] 25 + #[builder(into)] 16 26 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 17 27 ///(default: 50, min: 1, max: 100) 18 28 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/feed/get_reposted_by.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRepostedBy<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 13 22 pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>, 14 23 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 24 #[serde(borrow)] 25 + #[builder(into)] 16 26 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 17 27 ///(default: 50, min: 1, max: 100) 18 28 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+13 -4
crates/jacquard-api/src/app_bsky/feed/get_suggested_feeds.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestedFeeds<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 50 60 51 61 impl jacquard_common::types::xrpc::XrpcRequest for GetSuggestedFeeds<'_> { 52 62 const NSID: &'static str = "app.bsky.feed.getSuggestedFeeds"; 53 - const METHOD: jacquard_common::types::xrpc::XrpcMethod = 54 - jacquard_common::types::xrpc::XrpcMethod::Query; 63 + const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Query; 55 64 const OUTPUT_ENCODING: &'static str = "application/json"; 56 65 type Output<'de> = GetSuggestedFeedsOutput<'de>; 57 66 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 58 - } 67 + }
+12 -1
crates/jacquard-api/src/app_bsky/feed/get_timeline.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetTimeline<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub algorithm: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 25 #[serde(borrow)] 26 + #[builder(into)] 16 27 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 17 28 ///(default: 50, min: 1, max: 100) 18 29 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+16 -1
crates/jacquard-api/src/app_bsky/feed/search_posts.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchPosts<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 13 22 pub author: std::option::Option<jacquard_common::types::ident::AtIdentifier<'a>>, 14 23 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 24 #[serde(borrow)] 25 + #[builder(into)] 16 26 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub domain: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 32 pub lang: std::option::Option<jacquard_common::types::string::Language>, ··· 26 37 #[serde(borrow)] 27 38 pub mentions: std::option::Option<jacquard_common::types::ident::AtIdentifier<'a>>, 28 39 #[serde(borrow)] 40 + #[builder(into)] 29 41 pub q: jacquard_common::CowStr<'a>, 30 42 #[serde(skip_serializing_if = "std::option::Option::is_none")] 31 43 #[serde(borrow)] 44 + #[builder(into)] 32 45 pub since: std::option::Option<jacquard_common::CowStr<'a>>, 33 46 ///(default: "latest") 34 47 #[serde(skip_serializing_if = "std::option::Option::is_none")] 35 48 #[serde(borrow)] 49 + #[builder(into)] 36 50 pub sort: std::option::Option<jacquard_common::CowStr<'a>>, 37 51 #[serde(skip_serializing_if = "std::option::Option::is_none")] 38 52 #[serde(borrow)] 39 53 pub tag: std::option::Option<Vec<jacquard_common::CowStr<'a>>>, 40 54 #[serde(skip_serializing_if = "std::option::Option::is_none")] 41 55 #[serde(borrow)] 56 + #[builder(into)] 42 57 pub until: std::option::Option<jacquard_common::CowStr<'a>>, 43 58 #[serde(skip_serializing_if = "std::option::Option::is_none")] 44 59 #[serde(borrow)]
+17 -1
crates/jacquard-api/src/app_bsky/feed/send_interactions.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct SendInteractions<'a> { 12 21 #[serde(borrow)] 13 22 pub interactions: Vec<crate::app_bsky::feed::Interaction<'a>>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for SendInteractions<'_> {
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_actor_starter_packs.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetActorStarterPacks<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_blocks.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetBlocks<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_followers.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetFollowers<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_follows.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetFollows<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_known_followers.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetKnownFollowers<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_list.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetList<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_list_blocks.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetListBlocks<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_list_mutes.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetListMutes<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_lists.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetLists<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_lists_with_membership.rs
··· 28 28 } 29 29 } 30 30 31 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 31 + #[derive( 32 + serde::Serialize, 33 + serde::Deserialize, 34 + Debug, 35 + Clone, 36 + PartialEq, 37 + Eq, 38 + bon::Builder 39 + )] 40 + #[builder(start_fn = new)] 32 41 #[serde(rename_all = "camelCase")] 33 42 pub struct GetListsWithMembership<'a> { 34 43 #[serde(borrow)] 35 44 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 36 45 #[serde(skip_serializing_if = "std::option::Option::is_none")] 37 46 #[serde(borrow)] 47 + #[builder(into)] 38 48 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 39 49 ///(default: 50, min: 1, max: 100) 40 50 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_mutes.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetMutes<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+10 -1
crates/jacquard-api/src/app_bsky/graph/get_relationships.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRelationships<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/app_bsky/graph/get_starter_pack.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetStarterPack<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/app_bsky/graph/get_starter_packs.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetStarterPacks<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/app_bsky/graph/get_starter_packs_with_membership.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetStarterPacksWithMembership<'a> { 11 20 #[serde(borrow)] 12 21 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+10 -1
crates/jacquard-api/src/app_bsky/graph/get_suggested_follows_by_actor.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestedFollowsByActor<'a> { 11 20 #[serde(borrow)]
+17 -1
crates/jacquard-api/src/app_bsky/graph/mute_actor.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct MuteActor<'a> { 12 21 #[serde(borrow)] 13 22 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for MuteActor<'_> {
+17 -1
crates/jacquard-api/src/app_bsky/graph/mute_actor_list.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct MuteActorList<'a> { 12 21 #[serde(borrow)] 13 22 pub list: jacquard_common::types::string::AtUri<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for MuteActorList<'_> {
+17 -1
crates/jacquard-api/src/app_bsky/graph/mute_thread.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct MuteThread<'a> { 12 21 #[serde(borrow)] 13 22 pub root: jacquard_common::types::string::AtUri<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for MuteThread<'_> {
+12 -1
crates/jacquard-api/src/app_bsky/graph/search_starter_packs.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchStarterPacks<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 25, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 26 pub limit: std::option::Option<i64>, 17 27 #[serde(borrow)] 28 + #[builder(into)] 18 29 pub q: jacquard_common::CowStr<'a>, 19 30 } 20 31
+17 -1
crates/jacquard-api/src/app_bsky/graph/unmute_actor.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UnmuteActor<'a> { 12 21 #[serde(borrow)] 13 22 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for UnmuteActor<'_> {
+17 -1
crates/jacquard-api/src/app_bsky/graph/unmute_actor_list.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UnmuteActorList<'a> { 12 21 #[serde(borrow)] 13 22 pub list: jacquard_common::types::string::AtUri<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for UnmuteActorList<'_> {
+17 -1
crates/jacquard-api/src/app_bsky/graph/unmute_thread.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UnmuteThread<'a> { 12 21 #[serde(borrow)] 13 22 pub root: jacquard_common::types::string::AtUri<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for UnmuteThread<'_> {
+10 -1
crates/jacquard-api/src/app_bsky/labeler/get_services.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetServices<'a> { 11 20 ///(default: false)
+10 -1
crates/jacquard-api/src/app_bsky/notification/get_preferences.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetPreferences {} 11 20 impl jacquard_common::IntoStatic for GetPreferences {
+10 -1
crates/jacquard-api/src/app_bsky/notification/get_unread_count.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetUnreadCount { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/notification/list_activity_subscriptions.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListActivitySubscriptions<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/notification/list_notifications.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListNotifications<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+17 -1
crates/jacquard-api/src/app_bsky/notification/put_activity_subscription.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct PutActivitySubscription<'a> { 12 21 #[serde(borrow)] 13 22 pub activity_subscription: crate::app_bsky::notification::ActivitySubscription<'a>, 14 23 #[serde(borrow)] 15 24 pub subject: jacquard_common::types::string::Did<'a>, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 16 32 } 17 33 18 34 impl jacquard_common::IntoStatic for PutActivitySubscription<'_> {
+17 -1
crates/jacquard-api/src/app_bsky/notification/put_preferences.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct PutPreferences<'a> { 12 21 pub priority: bool, 22 + #[serde(flatten)] 23 + #[serde(borrow)] 24 + #[builder(default)] 25 + pub extra_data: ::std::collections::BTreeMap< 26 + ::jacquard_common::smol_str::SmolStr, 27 + ::jacquard_common::types::value::Data<'a>, 28 + >, 13 29 } 14 30 15 31 impl jacquard_common::IntoStatic for PutPreferences<'_> {
+17 -1
crates/jacquard-api/src/app_bsky/notification/put_preferences_v2.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct PutPreferencesV2<'a> { 12 21 #[serde(skip_serializing_if = "std::option::Option::is_none")] 13 22 #[serde(borrow)] ··· 68 77 #[serde(skip_serializing_if = "std::option::Option::is_none")] 69 78 #[serde(borrow)] 70 79 pub verified: std::option::Option<crate::app_bsky::notification::Preference<'a>>, 80 + #[serde(flatten)] 81 + #[serde(borrow)] 82 + #[builder(default)] 83 + pub extra_data: ::std::collections::BTreeMap< 84 + ::jacquard_common::smol_str::SmolStr, 85 + ::jacquard_common::types::value::Data<'a>, 86 + >, 71 87 } 72 88 73 89 impl jacquard_common::IntoStatic for PutPreferencesV2<'_> {
+20 -1
crates/jacquard-api/src/app_bsky/notification/register_push.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RegisterPush<'a> { 12 21 ///Set to true when the actor is age restricted 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 pub age_restricted: std::option::Option<bool>, 15 24 #[serde(borrow)] 25 + #[builder(into)] 16 26 pub app_id: jacquard_common::CowStr<'a>, 17 27 #[serde(borrow)] 28 + #[builder(into)] 18 29 pub platform: jacquard_common::CowStr<'a>, 19 30 #[serde(borrow)] 20 31 pub service_did: jacquard_common::types::string::Did<'a>, 21 32 #[serde(borrow)] 33 + #[builder(into)] 22 34 pub token: jacquard_common::CowStr<'a>, 35 + #[serde(flatten)] 36 + #[serde(borrow)] 37 + #[builder(default)] 38 + pub extra_data: ::std::collections::BTreeMap< 39 + ::jacquard_common::smol_str::SmolStr, 40 + ::jacquard_common::types::value::Data<'a>, 41 + >, 23 42 } 24 43 25 44 impl jacquard_common::IntoStatic for RegisterPush<'_> {
+20 -1
crates/jacquard-api/src/app_bsky/notification/unregister_push.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UnregisterPush<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub app_id: jacquard_common::CowStr<'a>, 14 24 #[serde(borrow)] 25 + #[builder(into)] 15 26 pub platform: jacquard_common::CowStr<'a>, 16 27 #[serde(borrow)] 17 28 pub service_did: jacquard_common::types::string::Did<'a>, 18 29 #[serde(borrow)] 30 + #[builder(into)] 19 31 pub token: jacquard_common::CowStr<'a>, 32 + #[serde(flatten)] 33 + #[serde(borrow)] 34 + #[builder(default)] 35 + pub extra_data: ::std::collections::BTreeMap< 36 + ::jacquard_common::smol_str::SmolStr, 37 + ::jacquard_common::types::value::Data<'a>, 38 + >, 20 39 } 21 40 22 41 impl jacquard_common::IntoStatic for UnregisterPush<'_> {
+17 -1
crates/jacquard-api/src/app_bsky/notification/update_seen.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateSeen<'a> { 12 21 pub seen_at: jacquard_common::types::string::Datetime, 22 + #[serde(flatten)] 23 + #[serde(borrow)] 24 + #[builder(default)] 25 + pub extra_data: ::std::collections::BTreeMap< 26 + ::jacquard_common::smol_str::SmolStr, 27 + ::jacquard_common::types::value::Data<'a>, 28 + >, 13 29 } 14 30 15 31 impl jacquard_common::IntoStatic for UpdateSeen<'_> {
+12 -4
crates/jacquard-api/src/app_bsky/unspecced/get_onboarding_suggested_starter_packs.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetOnboardingSuggestedStarterPacks { 11 20 ///(default: 10, min: 1, max: 25) ··· 40 49 41 50 impl jacquard_common::types::xrpc::XrpcRequest for GetOnboardingSuggestedStarterPacks { 42 51 const NSID: &'static str = "app.bsky.unspecced.getOnboardingSuggestedStarterPacks"; 43 - const METHOD: jacquard_common::types::xrpc::XrpcMethod = 44 - jacquard_common::types::xrpc::XrpcMethod::Query; 52 + const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Query; 45 53 const OUTPUT_ENCODING: &'static str = "application/json"; 46 54 type Output<'de> = GetOnboardingSuggestedStarterPacksOutput<'de>; 47 55 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 48 - } 56 + }
+10 -1
crates/jacquard-api/src/app_bsky/unspecced/get_onboarding_suggested_starter_packs_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetOnboardingSuggestedStarterPacksSkeleton<'a> { 11 20 ///(default: 10, min: 1, max: 25)
+10 -1
crates/jacquard-api/src/app_bsky/unspecced/get_post_thread_other_v2.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetPostThreadOtherV2<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/app_bsky/unspecced/get_post_thread_v2.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetPostThreadV2<'a> { 11 20 ///(default: true) ··· 25 34 ///(default: "oldest") 26 35 #[serde(skip_serializing_if = "std::option::Option::is_none")] 27 36 #[serde(borrow)] 37 + #[builder(into)] 28 38 pub sort: std::option::Option<jacquard_common::CowStr<'a>>, 29 39 } 30 40
+10 -1
crates/jacquard-api/src/app_bsky/unspecced/get_suggested_feeds.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestedFeeds { 11 20 ///(default: 10, min: 1, max: 25)
+10 -1
crates/jacquard-api/src/app_bsky/unspecced/get_suggested_feeds_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestedFeedsSkeleton<'a> { 11 20 ///(default: 10, min: 1, max: 25)
+10 -1
crates/jacquard-api/src/app_bsky/unspecced/get_suggested_starter_packs.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestedStarterPacks { 11 20 ///(default: 10, min: 1, max: 25)
+10 -1
crates/jacquard-api/src/app_bsky/unspecced/get_suggested_starter_packs_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestedStarterPacksSkeleton<'a> { 11 20 ///(default: 10, min: 1, max: 25)
+11 -1
crates/jacquard-api/src/app_bsky/unspecced/get_suggested_users.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestedUsers<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub category: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 25, min: 1, max: 50) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/unspecced/get_suggested_users_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestedUsersSkeleton<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub category: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 25, min: 1, max: 50) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/app_bsky/unspecced/get_suggestions_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSuggestionsSkeleton<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+10 -1
crates/jacquard-api/src/app_bsky/unspecced/get_tagged_suggestions.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetTaggedSuggestions {} 11 20 impl jacquard_common::IntoStatic for GetTaggedSuggestions {
+10 -1
crates/jacquard-api/src/app_bsky/unspecced/get_trends.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetTrends { 11 20 ///(default: 10, min: 1, max: 25)
+20 -1
crates/jacquard-api/src/app_bsky/unspecced/init_age_assurance.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct InitAgeAssurance<'a> { 12 21 ///An ISO 3166-1 alpha-2 code of the user's location. 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub country_code: jacquard_common::CowStr<'a>, 15 25 ///The user's email address to receive assurance instructions. 16 26 #[serde(borrow)] 27 + #[builder(into)] 17 28 pub email: jacquard_common::CowStr<'a>, 18 29 ///The user's preferred language for communication during the assurance process. 19 30 #[serde(borrow)] 31 + #[builder(into)] 20 32 pub language: jacquard_common::CowStr<'a>, 33 + #[serde(flatten)] 34 + #[serde(borrow)] 35 + #[builder(default)] 36 + pub extra_data: ::std::collections::BTreeMap< 37 + ::jacquard_common::smol_str::SmolStr, 38 + ::jacquard_common::types::value::Data<'a>, 39 + >, 21 40 } 22 41 23 42 impl jacquard_common::IntoStatic for InitAgeAssurance<'_> {
+12 -1
crates/jacquard-api/src/app_bsky/unspecced/search_actors_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchActorsSkeleton<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 25, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 26 pub limit: std::option::Option<i64>, 17 27 #[serde(borrow)] 28 + #[builder(into)] 18 29 pub q: jacquard_common::CowStr<'a>, 19 30 #[serde(skip_serializing_if = "std::option::Option::is_none")] 20 31 pub typeahead: std::option::Option<bool>,
+16 -1
crates/jacquard-api/src/app_bsky/unspecced/search_posts_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchPostsSkeleton<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 13 22 pub author: std::option::Option<jacquard_common::types::ident::AtIdentifier<'a>>, 14 23 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 24 #[serde(borrow)] 25 + #[builder(into)] 16 26 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub domain: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 32 pub lang: std::option::Option<jacquard_common::types::string::Language>, ··· 26 37 #[serde(borrow)] 27 38 pub mentions: std::option::Option<jacquard_common::types::ident::AtIdentifier<'a>>, 28 39 #[serde(borrow)] 40 + #[builder(into)] 29 41 pub q: jacquard_common::CowStr<'a>, 30 42 #[serde(skip_serializing_if = "std::option::Option::is_none")] 31 43 #[serde(borrow)] 44 + #[builder(into)] 32 45 pub since: std::option::Option<jacquard_common::CowStr<'a>>, 33 46 ///(default: "latest") 34 47 #[serde(skip_serializing_if = "std::option::Option::is_none")] 35 48 #[serde(borrow)] 49 + #[builder(into)] 36 50 pub sort: std::option::Option<jacquard_common::CowStr<'a>>, 37 51 #[serde(skip_serializing_if = "std::option::Option::is_none")] 38 52 #[serde(borrow)] 39 53 pub tag: std::option::Option<Vec<jacquard_common::CowStr<'a>>>, 40 54 #[serde(skip_serializing_if = "std::option::Option::is_none")] 41 55 #[serde(borrow)] 56 + #[builder(into)] 42 57 pub until: std::option::Option<jacquard_common::CowStr<'a>>, 43 58 #[serde(skip_serializing_if = "std::option::Option::is_none")] 44 59 #[serde(borrow)]
+12 -1
crates/jacquard-api/src/app_bsky/unspecced/search_starter_packs_skeleton.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchStarterPacksSkeleton<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 25, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 26 pub limit: std::option::Option<i64>, 17 27 #[serde(borrow)] 28 + #[builder(into)] 18 29 pub q: jacquard_common::CowStr<'a>, 19 30 #[serde(skip_serializing_if = "std::option::Option::is_none")] 20 31 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/app_bsky/video/get_job_status.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetJobStatus<'a> { 11 20 #[serde(borrow)] 21 + #[builder(into)] 12 22 pub job_id: jacquard_common::CowStr<'a>, 13 23 } 14 24
+21 -9
crates/jacquard-api/src/app_bsky/video/upload_video.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 10 18 #[serde(rename_all = "camelCase")] 11 - pub struct UploadVideo<'a> {} 12 - impl jacquard_common::IntoStatic for UploadVideo<'_> { 13 - type Output = UploadVideo<'static>; 19 + pub struct UploadVideo { 20 + pub body: bytes::Bytes, 21 + } 22 + 23 + impl jacquard_common::IntoStatic for UploadVideo { 24 + type Output = UploadVideo; 14 25 fn into_static(self) -> Self::Output { 15 - UploadVideo { 16 - extra_data: self.extra_data.into_static(), 17 - } 26 + self 18 27 } 19 28 } 20 29 ··· 36 45 } 37 46 } 38 47 39 - impl jacquard_common::types::xrpc::XrpcRequest for UploadVideo<'_> { 48 + impl jacquard_common::types::xrpc::XrpcRequest for UploadVideo { 40 49 const NSID: &'static str = "app.bsky.video.uploadVideo"; 41 50 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 42 51 "video/mp4", ··· 44 53 const OUTPUT_ENCODING: &'static str = "application/json"; 45 54 type Output<'de> = UploadVideoOutput<'de>; 46 55 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 56 + fn encode_body(&self) -> Result<Vec<u8>, jacquard_common::types::xrpc::EncodeError> { 57 + Ok(self.body.to_vec()) 58 + } 47 59 }
+18 -1
crates/jacquard-api/src/chat_bsky/convo/accept_convo.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct AcceptConvo<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for AcceptConvo<'_> {
+20 -1
crates/jacquard-api/src/chat_bsky/convo/add_reaction.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct AddReaction<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 14 24 #[serde(borrow)] 25 + #[builder(into)] 15 26 pub message_id: jacquard_common::CowStr<'a>, 16 27 #[serde(borrow)] 28 + #[builder(into)] 17 29 pub value: jacquard_common::CowStr<'a>, 30 + #[serde(flatten)] 31 + #[serde(borrow)] 32 + #[builder(default)] 33 + pub extra_data: ::std::collections::BTreeMap< 34 + ::jacquard_common::smol_str::SmolStr, 35 + ::jacquard_common::types::value::Data<'a>, 36 + >, 18 37 } 19 38 20 39 impl jacquard_common::IntoStatic for AddReaction<'_> {
+19 -1
crates/jacquard-api/src/chat_bsky/convo/delete_message_for_self.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteMessageForSelf<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 14 24 #[serde(borrow)] 25 + #[builder(into)] 15 26 pub message_id: jacquard_common::CowStr<'a>, 27 + #[serde(flatten)] 28 + #[serde(borrow)] 29 + #[builder(default)] 30 + pub extra_data: ::std::collections::BTreeMap< 31 + ::jacquard_common::smol_str::SmolStr, 32 + ::jacquard_common::types::value::Data<'a>, 33 + >, 16 34 } 17 35 18 36 impl jacquard_common::IntoStatic for DeleteMessageForSelf<'_> {
+11 -1
crates/jacquard-api/src/chat_bsky/convo/get_convo.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetConvo<'a> { 11 20 #[serde(borrow)] 21 + #[builder(into)] 12 22 pub convo_id: jacquard_common::CowStr<'a>, 13 23 } 14 24
+10 -1
crates/jacquard-api/src/chat_bsky/convo/get_convo_availability.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetConvoAvailability<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/chat_bsky/convo/get_convo_for_members.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetConvoForMembers<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/chat_bsky/convo/get_log.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetLog<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 } 15 25
+12 -1
crates/jacquard-api/src/chat_bsky/convo/get_messages.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetMessages<'a> { 11 20 #[serde(borrow)] 21 + #[builder(into)] 12 22 pub convo_id: jacquard_common::CowStr<'a>, 13 23 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 24 #[serde(borrow)] 25 + #[builder(into)] 15 26 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 27 ///(default: 50, min: 1, max: 100) 17 28 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+18 -1
crates/jacquard-api/src/chat_bsky/convo/leave_convo.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct LeaveConvo<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for LeaveConvo<'_> {
+13 -1
crates/jacquard-api/src/chat_bsky/convo/list_convos.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListConvos<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 26 pub limit: std::option::Option<i64>, 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub read_state: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 32 #[serde(borrow)] 33 + #[builder(into)] 22 34 pub status: std::option::Option<jacquard_common::CowStr<'a>>, 23 35 } 24 36
+18 -1
crates/jacquard-api/src/chat_bsky/convo/mute_convo.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct MuteConvo<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for MuteConvo<'_> {
+20 -1
crates/jacquard-api/src/chat_bsky/convo/remove_reaction.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RemoveReaction<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 14 24 #[serde(borrow)] 25 + #[builder(into)] 15 26 pub message_id: jacquard_common::CowStr<'a>, 16 27 #[serde(borrow)] 28 + #[builder(into)] 17 29 pub value: jacquard_common::CowStr<'a>, 30 + #[serde(flatten)] 31 + #[serde(borrow)] 32 + #[builder(default)] 33 + pub extra_data: ::std::collections::BTreeMap< 34 + ::jacquard_common::smol_str::SmolStr, 35 + ::jacquard_common::types::value::Data<'a>, 36 + >, 18 37 } 19 38 20 39 impl jacquard_common::IntoStatic for RemoveReaction<'_> {
+18 -1
crates/jacquard-api/src/chat_bsky/convo/send_message.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct SendMessage<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 14 24 #[serde(borrow)] 15 25 pub message: crate::chat_bsky::convo::MessageInput<'a>, 26 + #[serde(flatten)] 27 + #[serde(borrow)] 28 + #[builder(default)] 29 + pub extra_data: ::std::collections::BTreeMap< 30 + ::jacquard_common::smol_str::SmolStr, 31 + ::jacquard_common::types::value::Data<'a>, 32 + >, 16 33 } 17 34 18 35 impl jacquard_common::IntoStatic for SendMessage<'_> {
+17 -1
crates/jacquard-api/src/chat_bsky/convo/send_message_batch.rs
··· 27 27 } 28 28 29 29 #[jacquard_derive::lexicon] 30 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 30 + #[derive( 31 + serde::Serialize, 32 + serde::Deserialize, 33 + Debug, 34 + Clone, 35 + PartialEq, 36 + Eq, 37 + bon::Builder 38 + )] 31 39 #[serde(rename_all = "camelCase")] 40 + #[builder(start_fn = new)] 32 41 pub struct SendMessageBatch<'a> { 33 42 #[serde(borrow)] 34 43 pub items: Vec<jacquard_common::types::value::Data<'a>>, 44 + #[serde(flatten)] 45 + #[serde(borrow)] 46 + #[builder(default)] 47 + pub extra_data: ::std::collections::BTreeMap< 48 + ::jacquard_common::smol_str::SmolStr, 49 + ::jacquard_common::types::value::Data<'a>, 50 + >, 35 51 } 36 52 37 53 impl jacquard_common::IntoStatic for SendMessageBatch<'_> {
+18 -1
crates/jacquard-api/src/chat_bsky/convo/unmute_convo.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UnmuteConvo<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for UnmuteConvo<'_> {
+18 -1
crates/jacquard-api/src/chat_bsky/convo/update_all_read.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateAllRead<'a> { 12 21 #[serde(skip_serializing_if = "std::option::Option::is_none")] 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub status: std::option::Option<jacquard_common::CowStr<'a>>, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 15 32 } 16 33 17 34 impl jacquard_common::IntoStatic for UpdateAllRead<'_> {
+19 -1
crates/jacquard-api/src/chat_bsky/convo/update_read.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateRead<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub convo_id: jacquard_common::CowStr<'a>, 14 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 25 #[serde(borrow)] 26 + #[builder(into)] 16 27 pub message_id: std::option::Option<jacquard_common::CowStr<'a>>, 28 + #[serde(flatten)] 29 + #[serde(borrow)] 30 + #[builder(default)] 31 + pub extra_data: ::std::collections::BTreeMap< 32 + ::jacquard_common::smol_str::SmolStr, 33 + ::jacquard_common::types::value::Data<'a>, 34 + >, 17 35 } 18 36 19 37 impl jacquard_common::IntoStatic for UpdateRead<'_> {
+10 -1
crates/jacquard-api/src/chat_bsky/moderation/get_actor_metadata.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetActorMetadata<'a> { 11 20 #[serde(borrow)]
+12 -1
crates/jacquard-api/src/chat_bsky/moderation/get_message_context.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetMessageContext<'a> { 11 20 ///(default: 5) ··· 16 25 pub before: std::option::Option<i64>, 17 26 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 27 #[serde(borrow)] 28 + #[builder(into)] 19 29 pub convo_id: std::option::Option<jacquard_common::CowStr<'a>>, 20 30 #[serde(borrow)] 31 + #[builder(into)] 21 32 pub message_id: jacquard_common::CowStr<'a>, 22 33 } 23 34
+18 -1
crates/jacquard-api/src/chat_bsky/moderation/update_actor_access.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateActorAccess<'a> { 12 21 #[serde(borrow)] 13 22 pub actor: jacquard_common::types::string::Did<'a>, 14 23 pub allow_access: bool, 15 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 25 #[serde(borrow)] 26 + #[builder(into)] 17 27 pub r#ref: std::option::Option<jacquard_common::CowStr<'a>>, 28 + #[serde(flatten)] 29 + #[serde(borrow)] 30 + #[builder(default)] 31 + pub extra_data: ::std::collections::BTreeMap< 32 + ::jacquard_common::smol_str::SmolStr, 33 + ::jacquard_common::types::value::Data<'a>, 34 + >, 18 35 } 19 36 20 37 impl jacquard_common::IntoStatic for UpdateActorAccess<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/admin/delete_account.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteAccount<'a> { 12 21 #[serde(borrow)] 13 22 pub did: jacquard_common::types::string::Did<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for DeleteAccount<'_> {
+18 -1
crates/jacquard-api/src/com_atproto/admin/disable_account_invites.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DisableAccountInvites<'a> { 12 21 #[serde(borrow)] 13 22 pub account: jacquard_common::types::string::Did<'a>, 14 23 ///Optional reason for disabled invites. 15 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 25 #[serde(borrow)] 26 + #[builder(into)] 17 27 pub note: std::option::Option<jacquard_common::CowStr<'a>>, 28 + #[serde(flatten)] 29 + #[serde(borrow)] 30 + #[builder(default)] 31 + pub extra_data: ::std::collections::BTreeMap< 32 + ::jacquard_common::smol_str::SmolStr, 33 + ::jacquard_common::types::value::Data<'a>, 34 + >, 18 35 } 19 36 20 37 impl jacquard_common::IntoStatic for DisableAccountInvites<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/admin/disable_invite_codes.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DisableInviteCodes<'a> { 12 21 #[serde(skip_serializing_if = "std::option::Option::is_none")] 13 22 #[serde(borrow)] ··· 15 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 25 #[serde(borrow)] 17 26 pub codes: std::option::Option<Vec<jacquard_common::CowStr<'a>>>, 27 + #[serde(flatten)] 28 + #[serde(borrow)] 29 + #[builder(default)] 30 + pub extra_data: ::std::collections::BTreeMap< 31 + ::jacquard_common::smol_str::SmolStr, 32 + ::jacquard_common::types::value::Data<'a>, 33 + >, 18 34 } 19 35 20 36 impl jacquard_common::IntoStatic for DisableInviteCodes<'_> {
+18 -1
crates/jacquard-api/src/com_atproto/admin/enable_account_invites.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct EnableAccountInvites<'a> { 12 21 #[serde(borrow)] 13 22 pub account: jacquard_common::types::string::Did<'a>, 14 23 ///Optional reason for enabled invites. 15 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 25 #[serde(borrow)] 26 + #[builder(into)] 17 27 pub note: std::option::Option<jacquard_common::CowStr<'a>>, 28 + #[serde(flatten)] 29 + #[serde(borrow)] 30 + #[builder(default)] 31 + pub extra_data: ::std::collections::BTreeMap< 32 + ::jacquard_common::smol_str::SmolStr, 33 + ::jacquard_common::types::value::Data<'a>, 34 + >, 18 35 } 19 36 20 37 impl jacquard_common::IntoStatic for EnableAccountInvites<'_> {
+10 -1
crates/jacquard-api/src/com_atproto/admin/get_account_info.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetAccountInfo<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/admin/get_account_infos.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetAccountInfos<'a> { 11 20 #[serde(borrow)]
+12 -1
crates/jacquard-api/src/com_atproto/admin/get_invite_codes.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetInviteCodes<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 100, min: 1, max: 500) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 17 27 ///(default: "recent") 18 28 #[serde(skip_serializing_if = "std::option::Option::is_none")] 19 29 #[serde(borrow)] 30 + #[builder(into)] 20 31 pub sort: std::option::Option<jacquard_common::CowStr<'a>>, 21 32 } 22 33
+10 -1
crates/jacquard-api/src/com_atproto/admin/get_subject_status.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSubjectStatus<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+12 -1
crates/jacquard-api/src/com_atproto/admin/search_accounts.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchAccounts<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 25 #[serde(borrow)] 26 + #[builder(into)] 16 27 pub email: std::option::Option<jacquard_common::CowStr<'a>>, 17 28 ///(default: 50, min: 1, max: 100) 18 29 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+20 -1
crates/jacquard-api/src/com_atproto/admin/send_email.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct SendEmail<'a> { 12 21 ///Additional comment by the sender that won't be used in the email itself but helpful to provide more context for moderators/reviewers 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub comment: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 #[serde(borrow)] 27 + #[builder(into)] 17 28 pub content: jacquard_common::CowStr<'a>, 18 29 #[serde(borrow)] 19 30 pub recipient_did: jacquard_common::types::string::Did<'a>, ··· 21 32 pub sender_did: jacquard_common::types::string::Did<'a>, 22 33 #[serde(skip_serializing_if = "std::option::Option::is_none")] 23 34 #[serde(borrow)] 35 + #[builder(into)] 24 36 pub subject: std::option::Option<jacquard_common::CowStr<'a>>, 37 + #[serde(flatten)] 38 + #[serde(borrow)] 39 + #[builder(default)] 40 + pub extra_data: ::std::collections::BTreeMap< 41 + ::jacquard_common::smol_str::SmolStr, 42 + ::jacquard_common::types::value::Data<'a>, 43 + >, 25 44 } 26 45 27 46 impl jacquard_common::IntoStatic for SendEmail<'_> {
+18 -1
crates/jacquard-api/src/com_atproto/admin/update_account_email.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateAccountEmail<'a> { 12 21 ///The handle or DID of the repo. 13 22 #[serde(borrow)] 14 23 pub account: jacquard_common::types::ident::AtIdentifier<'a>, 15 24 #[serde(borrow)] 25 + #[builder(into)] 16 26 pub email: jacquard_common::CowStr<'a>, 27 + #[serde(flatten)] 28 + #[serde(borrow)] 29 + #[builder(default)] 30 + pub extra_data: ::std::collections::BTreeMap< 31 + ::jacquard_common::smol_str::SmolStr, 32 + ::jacquard_common::types::value::Data<'a>, 33 + >, 17 34 } 18 35 19 36 impl jacquard_common::IntoStatic for UpdateAccountEmail<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/admin/update_account_handle.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateAccountHandle<'a> { 12 21 #[serde(borrow)] 13 22 pub did: jacquard_common::types::string::Did<'a>, 14 23 #[serde(borrow)] 15 24 pub handle: jacquard_common::types::string::Handle<'a>, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 16 32 } 17 33 18 34 impl jacquard_common::IntoStatic for UpdateAccountHandle<'_> {
+18 -1
crates/jacquard-api/src/com_atproto/admin/update_account_password.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateAccountPassword<'a> { 12 21 #[serde(borrow)] 13 22 pub did: jacquard_common::types::string::Did<'a>, 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub password: jacquard_common::CowStr<'a>, 26 + #[serde(flatten)] 27 + #[serde(borrow)] 28 + #[builder(default)] 29 + pub extra_data: ::std::collections::BTreeMap< 30 + ::jacquard_common::smol_str::SmolStr, 31 + ::jacquard_common::types::value::Data<'a>, 32 + >, 16 33 } 17 34 18 35 impl jacquard_common::IntoStatic for UpdateAccountPassword<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/admin/update_account_signing_key.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateAccountSigningKey<'a> { 12 21 #[serde(borrow)] 13 22 pub did: jacquard_common::types::string::Did<'a>, 14 23 ///Did-key formatted public key 15 24 #[serde(borrow)] 16 25 pub signing_key: jacquard_common::types::string::Did<'a>, 26 + #[serde(flatten)] 27 + #[serde(borrow)] 28 + #[builder(default)] 29 + pub extra_data: ::std::collections::BTreeMap< 30 + ::jacquard_common::smol_str::SmolStr, 31 + ::jacquard_common::types::value::Data<'a>, 32 + >, 17 33 } 18 34 19 35 impl jacquard_common::IntoStatic for UpdateAccountSigningKey<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/admin/update_subject_status.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateSubjectStatus<'a> { 12 21 #[serde(skip_serializing_if = "std::option::Option::is_none")] 13 22 #[serde(borrow)] ··· 17 26 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 27 #[serde(borrow)] 19 28 pub takedown: std::option::Option<crate::com_atproto::admin::StatusAttr<'a>>, 29 + #[serde(flatten)] 30 + #[serde(borrow)] 31 + #[builder(default)] 32 + pub extra_data: ::std::collections::BTreeMap< 33 + ::jacquard_common::smol_str::SmolStr, 34 + ::jacquard_common::types::value::Data<'a>, 35 + >, 20 36 } 21 37 22 38 #[jacquard_derive::open_union]
+17 -1
crates/jacquard-api/src/com_atproto/identity/refresh_identity.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RefreshIdentity<'a> { 12 21 #[serde(borrow)] 13 22 pub identifier: jacquard_common::types::ident::AtIdentifier<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for RefreshIdentity<'_> {
+10 -1
crates/jacquard-api/src/com_atproto/identity/resolve_did.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ResolveDid<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/identity/resolve_handle.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ResolveHandle<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/identity/resolve_identity.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ResolveIdentity<'a> { 11 20 #[serde(borrow)]
+18 -1
crates/jacquard-api/src/com_atproto/identity/sign_plc_operation.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct SignPlcOperation<'a> { 12 21 #[serde(skip_serializing_if = "std::option::Option::is_none")] 13 22 #[serde(borrow)] ··· 21 30 ///A token received through com.atproto.identity.requestPlcOperationSignature 22 31 #[serde(skip_serializing_if = "std::option::Option::is_none")] 23 32 #[serde(borrow)] 33 + #[builder(into)] 24 34 pub token: std::option::Option<jacquard_common::CowStr<'a>>, 25 35 #[serde(skip_serializing_if = "std::option::Option::is_none")] 26 36 #[serde(borrow)] 27 37 pub verification_methods: std::option::Option< 28 38 jacquard_common::types::value::Data<'a>, 39 + >, 40 + #[serde(flatten)] 41 + #[serde(borrow)] 42 + #[builder(default)] 43 + pub extra_data: ::std::collections::BTreeMap< 44 + ::jacquard_common::smol_str::SmolStr, 45 + ::jacquard_common::types::value::Data<'a>, 29 46 >, 30 47 } 31 48
+17 -1
crates/jacquard-api/src/com_atproto/identity/submit_plc_operation.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct SubmitPlcOperation<'a> { 12 21 #[serde(borrow)] 13 22 pub operation: jacquard_common::types::value::Data<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for SubmitPlcOperation<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/identity/update_handle.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateHandle<'a> { 12 21 ///The new handle. 13 22 #[serde(borrow)] 14 23 pub handle: jacquard_common::types::string::Handle<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 15 31 } 16 32 17 33 impl jacquard_common::IntoStatic for UpdateHandle<'_> {
+11 -1
crates/jacquard-api/src/com_atproto/label/query_labels.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct QueryLabels<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 250) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+10 -1
crates/jacquard-api/src/com_atproto/label/subscribe_labels.rs
··· 47 47 } 48 48 } 49 49 50 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 50 + #[derive( 51 + serde::Serialize, 52 + serde::Deserialize, 53 + Debug, 54 + Clone, 55 + PartialEq, 56 + Eq, 57 + bon::Builder 58 + )] 59 + #[builder(start_fn = new)] 51 60 #[serde(rename_all = "camelCase")] 52 61 pub struct SubscribeLabels { 53 62 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+18 -1
crates/jacquard-api/src/com_atproto/moderation/create_report.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct CreateReport<'a> { 12 21 #[serde(skip_serializing_if = "std::option::Option::is_none")] 13 22 #[serde(borrow)] ··· 15 24 ///Additional context about the content and violation. 16 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 17 26 #[serde(borrow)] 27 + #[builder(into)] 18 28 pub reason: std::option::Option<jacquard_common::CowStr<'a>>, 19 29 ///Indicates the broad category of violation the report is for. 20 30 #[serde(borrow)] 21 31 pub reason_type: crate::com_atproto::moderation::ReasonType<'a>, 22 32 #[serde(borrow)] 23 33 pub subject: CreateReportRecordSubject<'a>, 34 + #[serde(flatten)] 35 + #[serde(borrow)] 36 + #[builder(default)] 37 + pub extra_data: ::std::collections::BTreeMap< 38 + ::jacquard_common::smol_str::SmolStr, 39 + ::jacquard_common::types::value::Data<'a>, 40 + >, 24 41 } 25 42 26 43 #[jacquard_derive::open_union]
+17 -1
crates/jacquard-api/src/com_atproto/repo/apply_writes.rs
··· 99 99 } 100 100 101 101 #[jacquard_derive::lexicon] 102 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 102 + #[derive( 103 + serde::Serialize, 104 + serde::Deserialize, 105 + Debug, 106 + Clone, 107 + PartialEq, 108 + Eq, 109 + bon::Builder 110 + )] 103 111 #[serde(rename_all = "camelCase")] 112 + #[builder(start_fn = new)] 104 113 pub struct ApplyWrites<'a> { 105 114 ///The handle or DID of the repo (aka, current account). 106 115 #[serde(borrow)] ··· 114 123 pub validate: std::option::Option<bool>, 115 124 #[serde(borrow)] 116 125 pub writes: Vec<jacquard_common::types::value::Data<'a>>, 126 + #[serde(flatten)] 127 + #[serde(borrow)] 128 + #[builder(default)] 129 + pub extra_data: ::std::collections::BTreeMap< 130 + ::jacquard_common::smol_str::SmolStr, 131 + ::jacquard_common::types::value::Data<'a>, 132 + >, 117 133 } 118 134 119 135 impl jacquard_common::IntoStatic for ApplyWrites<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/repo/create_record.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct CreateRecord<'a> { 12 21 ///The NSID of the record collection. 13 22 #[serde(borrow)] ··· 33 42 ///Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons. 34 43 #[serde(skip_serializing_if = "std::option::Option::is_none")] 35 44 pub validate: std::option::Option<bool>, 45 + #[serde(flatten)] 46 + #[serde(borrow)] 47 + #[builder(default)] 48 + pub extra_data: ::std::collections::BTreeMap< 49 + ::jacquard_common::smol_str::SmolStr, 50 + ::jacquard_common::types::value::Data<'a>, 51 + >, 36 52 } 37 53 38 54 impl jacquard_common::IntoStatic for CreateRecord<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/repo/delete_record.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteRecord<'a> { 12 21 ///The NSID of the record collection. 13 22 #[serde(borrow)] ··· 28 37 #[serde(skip_serializing_if = "std::option::Option::is_none")] 29 38 #[serde(borrow)] 30 39 pub swap_record: std::option::Option<jacquard_common::types::string::Cid<'a>>, 40 + #[serde(flatten)] 41 + #[serde(borrow)] 42 + #[builder(default)] 43 + pub extra_data: ::std::collections::BTreeMap< 44 + ::jacquard_common::smol_str::SmolStr, 45 + ::jacquard_common::types::value::Data<'a>, 46 + >, 31 47 } 32 48 33 49 impl jacquard_common::IntoStatic for DeleteRecord<'_> {
+10 -1
crates/jacquard-api/src/com_atproto/repo/describe_repo.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct DescribeRepo<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/repo/get_record.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRecord<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+21 -9
crates/jacquard-api/src/com_atproto/repo/import_repo.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 10 18 #[serde(rename_all = "camelCase")] 11 - pub struct ImportRepo<'a> {} 12 - impl jacquard_common::IntoStatic for ImportRepo<'_> { 13 - type Output = ImportRepo<'static>; 19 + pub struct ImportRepo { 20 + pub body: bytes::Bytes, 21 + } 22 + 23 + impl jacquard_common::IntoStatic for ImportRepo { 24 + type Output = ImportRepo; 14 25 fn into_static(self) -> Self::Output { 15 - ImportRepo { 16 - extra_data: self.extra_data.into_static(), 17 - } 26 + self 18 27 } 19 28 } 20 29 21 - impl jacquard_common::types::xrpc::XrpcRequest for ImportRepo<'_> { 30 + impl jacquard_common::types::xrpc::XrpcRequest for ImportRepo { 22 31 const NSID: &'static str = "com.atproto.repo.importRepo"; 23 32 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 24 33 "application/vnd.ipld.car", ··· 26 35 const OUTPUT_ENCODING: &'static str = "application/json"; 27 36 type Output<'de> = (); 28 37 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 38 + fn encode_body(&self) -> Result<Vec<u8>, jacquard_common::types::xrpc::EncodeError> { 39 + Ok(self.body.to_vec()) 40 + } 29 41 }
+11 -1
crates/jacquard-api/src/com_atproto/repo/list_missing_blobs.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListMissingBlobs<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 500, min: 1, max: 1000) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/com_atproto/repo/list_records.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListRecords<'a> { 11 20 #[serde(borrow)] 12 21 pub collection: jacquard_common::types::string::Nsid<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 50, min: 1, max: 100) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+17 -1
crates/jacquard-api/src/com_atproto/repo/put_record.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct PutRecord<'a> { 12 21 ///The NSID of the record collection. 13 22 #[serde(borrow)] ··· 34 43 ///Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons. 35 44 #[serde(skip_serializing_if = "std::option::Option::is_none")] 36 45 pub validate: std::option::Option<bool>, 46 + #[serde(flatten)] 47 + #[serde(borrow)] 48 + #[builder(default)] 49 + pub extra_data: ::std::collections::BTreeMap< 50 + ::jacquard_common::smol_str::SmolStr, 51 + ::jacquard_common::types::value::Data<'a>, 52 + >, 37 53 } 38 54 39 55 impl jacquard_common::IntoStatic for PutRecord<'_> {
+21 -9
crates/jacquard-api/src/com_atproto/repo/upload_blob.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 10 18 #[serde(rename_all = "camelCase")] 11 - pub struct UploadBlob<'a> {} 12 - impl jacquard_common::IntoStatic for UploadBlob<'_> { 13 - type Output = UploadBlob<'static>; 19 + pub struct UploadBlob { 20 + pub body: bytes::Bytes, 21 + } 22 + 23 + impl jacquard_common::IntoStatic for UploadBlob { 24 + type Output = UploadBlob; 14 25 fn into_static(self) -> Self::Output { 15 - UploadBlob { 16 - extra_data: self.extra_data.into_static(), 17 - } 26 + self 18 27 } 19 28 } 20 29 ··· 36 45 } 37 46 } 38 47 39 - impl jacquard_common::types::xrpc::XrpcRequest for UploadBlob<'_> { 48 + impl jacquard_common::types::xrpc::XrpcRequest for UploadBlob { 40 49 const NSID: &'static str = "com.atproto.repo.uploadBlob"; 41 50 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 42 51 "*/*", ··· 44 53 const OUTPUT_ENCODING: &'static str = "application/json"; 45 54 type Output<'de> = UploadBlobOutput<'de>; 46 55 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 56 + fn encode_body(&self) -> Result<Vec<u8>, jacquard_common::types::xrpc::EncodeError> { 57 + Ok(self.body.to_vec()) 58 + } 47 59 }
+19 -1
crates/jacquard-api/src/com_atproto/server/confirm_email.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct ConfirmEmail<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub email: jacquard_common::CowStr<'a>, 14 24 #[serde(borrow)] 25 + #[builder(into)] 15 26 pub token: jacquard_common::CowStr<'a>, 27 + #[serde(flatten)] 28 + #[serde(borrow)] 29 + #[builder(default)] 30 + pub extra_data: ::std::collections::BTreeMap< 31 + ::jacquard_common::smol_str::SmolStr, 32 + ::jacquard_common::types::value::Data<'a>, 33 + >, 16 34 } 17 35 18 36 impl jacquard_common::IntoStatic for ConfirmEmail<'_> {
+23 -1
crates/jacquard-api/src/com_atproto/server/create_account.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct CreateAccount<'a> { 12 21 ///Pre-existing atproto DID, being imported to a new account. 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 15 24 pub did: std::option::Option<jacquard_common::types::string::Did<'a>>, 16 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 17 26 #[serde(borrow)] 27 + #[builder(into)] 18 28 pub email: std::option::Option<jacquard_common::CowStr<'a>>, 19 29 ///Requested handle for the account. 20 30 #[serde(borrow)] 21 31 pub handle: jacquard_common::types::string::Handle<'a>, 22 32 #[serde(skip_serializing_if = "std::option::Option::is_none")] 23 33 #[serde(borrow)] 34 + #[builder(into)] 24 35 pub invite_code: std::option::Option<jacquard_common::CowStr<'a>>, 25 36 ///Initial account password. May need to meet instance-specific password strength requirements. 26 37 #[serde(skip_serializing_if = "std::option::Option::is_none")] 27 38 #[serde(borrow)] 39 + #[builder(into)] 28 40 pub password: std::option::Option<jacquard_common::CowStr<'a>>, 29 41 ///A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented. 30 42 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 33 45 ///DID PLC rotation key (aka, recovery key) to be included in PLC creation operation. 34 46 #[serde(skip_serializing_if = "std::option::Option::is_none")] 35 47 #[serde(borrow)] 48 + #[builder(into)] 36 49 pub recovery_key: std::option::Option<jacquard_common::CowStr<'a>>, 37 50 #[serde(skip_serializing_if = "std::option::Option::is_none")] 38 51 #[serde(borrow)] 52 + #[builder(into)] 39 53 pub verification_code: std::option::Option<jacquard_common::CowStr<'a>>, 40 54 #[serde(skip_serializing_if = "std::option::Option::is_none")] 41 55 #[serde(borrow)] 56 + #[builder(into)] 42 57 pub verification_phone: std::option::Option<jacquard_common::CowStr<'a>>, 58 + #[serde(flatten)] 59 + #[serde(borrow)] 60 + #[builder(default)] 61 + pub extra_data: ::std::collections::BTreeMap< 62 + ::jacquard_common::smol_str::SmolStr, 63 + ::jacquard_common::types::value::Data<'a>, 64 + >, 43 65 } 44 66 45 67 impl jacquard_common::IntoStatic for CreateAccount<'_> {
+18 -1
crates/jacquard-api/src/com_atproto/server/create_app_password.rs
··· 32 32 } 33 33 34 34 #[jacquard_derive::lexicon] 35 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 35 + #[derive( 36 + serde::Serialize, 37 + serde::Deserialize, 38 + Debug, 39 + Clone, 40 + PartialEq, 41 + Eq, 42 + bon::Builder 43 + )] 36 44 #[serde(rename_all = "camelCase")] 45 + #[builder(start_fn = new)] 37 46 pub struct CreateAppPassword<'a> { 38 47 ///A short name for the App Password, to help distinguish them. 39 48 #[serde(borrow)] 49 + #[builder(into)] 40 50 pub name: jacquard_common::CowStr<'a>, 41 51 ///If an app password has 'privileged' access to possibly sensitive account state. Meant for use with trusted clients. 42 52 #[serde(skip_serializing_if = "std::option::Option::is_none")] 43 53 pub privileged: std::option::Option<bool>, 54 + #[serde(flatten)] 55 + #[serde(borrow)] 56 + #[builder(default)] 57 + pub extra_data: ::std::collections::BTreeMap< 58 + ::jacquard_common::smol_str::SmolStr, 59 + ::jacquard_common::types::value::Data<'a>, 60 + >, 44 61 } 45 62 46 63 impl jacquard_common::IntoStatic for CreateAppPassword<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/server/create_invite_code.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct CreateInviteCode<'a> { 12 21 #[serde(skip_serializing_if = "std::option::Option::is_none")] 13 22 #[serde(borrow)] 14 23 pub for_account: std::option::Option<jacquard_common::types::string::Did<'a>>, 15 24 pub use_count: i64, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 16 32 } 17 33 18 34 impl jacquard_common::IntoStatic for CreateInviteCode<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/server/create_invite_codes.rs
··· 27 27 } 28 28 29 29 #[jacquard_derive::lexicon] 30 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 30 + #[derive( 31 + serde::Serialize, 32 + serde::Deserialize, 33 + Debug, 34 + Clone, 35 + PartialEq, 36 + Eq, 37 + bon::Builder 38 + )] 31 39 #[serde(rename_all = "camelCase")] 40 + #[builder(start_fn = new)] 32 41 pub struct CreateInviteCodes<'a> { 33 42 pub code_count: i64, 34 43 #[serde(skip_serializing_if = "std::option::Option::is_none")] 35 44 #[serde(borrow)] 36 45 pub for_accounts: std::option::Option<Vec<jacquard_common::types::string::Did<'a>>>, 37 46 pub use_count: i64, 47 + #[serde(flatten)] 48 + #[serde(borrow)] 49 + #[builder(default)] 50 + pub extra_data: ::std::collections::BTreeMap< 51 + ::jacquard_common::smol_str::SmolStr, 52 + ::jacquard_common::types::value::Data<'a>, 53 + >, 38 54 } 39 55 40 56 impl jacquard_common::IntoStatic for CreateInviteCodes<'_> {
+20 -1
crates/jacquard-api/src/com_atproto/server/create_session.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct CreateSession<'a> { 12 21 ///When true, instead of throwing error for takendown accounts, a valid response with a narrow scoped token will be returned 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 pub allow_takendown: std::option::Option<bool>, 15 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 25 #[serde(borrow)] 26 + #[builder(into)] 17 27 pub auth_factor_token: std::option::Option<jacquard_common::CowStr<'a>>, 18 28 ///Handle or other identifier supported by the server for the authenticating user. 19 29 #[serde(borrow)] 30 + #[builder(into)] 20 31 pub identifier: jacquard_common::CowStr<'a>, 21 32 #[serde(borrow)] 33 + #[builder(into)] 22 34 pub password: jacquard_common::CowStr<'a>, 35 + #[serde(flatten)] 36 + #[serde(borrow)] 37 + #[builder(default)] 38 + pub extra_data: ::std::collections::BTreeMap< 39 + ::jacquard_common::smol_str::SmolStr, 40 + ::jacquard_common::types::value::Data<'a>, 41 + >, 23 42 } 24 43 25 44 impl jacquard_common::IntoStatic for CreateSession<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/server/deactivate_account.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeactivateAccount<'a> { 12 21 ///A recommendation to server as to how long they should hold onto the deactivated account before deleting. 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 pub delete_after: std::option::Option<jacquard_common::types::string::Datetime>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 15 31 } 16 32 17 33 impl jacquard_common::IntoStatic for DeactivateAccount<'_> {
+19 -1
crates/jacquard-api/src/com_atproto/server/delete_account.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteAccount<'a> { 12 21 #[serde(borrow)] 13 22 pub did: jacquard_common::types::string::Did<'a>, 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub password: jacquard_common::CowStr<'a>, 16 26 #[serde(borrow)] 27 + #[builder(into)] 17 28 pub token: jacquard_common::CowStr<'a>, 29 + #[serde(flatten)] 30 + #[serde(borrow)] 31 + #[builder(default)] 32 + pub extra_data: ::std::collections::BTreeMap< 33 + ::jacquard_common::smol_str::SmolStr, 34 + ::jacquard_common::types::value::Data<'a>, 35 + >, 18 36 } 19 37 20 38 impl jacquard_common::IntoStatic for DeleteAccount<'_> {
+10 -1
crates/jacquard-api/src/com_atproto/server/get_account_invite_codes.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetAccountInviteCodes { 11 20 ///(default: true)
+10 -1
crates/jacquard-api/src/com_atproto/server/get_service_auth.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetServiceAuth<'a> { 11 20 #[serde(borrow)]
+18 -1
crates/jacquard-api/src/com_atproto/server/request_password_reset.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RequestPasswordReset<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub email: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for RequestPasswordReset<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/server/reserve_signing_key.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct ReserveSigningKey<'a> { 12 21 ///The DID to reserve a key for. 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 15 24 pub did: std::option::Option<jacquard_common::types::string::Did<'a>>, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 16 32 } 17 33 18 34 impl jacquard_common::IntoStatic for ReserveSigningKey<'_> {
+19 -1
crates/jacquard-api/src/com_atproto/server/reset_password.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct ResetPassword<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub password: jacquard_common::CowStr<'a>, 14 24 #[serde(borrow)] 25 + #[builder(into)] 15 26 pub token: jacquard_common::CowStr<'a>, 27 + #[serde(flatten)] 28 + #[serde(borrow)] 29 + #[builder(default)] 30 + pub extra_data: ::std::collections::BTreeMap< 31 + ::jacquard_common::smol_str::SmolStr, 32 + ::jacquard_common::types::value::Data<'a>, 33 + >, 16 34 } 17 35 18 36 impl jacquard_common::IntoStatic for ResetPassword<'_> {
+18 -1
crates/jacquard-api/src/com_atproto/server/revoke_app_password.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RevokeAppPassword<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub name: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for RevokeAppPassword<'_> {
+19 -1
crates/jacquard-api/src/com_atproto/server/update_email.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateEmail<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub email: jacquard_common::CowStr<'a>, 14 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 25 pub email_auth_factor: std::option::Option<bool>, 16 26 ///Requires a token from com.atproto.sever.requestEmailUpdate if the account's email has been confirmed. 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub token: std::option::Option<jacquard_common::CowStr<'a>>, 31 + #[serde(flatten)] 32 + #[serde(borrow)] 33 + #[builder(default)] 34 + pub extra_data: ::std::collections::BTreeMap< 35 + ::jacquard_common::smol_str::SmolStr, 36 + ::jacquard_common::types::value::Data<'a>, 37 + >, 20 38 } 21 39 22 40 impl jacquard_common::IntoStatic for UpdateEmail<'_> {
+10 -1
crates/jacquard-api/src/com_atproto/sync/get_blob.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetBlob<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/sync/get_blocks.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetBlocks<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/sync/get_checkout.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetCheckout<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/sync/get_head.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetHead<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/com_atproto/sync/get_host_status.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetHostStatus<'a> { 11 20 #[serde(borrow)] 21 + #[builder(into)] 12 22 pub hostname: jacquard_common::CowStr<'a>, 13 23 } 14 24
+10 -1
crates/jacquard-api/src/com_atproto/sync/get_latest_commit.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetLatestCommit<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/sync/get_record.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRecord<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/sync/get_repo.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRepo<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/com_atproto/sync/get_repo_status.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRepoStatus<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/com_atproto/sync/list_blobs.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListBlobs<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 #[serde(borrow)] 15 25 pub did: jacquard_common::types::string::Did<'a>,
+11 -1
crates/jacquard-api/src/com_atproto/sync/list_hosts.rs
··· 35 35 } 36 36 } 37 37 38 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 38 + #[derive( 39 + serde::Serialize, 40 + serde::Deserialize, 41 + Debug, 42 + Clone, 43 + PartialEq, 44 + Eq, 45 + bon::Builder 46 + )] 47 + #[builder(start_fn = new)] 39 48 #[serde(rename_all = "camelCase")] 40 49 pub struct ListHosts<'a> { 41 50 #[serde(skip_serializing_if = "std::option::Option::is_none")] 42 51 #[serde(borrow)] 52 + #[builder(into)] 43 53 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 44 54 ///(default: 200, min: 1, max: 1000) 45 55 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/com_atproto/sync/list_repos.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListRepos<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 500, min: 1, max: 1000) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+11 -1
crates/jacquard-api/src/com_atproto/sync/list_repos_by_collection.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListReposByCollection<'a> { 11 20 #[serde(borrow)] 12 21 pub collection: jacquard_common::types::string::Nsid<'a>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///(default: 500, min: 1, max: 2000) 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+18 -1
crates/jacquard-api/src/com_atproto/sync/notify_of_update.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct NotifyOfUpdate<'a> { 12 21 ///Hostname of the current service (usually a PDS) that is notifying of update. 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub hostname: jacquard_common::CowStr<'a>, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 15 32 } 16 33 17 34 impl jacquard_common::IntoStatic for NotifyOfUpdate<'_> {
+18 -1
crates/jacquard-api/src/com_atproto/sync/request_crawl.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RequestCrawl<'a> { 12 21 ///Hostname of the current service (eg, PDS) that is requesting to be crawled. 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub hostname: jacquard_common::CowStr<'a>, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 15 32 } 16 33 17 34 impl jacquard_common::IntoStatic for RequestCrawl<'_> {
+10 -1
crates/jacquard-api/src/com_atproto/sync/subscribe_repos.rs
··· 142 142 } 143 143 } 144 144 145 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 145 + #[derive( 146 + serde::Serialize, 147 + serde::Deserialize, 148 + Debug, 149 + Clone, 150 + PartialEq, 151 + Eq, 152 + bon::Builder 153 + )] 154 + #[builder(start_fn = new)] 146 155 #[serde(rename_all = "camelCase")] 147 156 pub struct SubscribeRepos { 148 157 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+18 -1
crates/jacquard-api/src/com_atproto/temp/add_reserved_handle.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct AddReservedHandle<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub handle: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for AddReservedHandle<'_> {
+11 -1
crates/jacquard-api/src/com_atproto/temp/check_handle_availability.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct CheckHandleAvailability<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 pub birth_date: std::option::Option<jacquard_common::types::string::Datetime>, 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub email: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 #[serde(borrow)] 17 27 pub handle: jacquard_common::types::string::Handle<'a>,
+11 -1
crates/jacquard-api/src/com_atproto/temp/dereference_scope.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct DereferenceScope<'a> { 11 20 #[serde(borrow)] 21 + #[builder(into)] 12 22 pub scope: jacquard_common::CowStr<'a>, 13 23 } 14 24
+10 -1
crates/jacquard-api/src/com_atproto/temp/fetch_labels.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct FetchLabels { 11 20 ///(default: 50, min: 1, max: 250)
+18 -1
crates/jacquard-api/src/com_atproto/temp/request_phone_verification.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RequestPhoneVerification<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub phone_number: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for RequestPhoneVerification<'_> {
+17 -1
crates/jacquard-api/src/com_atproto/temp/revoke_account_credentials.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RevokeAccountCredentials<'a> { 12 21 #[serde(borrow)] 13 22 pub account: jacquard_common::types::ident::AtIdentifier<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for RevokeAccountCredentials<'_> {
+7
crates/jacquard-api/src/lib.rs
··· 3 3 // This file was automatically generated from Lexicon schemas. 4 4 // Any manual changes will be overwritten on the next regeneration. 5 5 6 + #[cfg(feature = "app_bsky")] 6 7 pub mod app_bsky; 8 + 9 + #[cfg(feature = "chat_bsky")] 7 10 pub mod chat_bsky; 11 + 12 + #[cfg(feature = "com_atproto")] 8 13 pub mod com_atproto; 14 + 15 + #[cfg(feature = "tools_ozone")] 9 16 pub mod tools_ozone;
+20 -1
crates/jacquard-api/src/tools_ozone/communication/create_template.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct CreateTemplate<'a> { 12 21 ///Content of the template, markdown supported, can contain variable placeholders. 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub content_markdown: jacquard_common::CowStr<'a>, 15 25 ///DID of the user who is creating the template. 16 26 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 21 31 pub lang: std::option::Option<jacquard_common::types::string::Language>, 22 32 ///Name of the template. 23 33 #[serde(borrow)] 34 + #[builder(into)] 24 35 pub name: jacquard_common::CowStr<'a>, 25 36 ///Subject of the message, used in emails. 26 37 #[serde(borrow)] 38 + #[builder(into)] 27 39 pub subject: jacquard_common::CowStr<'a>, 40 + #[serde(flatten)] 41 + #[serde(borrow)] 42 + #[builder(default)] 43 + pub extra_data: ::std::collections::BTreeMap< 44 + ::jacquard_common::smol_str::SmolStr, 45 + ::jacquard_common::types::value::Data<'a>, 46 + >, 28 47 } 29 48 30 49 impl jacquard_common::IntoStatic for CreateTemplate<'_> {
+18 -1
crates/jacquard-api/src/tools_ozone/communication/delete_template.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteTemplate<'a> { 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub id: jacquard_common::CowStr<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 14 31 } 15 32 16 33 impl jacquard_common::IntoStatic for DeleteTemplate<'_> {
+21 -1
crates/jacquard-api/src/tools_ozone/communication/update_template.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateTemplate<'a> { 12 21 ///Content of the template, markdown supported, can contain variable placeholders. 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub content_markdown: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 #[serde(skip_serializing_if = "std::option::Option::is_none")] 17 27 pub disabled: std::option::Option<bool>, 18 28 ///ID of the template to be updated. 19 29 #[serde(borrow)] 30 + #[builder(into)] 20 31 pub id: jacquard_common::CowStr<'a>, 21 32 ///Message language. 22 33 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 24 35 ///Name of the template. 25 36 #[serde(skip_serializing_if = "std::option::Option::is_none")] 26 37 #[serde(borrow)] 38 + #[builder(into)] 27 39 pub name: std::option::Option<jacquard_common::CowStr<'a>>, 28 40 ///Subject of the message, used in emails. 29 41 #[serde(skip_serializing_if = "std::option::Option::is_none")] 30 42 #[serde(borrow)] 43 + #[builder(into)] 31 44 pub subject: std::option::Option<jacquard_common::CowStr<'a>>, 32 45 ///DID of the user who is updating the template. 33 46 #[serde(skip_serializing_if = "std::option::Option::is_none")] 34 47 #[serde(borrow)] 35 48 pub updated_by: std::option::Option<jacquard_common::types::string::Did<'a>>, 49 + #[serde(flatten)] 50 + #[serde(borrow)] 51 + #[builder(default)] 52 + pub extra_data: ::std::collections::BTreeMap< 53 + ::jacquard_common::smol_str::SmolStr, 54 + ::jacquard_common::types::value::Data<'a>, 55 + >, 36 56 } 37 57 38 58 impl jacquard_common::IntoStatic for UpdateTemplate<'_> {
+11 -1
crates/jacquard-api/src/tools_ozone/hosting/get_account_history.rs
··· 121 121 } 122 122 } 123 123 124 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 124 + #[derive( 125 + serde::Serialize, 126 + serde::Deserialize, 127 + Debug, 128 + Clone, 129 + PartialEq, 130 + Eq, 131 + bon::Builder 132 + )] 133 + #[builder(start_fn = new)] 125 134 #[serde(rename_all = "camelCase")] 126 135 pub struct GetAccountHistory<'a> { 127 136 #[serde(skip_serializing_if = "std::option::Option::is_none")] 128 137 #[serde(borrow)] 138 + #[builder(into)] 129 139 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 130 140 #[serde(borrow)] 131 141 pub did: jacquard_common::types::string::Did<'a>,
+18 -1
crates/jacquard-api/src/tools_ozone/moderation/emit_event.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct EmitEvent<'a> { 12 21 #[serde(borrow)] 13 22 pub created_by: jacquard_common::types::string::Did<'a>, ··· 16 25 ///An optional external ID for the event, used to deduplicate events from external systems. Fails when an event of same type with the same external ID exists for the same subject. 17 26 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 27 #[serde(borrow)] 28 + #[builder(into)] 19 29 pub external_id: std::option::Option<jacquard_common::CowStr<'a>>, 20 30 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 31 #[serde(borrow)] ··· 26 36 #[serde(borrow)] 27 37 pub subject_blob_cids: std::option::Option< 28 38 Vec<jacquard_common::types::string::Cid<'a>>, 39 + >, 40 + #[serde(flatten)] 41 + #[serde(borrow)] 42 + #[builder(default)] 43 + pub extra_data: ::std::collections::BTreeMap< 44 + ::jacquard_common::smol_str::SmolStr, 45 + ::jacquard_common::types::value::Data<'a>, 29 46 >, 30 47 } 31 48
+10 -1
crates/jacquard-api/src/tools_ozone/moderation/get_account_timeline.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetAccountTimeline<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/tools_ozone/moderation/get_event.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetEvent { 11 20 pub id: i64,
+10 -1
crates/jacquard-api/src/tools_ozone/moderation/get_record.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRecord<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+10 -1
crates/jacquard-api/src/tools_ozone/moderation/get_records.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRecords<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/tools_ozone/moderation/get_repo.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRepo<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/tools_ozone/moderation/get_reporter_stats.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetReporterStats<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/tools_ozone/moderation/get_repos.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetRepos<'a> { 11 20 #[serde(borrow)]
+10 -1
crates/jacquard-api/src/tools_ozone/moderation/get_subjects.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetSubjects<'a> { 11 20 #[serde(borrow)]
+16 -1
crates/jacquard-api/src/tools_ozone/moderation/query_events.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct QueryEvents<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 16 25 pub added_tags: std::option::Option<Vec<jacquard_common::CowStr<'a>>>, 17 26 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 27 #[serde(borrow)] 28 + #[builder(into)] 19 29 pub age_assurance_state: std::option::Option<jacquard_common::CowStr<'a>>, 20 30 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 31 #[serde(borrow)] 32 + #[builder(into)] 22 33 pub batch_id: std::option::Option<jacquard_common::CowStr<'a>>, 23 34 #[serde(skip_serializing_if = "std::option::Option::is_none")] 24 35 #[serde(borrow)] 25 36 pub collections: std::option::Option<Vec<jacquard_common::types::string::Nsid<'a>>>, 26 37 #[serde(skip_serializing_if = "std::option::Option::is_none")] 27 38 #[serde(borrow)] 39 + #[builder(into)] 28 40 pub comment: std::option::Option<jacquard_common::CowStr<'a>>, 29 41 #[serde(skip_serializing_if = "std::option::Option::is_none")] 30 42 pub created_after: std::option::Option<jacquard_common::types::string::Datetime>, ··· 35 47 pub created_by: std::option::Option<jacquard_common::types::string::Did<'a>>, 36 48 #[serde(skip_serializing_if = "std::option::Option::is_none")] 37 49 #[serde(borrow)] 50 + #[builder(into)] 38 51 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 39 52 #[serde(skip_serializing_if = "std::option::Option::is_none")] 40 53 pub has_comment: std::option::Option<bool>, ··· 62 75 ///(default: "desc") 63 76 #[serde(skip_serializing_if = "std::option::Option::is_none")] 64 77 #[serde(borrow)] 78 + #[builder(into)] 65 79 pub sort_direction: std::option::Option<jacquard_common::CowStr<'a>>, 66 80 #[serde(skip_serializing_if = "std::option::Option::is_none")] 67 81 #[serde(borrow)] 68 82 pub subject: std::option::Option<jacquard_common::types::string::Uri<'a>>, 69 83 #[serde(skip_serializing_if = "std::option::Option::is_none")] 70 84 #[serde(borrow)] 85 + #[builder(into)] 71 86 pub subject_type: std::option::Option<jacquard_common::CowStr<'a>>, 72 87 #[serde(skip_serializing_if = "std::option::Option::is_none")] 73 88 #[serde(borrow)]
+18 -1
crates/jacquard-api/src/tools_ozone/moderation/query_statuses.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct QueryStatuses<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub age_assurance_state: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 25 pub appealed: std::option::Option<bool>, ··· 18 28 pub collections: std::option::Option<Vec<jacquard_common::types::string::Nsid<'a>>>, 19 29 #[serde(skip_serializing_if = "std::option::Option::is_none")] 20 30 #[serde(borrow)] 31 + #[builder(into)] 21 32 pub comment: std::option::Option<jacquard_common::CowStr<'a>>, 22 33 #[serde(skip_serializing_if = "std::option::Option::is_none")] 23 34 #[serde(borrow)] 35 + #[builder(into)] 24 36 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 25 37 #[serde(skip_serializing_if = "std::option::Option::is_none")] 26 38 #[serde(borrow)] ··· 76 88 pub queue_index: std::option::Option<i64>, 77 89 #[serde(skip_serializing_if = "std::option::Option::is_none")] 78 90 #[serde(borrow)] 91 + #[builder(into)] 79 92 pub queue_seed: std::option::Option<jacquard_common::CowStr<'a>>, 80 93 #[serde(skip_serializing_if = "std::option::Option::is_none")] 81 94 pub reported_after: std::option::Option<jacquard_common::types::string::Datetime>, ··· 83 96 pub reported_before: std::option::Option<jacquard_common::types::string::Datetime>, 84 97 #[serde(skip_serializing_if = "std::option::Option::is_none")] 85 98 #[serde(borrow)] 99 + #[builder(into)] 86 100 pub review_state: std::option::Option<jacquard_common::CowStr<'a>>, 87 101 #[serde(skip_serializing_if = "std::option::Option::is_none")] 88 102 pub reviewed_after: std::option::Option<jacquard_common::types::string::Datetime>, ··· 91 105 ///(default: "desc") 92 106 #[serde(skip_serializing_if = "std::option::Option::is_none")] 93 107 #[serde(borrow)] 108 + #[builder(into)] 94 109 pub sort_direction: std::option::Option<jacquard_common::CowStr<'a>>, 95 110 ///(default: "lastReportedAt") 96 111 #[serde(skip_serializing_if = "std::option::Option::is_none")] 97 112 #[serde(borrow)] 113 + #[builder(into)] 98 114 pub sort_field: std::option::Option<jacquard_common::CowStr<'a>>, 99 115 #[serde(skip_serializing_if = "std::option::Option::is_none")] 100 116 #[serde(borrow)] 101 117 pub subject: std::option::Option<jacquard_common::types::string::Uri<'a>>, 102 118 #[serde(skip_serializing_if = "std::option::Option::is_none")] 103 119 #[serde(borrow)] 120 + #[builder(into)] 104 121 pub subject_type: std::option::Option<jacquard_common::CowStr<'a>>, 105 122 #[serde(skip_serializing_if = "std::option::Option::is_none")] 106 123 #[serde(borrow)]
+13 -1
crates/jacquard-api/src/tools_ozone/moderation/search_repos.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchRepos<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 26 pub limit: std::option::Option<i64>, 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub q: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 32 #[serde(borrow)] 33 + #[builder(into)] 22 34 pub term: std::option::Option<jacquard_common::CowStr<'a>>, 23 35 } 24 36
+19 -1
crates/jacquard-api/src/tools_ozone/safelink/add_rule.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct AddRule<'a> { 12 21 #[serde(borrow)] 13 22 pub action: crate::tools_ozone::safelink::ActionType<'a>, 14 23 ///Optional comment about the decision 15 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 25 #[serde(borrow)] 26 + #[builder(into)] 17 27 pub comment: std::option::Option<jacquard_common::CowStr<'a>>, 18 28 ///Author DID. Only respected when using admin auth 19 29 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 25 35 pub reason: crate::tools_ozone::safelink::ReasonType<'a>, 26 36 ///The URL or domain to apply the rule to 27 37 #[serde(borrow)] 38 + #[builder(into)] 28 39 pub url: jacquard_common::CowStr<'a>, 40 + #[serde(flatten)] 41 + #[serde(borrow)] 42 + #[builder(default)] 43 + pub extra_data: ::std::collections::BTreeMap< 44 + ::jacquard_common::smol_str::SmolStr, 45 + ::jacquard_common::types::value::Data<'a>, 46 + >, 29 47 } 30 48 31 49 impl jacquard_common::IntoStatic for AddRule<'_> {
+20 -1
crates/jacquard-api/src/tools_ozone/safelink/query_events.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct QueryEvents<'a> { 12 21 ///Cursor for pagination 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///Maximum number of results to return 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 19 29 ///Filter by pattern type 20 30 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 31 #[serde(borrow)] 32 + #[builder(into)] 22 33 pub pattern_type: std::option::Option<jacquard_common::CowStr<'a>>, 23 34 ///Sort direction 24 35 #[serde(skip_serializing_if = "std::option::Option::is_none")] 25 36 #[serde(borrow)] 37 + #[builder(into)] 26 38 pub sort_direction: std::option::Option<jacquard_common::CowStr<'a>>, 27 39 ///Filter by specific URLs or domains 28 40 #[serde(skip_serializing_if = "std::option::Option::is_none")] 29 41 #[serde(borrow)] 30 42 pub urls: std::option::Option<Vec<jacquard_common::CowStr<'a>>>, 43 + #[serde(flatten)] 44 + #[serde(borrow)] 45 + #[builder(default)] 46 + pub extra_data: ::std::collections::BTreeMap< 47 + ::jacquard_common::smol_str::SmolStr, 48 + ::jacquard_common::types::value::Data<'a>, 49 + >, 31 50 } 32 51 33 52 impl jacquard_common::IntoStatic for QueryEvents<'_> {
+21 -1
crates/jacquard-api/src/tools_ozone/safelink/query_rules.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct QueryRules<'a> { 12 21 ///Filter by action types 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 20 29 ///Cursor for pagination 21 30 #[serde(skip_serializing_if = "std::option::Option::is_none")] 22 31 #[serde(borrow)] 32 + #[builder(into)] 23 33 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 24 34 ///Maximum number of results to return 25 35 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 27 37 ///Filter by pattern type 28 38 #[serde(skip_serializing_if = "std::option::Option::is_none")] 29 39 #[serde(borrow)] 40 + #[builder(into)] 30 41 pub pattern_type: std::option::Option<jacquard_common::CowStr<'a>>, 31 42 ///Filter by reason type 32 43 #[serde(skip_serializing_if = "std::option::Option::is_none")] 33 44 #[serde(borrow)] 45 + #[builder(into)] 34 46 pub reason: std::option::Option<jacquard_common::CowStr<'a>>, 35 47 ///Sort direction 36 48 #[serde(skip_serializing_if = "std::option::Option::is_none")] 37 49 #[serde(borrow)] 50 + #[builder(into)] 38 51 pub sort_direction: std::option::Option<jacquard_common::CowStr<'a>>, 39 52 ///Filter by specific URLs or domains 40 53 #[serde(skip_serializing_if = "std::option::Option::is_none")] 41 54 #[serde(borrow)] 42 55 pub urls: std::option::Option<Vec<jacquard_common::CowStr<'a>>>, 56 + #[serde(flatten)] 57 + #[serde(borrow)] 58 + #[builder(default)] 59 + pub extra_data: ::std::collections::BTreeMap< 60 + ::jacquard_common::smol_str::SmolStr, 61 + ::jacquard_common::types::value::Data<'a>, 62 + >, 43 63 } 44 64 45 65 impl jacquard_common::IntoStatic for QueryRules<'_> {
+19 -1
crates/jacquard-api/src/tools_ozone/safelink/remove_rule.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RemoveRule<'a> { 12 21 ///Optional comment about why the rule is being removed 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub comment: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///Optional DID of the user. Only respected when using admin auth. 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 21 31 pub pattern: crate::tools_ozone::safelink::PatternType<'a>, 22 32 ///The URL or domain to remove the rule for 23 33 #[serde(borrow)] 34 + #[builder(into)] 24 35 pub url: jacquard_common::CowStr<'a>, 36 + #[serde(flatten)] 37 + #[serde(borrow)] 38 + #[builder(default)] 39 + pub extra_data: ::std::collections::BTreeMap< 40 + ::jacquard_common::smol_str::SmolStr, 41 + ::jacquard_common::types::value::Data<'a>, 42 + >, 25 43 } 26 44 27 45 impl jacquard_common::IntoStatic for RemoveRule<'_> {
+19 -1
crates/jacquard-api/src/tools_ozone/safelink/update_rule.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateRule<'a> { 12 21 #[serde(borrow)] 13 22 pub action: crate::tools_ozone::safelink::ActionType<'a>, 14 23 ///Optional comment about the update 15 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 25 #[serde(borrow)] 26 + #[builder(into)] 17 27 pub comment: std::option::Option<jacquard_common::CowStr<'a>>, 18 28 ///Optional DID to credit as the creator. Only respected for admin_token authentication. 19 29 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 25 35 pub reason: crate::tools_ozone::safelink::ReasonType<'a>, 26 36 ///The URL or domain to update the rule for 27 37 #[serde(borrow)] 38 + #[builder(into)] 28 39 pub url: jacquard_common::CowStr<'a>, 40 + #[serde(flatten)] 41 + #[serde(borrow)] 42 + #[builder(default)] 43 + pub extra_data: ::std::collections::BTreeMap< 44 + ::jacquard_common::smol_str::SmolStr, 45 + ::jacquard_common::types::value::Data<'a>, 46 + >, 29 47 } 30 48 31 49 impl jacquard_common::IntoStatic for UpdateRule<'_> {
+18 -1
crates/jacquard-api/src/tools_ozone/set/add_values.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct AddValues<'a> { 12 21 ///Name of the set to add values to 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub name: jacquard_common::CowStr<'a>, 15 25 ///Array of string values to add to the set 16 26 #[serde(borrow)] 17 27 pub values: Vec<jacquard_common::CowStr<'a>>, 28 + #[serde(flatten)] 29 + #[serde(borrow)] 30 + #[builder(default)] 31 + pub extra_data: ::std::collections::BTreeMap< 32 + ::jacquard_common::smol_str::SmolStr, 33 + ::jacquard_common::types::value::Data<'a>, 34 + >, 18 35 } 19 36 20 37 impl jacquard_common::IntoStatic for AddValues<'_> {
+18 -1
crates/jacquard-api/src/tools_ozone/set/delete_set.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteSet<'a> { 12 21 ///Name of the set to delete 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub name: jacquard_common::CowStr<'a>, 25 + #[serde(flatten)] 26 + #[serde(borrow)] 27 + #[builder(default)] 28 + pub extra_data: ::std::collections::BTreeMap< 29 + ::jacquard_common::smol_str::SmolStr, 30 + ::jacquard_common::types::value::Data<'a>, 31 + >, 15 32 } 16 33 17 34 impl jacquard_common::IntoStatic for DeleteSet<'_> {
+18 -1
crates/jacquard-api/src/tools_ozone/set/delete_values.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteValues<'a> { 12 21 ///Name of the set to delete values from 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub name: jacquard_common::CowStr<'a>, 15 25 ///Array of string values to delete from the set 16 26 #[serde(borrow)] 17 27 pub values: Vec<jacquard_common::CowStr<'a>>, 28 + #[serde(flatten)] 29 + #[serde(borrow)] 30 + #[builder(default)] 31 + pub extra_data: ::std::collections::BTreeMap< 32 + ::jacquard_common::smol_str::SmolStr, 33 + ::jacquard_common::types::value::Data<'a>, 34 + >, 18 35 } 19 36 20 37 impl jacquard_common::IntoStatic for DeleteValues<'_> {
+12 -1
crates/jacquard-api/src/tools_ozone/set/get_values.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct GetValues<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 100, min: 1, max: 1000) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 26 pub limit: std::option::Option<i64>, 17 27 #[serde(borrow)] 28 + #[builder(into)] 18 29 pub name: jacquard_common::CowStr<'a>, 19 30 } 20 31
+14 -1
crates/jacquard-api/src/tools_ozone/set/query_sets.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct QuerySets<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 26 pub limit: std::option::Option<i64>, 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub name_prefix: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 ///(default: "name") 21 32 #[serde(skip_serializing_if = "std::option::Option::is_none")] 22 33 #[serde(borrow)] 34 + #[builder(into)] 23 35 pub sort_by: std::option::Option<jacquard_common::CowStr<'a>>, 24 36 ///(default: "asc") 25 37 #[serde(skip_serializing_if = "std::option::Option::is_none")] 26 38 #[serde(borrow)] 39 + #[builder(into)] 27 40 pub sort_direction: std::option::Option<jacquard_common::CowStr<'a>>, 28 41 } 29 42
+17 -1
crates/jacquard-api/src/tools_ozone/set/upsert_set.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpsertSet<'a> { 12 21 #[serde(flatten)] 13 22 #[serde(borrow)] 14 23 pub value: crate::tools_ozone::set::Set<'a>, 24 + #[serde(flatten)] 25 + #[serde(borrow)] 26 + #[builder(default)] 27 + pub extra_data: ::std::collections::BTreeMap< 28 + ::jacquard_common::smol_str::SmolStr, 29 + ::jacquard_common::types::value::Data<'a>, 30 + >, 15 31 } 16 32 17 33 impl jacquard_common::IntoStatic for UpsertSet<'_> {
+13 -1
crates/jacquard-api/src/tools_ozone/setting/list_options.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListOptions<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 25 #[serde(borrow)] ··· 19 29 pub limit: std::option::Option<i64>, 20 30 #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 31 #[serde(borrow)] 32 + #[builder(into)] 22 33 pub prefix: std::option::Option<jacquard_common::CowStr<'a>>, 23 34 ///(default: "instance") 24 35 #[serde(skip_serializing_if = "std::option::Option::is_none")] 25 36 #[serde(borrow)] 37 + #[builder(into)] 26 38 pub scope: std::option::Option<jacquard_common::CowStr<'a>>, 27 39 } 28 40
+18 -1
crates/jacquard-api/src/tools_ozone/setting/remove_options.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RemoveOptions<'a> { 12 21 #[serde(borrow)] 13 22 pub keys: Vec<jacquard_common::types::string::Nsid<'a>>, 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub scope: jacquard_common::CowStr<'a>, 26 + #[serde(flatten)] 27 + #[serde(borrow)] 28 + #[builder(default)] 29 + pub extra_data: ::std::collections::BTreeMap< 30 + ::jacquard_common::smol_str::SmolStr, 31 + ::jacquard_common::types::value::Data<'a>, 32 + >, 16 33 } 17 34 18 35 impl jacquard_common::IntoStatic for RemoveOptions<'_> {
+20 -1
crates/jacquard-api/src/tools_ozone/setting/upsert_option.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpsertOption<'a> { 12 21 #[serde(skip_serializing_if = "std::option::Option::is_none")] 13 22 #[serde(borrow)] 23 + #[builder(into)] 14 24 pub description: std::option::Option<jacquard_common::CowStr<'a>>, 15 25 #[serde(borrow)] 16 26 pub key: jacquard_common::types::string::Nsid<'a>, 17 27 #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 28 #[serde(borrow)] 29 + #[builder(into)] 19 30 pub manager_role: std::option::Option<jacquard_common::CowStr<'a>>, 20 31 #[serde(borrow)] 32 + #[builder(into)] 21 33 pub scope: jacquard_common::CowStr<'a>, 22 34 #[serde(borrow)] 23 35 pub value: jacquard_common::types::value::Data<'a>, 36 + #[serde(flatten)] 37 + #[serde(borrow)] 38 + #[builder(default)] 39 + pub extra_data: ::std::collections::BTreeMap< 40 + ::jacquard_common::smol_str::SmolStr, 41 + ::jacquard_common::types::value::Data<'a>, 42 + >, 24 43 } 25 44 26 45 impl jacquard_common::IntoStatic for UpsertOption<'_> {
+10 -1
crates/jacquard-api/src/tools_ozone/signature/find_correlation.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct FindCorrelation<'a> { 11 20 #[serde(borrow)]
+11 -1
crates/jacquard-api/src/tools_ozone/signature/search_accounts.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct SearchAccounts<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 ///(default: 50, min: 1, max: 100) 15 25 #[serde(skip_serializing_if = "std::option::Option::is_none")]
+18 -1
crates/jacquard-api/src/tools_ozone/team/add_member.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct AddMember<'a> { 12 21 #[serde(borrow)] 13 22 pub did: jacquard_common::types::string::Did<'a>, 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub role: jacquard_common::CowStr<'a>, 26 + #[serde(flatten)] 27 + #[serde(borrow)] 28 + #[builder(default)] 29 + pub extra_data: ::std::collections::BTreeMap< 30 + ::jacquard_common::smol_str::SmolStr, 31 + ::jacquard_common::types::value::Data<'a>, 32 + >, 16 33 } 17 34 18 35 impl jacquard_common::IntoStatic for AddMember<'_> {
+17 -1
crates/jacquard-api/src/tools_ozone/team/delete_member.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct DeleteMember<'a> { 12 21 #[serde(borrow)] 13 22 pub did: jacquard_common::types::string::Did<'a>, 23 + #[serde(flatten)] 24 + #[serde(borrow)] 25 + #[builder(default)] 26 + pub extra_data: ::std::collections::BTreeMap< 27 + ::jacquard_common::smol_str::SmolStr, 28 + ::jacquard_common::types::value::Data<'a>, 29 + >, 14 30 } 15 31 16 32 impl jacquard_common::IntoStatic for DeleteMember<'_> {
+12 -1
crates/jacquard-api/src/tools_ozone/team/list_members.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListMembers<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] 12 21 #[serde(borrow)] 22 + #[builder(into)] 13 23 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 14 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 25 pub disabled: std::option::Option<bool>, ··· 18 28 pub limit: std::option::Option<i64>, 19 29 #[serde(skip_serializing_if = "std::option::Option::is_none")] 20 30 #[serde(borrow)] 31 + #[builder(into)] 21 32 pub q: std::option::Option<jacquard_common::CowStr<'a>>, 22 33 #[serde(skip_serializing_if = "std::option::Option::is_none")] 23 34 #[serde(borrow)]
+18 -1
crates/jacquard-api/src/tools_ozone/team/update_member.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct UpdateMember<'a> { 12 21 #[serde(borrow)] 13 22 pub did: jacquard_common::types::string::Did<'a>, ··· 15 24 pub disabled: std::option::Option<bool>, 16 25 #[serde(skip_serializing_if = "std::option::Option::is_none")] 17 26 #[serde(borrow)] 27 + #[builder(into)] 18 28 pub role: std::option::Option<jacquard_common::CowStr<'a>>, 29 + #[serde(flatten)] 30 + #[serde(borrow)] 31 + #[builder(default)] 32 + pub extra_data: ::std::collections::BTreeMap< 33 + ::jacquard_common::smol_str::SmolStr, 34 + ::jacquard_common::types::value::Data<'a>, 35 + >, 19 36 } 20 37 21 38 impl jacquard_common::IntoStatic for UpdateMember<'_> {
+17 -1
crates/jacquard-api/src/tools_ozone/verification/grant_verifications.rs
··· 30 30 } 31 31 32 32 #[jacquard_derive::lexicon] 33 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 33 + #[derive( 34 + serde::Serialize, 35 + serde::Deserialize, 36 + Debug, 37 + Clone, 38 + PartialEq, 39 + Eq, 40 + bon::Builder 41 + )] 34 42 #[serde(rename_all = "camelCase")] 43 + #[builder(start_fn = new)] 35 44 pub struct GrantVerifications<'a> { 36 45 ///Array of verification requests to process 37 46 #[serde(borrow)] 38 47 pub verifications: Vec<jacquard_common::types::value::Data<'a>>, 48 + #[serde(flatten)] 49 + #[serde(borrow)] 50 + #[builder(default)] 51 + pub extra_data: ::std::collections::BTreeMap< 52 + ::jacquard_common::smol_str::SmolStr, 53 + ::jacquard_common::types::value::Data<'a>, 54 + >, 39 55 } 40 56 41 57 impl jacquard_common::IntoStatic for GrantVerifications<'_> {
+12 -1
crates/jacquard-api/src/tools_ozone/verification/list_verifications.rs
··· 5 5 // This file was automatically generated from Lexicon schemas. 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 + #[derive( 9 + serde::Serialize, 10 + serde::Deserialize, 11 + Debug, 12 + Clone, 13 + PartialEq, 14 + Eq, 15 + bon::Builder 16 + )] 17 + #[builder(start_fn = new)] 9 18 #[serde(rename_all = "camelCase")] 10 19 pub struct ListVerifications<'a> { 11 20 #[serde(skip_serializing_if = "std::option::Option::is_none")] ··· 14 23 pub created_before: std::option::Option<jacquard_common::types::string::Datetime>, 15 24 #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 25 #[serde(borrow)] 26 + #[builder(into)] 17 27 pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 18 28 #[serde(skip_serializing_if = "std::option::Option::is_none")] 19 29 pub is_revoked: std::option::Option<bool>, ··· 26 36 ///(default: "desc") 27 37 #[serde(skip_serializing_if = "std::option::Option::is_none")] 28 38 #[serde(borrow)] 39 + #[builder(into)] 29 40 pub sort_direction: std::option::Option<jacquard_common::CowStr<'a>>, 30 41 #[serde(skip_serializing_if = "std::option::Option::is_none")] 31 42 #[serde(borrow)]
+18 -1
crates/jacquard-api/src/tools_ozone/verification/revoke_verifications.rs
··· 6 6 // Any manual changes will be overwritten on the next regeneration. 7 7 8 8 #[jacquard_derive::lexicon] 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 + #[derive( 10 + serde::Serialize, 11 + serde::Deserialize, 12 + Debug, 13 + Clone, 14 + PartialEq, 15 + Eq, 16 + bon::Builder 17 + )] 10 18 #[serde(rename_all = "camelCase")] 19 + #[builder(start_fn = new)] 11 20 pub struct RevokeVerifications<'a> { 12 21 ///Reason for revoking the verification. This is optional and can be omitted if not needed. 13 22 #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 23 #[serde(borrow)] 24 + #[builder(into)] 15 25 pub revoke_reason: std::option::Option<jacquard_common::CowStr<'a>>, 16 26 ///Array of verification record uris to revoke 17 27 #[serde(borrow)] 18 28 pub uris: Vec<jacquard_common::types::string::AtUri<'a>>, 29 + #[serde(flatten)] 30 + #[serde(borrow)] 31 + #[builder(default)] 32 + pub extra_data: ::std::collections::BTreeMap< 33 + ::jacquard_common::smol_str::SmolStr, 34 + ::jacquard_common::types::value::Data<'a>, 35 + >, 19 36 } 20 37 21 38 impl jacquard_common::IntoStatic for RevokeVerifications<'_> {
+11 -12
crates/jacquard-common/Cargo.toml
··· 1 1 [package] 2 2 name = "jacquard-common" 3 + description = "Core AT Protocol types and utilities for Jacquard" 3 4 edition.workspace = true 4 5 version.workspace = true 5 6 authors.workspace = true ··· 7 8 keywords.workspace = true 8 9 categories.workspace = true 9 10 readme.workspace = true 10 - documentation.workspace = true 11 11 exclude.workspace = true 12 - description.workspace = true 13 - 12 + license-file.workspace = true 14 13 15 14 16 15 [dependencies] 17 16 base64 = "0.22.1" 18 - bytes = "1.10.1" 17 + bytes.workspace = true 19 18 chrono = "0.4.42" 20 19 cid = { version = "0.11.1", features = ["serde", "std"] } 21 20 enum_dispatch = "0.3.13" 22 21 ipld-core = { version = "0.4.2", features = ["serde"] } 23 22 langtag = { version = "0.4.0", features = ["serde"] } 24 - miette = "7.6.0" 23 + miette.workspace = true 25 24 multibase = "0.9.1" 26 25 multihash = "0.19.3" 27 26 num-traits = "0.2.19" 28 27 ouroboros = "0.18.5" 29 28 rand = "0.9.2" 30 29 regex = "1.11.3" 31 - serde = { version = "1.0.227", features = ["derive"] } 32 - serde_html_form = "0.2.8" 33 - serde_json = "1.0.145" 34 - serde_with = "3.14.1" 35 - smol_str = { version = "0.3.2", features = ["serde"] } 36 - thiserror = "2.0.16" 37 - url = "2.5.7" 30 + serde.workspace = true 31 + serde_html_form.workspace = true 32 + serde_json.workspace = true 33 + serde_with.workspace = true 34 + smol_str.workspace = true 35 + thiserror.workspace = true 36 + url.workspace = true
+11 -5
crates/jacquard-common/src/cowstr.rs
··· 9 9 10 10 use crate::IntoStatic; 11 11 12 - /// Shamelessly copied from https://github.com/bearcove/merde 12 + /// Shamelessly copied from [](https://github.com/bearcove/merde) 13 13 /// A copy-on-write immutable string type that uses [`SmolStr`] for 14 14 /// the "owned" variant. 15 15 /// ··· 17 17 /// `<str as ToOwned>::Owned` is `String`, and not `SmolStr`. 18 18 #[derive(Clone)] 19 19 pub enum CowStr<'s> { 20 + /// &str varaiant 20 21 Borrowed(&'s str), 22 + /// Smolstr variant 21 23 Owned(SmolStr), 22 24 } 23 25 24 26 impl CowStr<'static> { 25 27 /// Create a new `CowStr` by copying from a `&str` โ€” this might allocate 26 - /// if the `compact_str` feature is disabled, or if the string is longer 27 - /// than `MAX_INLINE_SIZE`. 28 + /// if the string is longer than `MAX_INLINE_SIZE`. 28 29 pub fn copy_from_str(s: &str) -> Self { 29 30 Self::Owned(SmolStr::from(s)) 30 31 } 31 32 33 + /// Create a new owned `CowStr` from a static &str without allocating 32 34 pub fn new_static(s: &'static str) -> Self { 33 35 Self::Owned(SmolStr::new_static(s)) 34 36 } ··· 36 38 37 39 impl<'s> CowStr<'s> { 38 40 #[inline] 41 + /// Borrow and decode a byte slice as utf8 into a CowStr 39 42 pub fn from_utf8(s: &'s [u8]) -> Result<Self, std::str::Utf8Error> { 40 43 Ok(Self::Borrowed(std::str::from_utf8(s)?)) 41 44 } 42 45 43 46 #[inline] 44 - pub fn from_utf8_owned(s: Vec<u8>) -> Result<Self, std::str::Utf8Error> { 45 - Ok(Self::Owned(SmolStr::new(std::str::from_utf8(&s)?))) 47 + /// Take bytes and decode them as utf8 into an owned CowStr. Might allocate. 48 + pub fn from_utf8_owned(s: impl AsRef<[u8]>) -> Result<Self, std::str::Utf8Error> { 49 + Ok(Self::Owned(SmolStr::new(std::str::from_utf8(&s.as_ref())?))) 46 50 } 47 51 48 52 #[inline] 53 + /// Take bytes and decode them as utf8, skipping invalid characters, taking ownership. 54 + /// Will allocate, uses String::from_utf8_lossy() internally for now. 49 55 pub fn from_utf8_lossy(s: &'s [u8]) -> Self { 50 56 Self::Owned(String::from_utf8_lossy(&s).into()) 51 57 }
+1 -1
crates/jacquard-common/src/into_static.rs
··· 7 7 use std::hash::Hash; 8 8 use std::sync::Arc; 9 9 10 - /// Shamelessly copied from https://github.com/bearcove/merde 10 + /// Shamelessly copied from [](https://github.com/bearcove/merde) 11 11 /// Allow turning a value into an "owned" variant, which can then be 12 12 /// returned, moved, etc. 13 13 ///
+12 -5
crates/jacquard-common/src/lib.rs
··· 1 + //! Common types for the jacquard implementation of atproto 2 + 3 + #![warn(missing_docs)] 4 + pub use cowstr::CowStr; 5 + pub use into_static::IntoStatic; 6 + pub use smol_str; 7 + pub use url; 8 + 9 + /// A copy-on-write immutable string type that uses [`SmolStr`] for 10 + /// the "owned" variant. 1 11 #[macro_use] 2 12 pub mod cowstr; 3 13 #[macro_use] 14 + /// Trait for taking ownership of most borrowed types in jacquard. 4 15 pub mod into_static; 5 16 pub mod macros; 17 + /// Baseline fundamental AT Protocol data types. 6 18 pub mod types; 7 - 8 - pub use cowstr::CowStr; 9 - pub use into_static::IntoStatic; 10 - pub use smol_str; 11 - pub use url;
+50 -23
crates/jacquard-common/src/types/aturi.rs
··· 12 12 use std::sync::LazyLock; 13 13 use std::{ops::Deref, str::FromStr}; 14 14 15 - /// at:// URI type 15 + /// AT Protocol URI (`at://`) for referencing records in repositories 16 + /// 17 + /// AT URIs provide a way to reference records using either a DID or handle as the authority. 18 + /// They're not content-addressed, so the record's contents can change over time. 19 + /// 20 + /// Format: `at://AUTHORITY[/COLLECTION[/RKEY]][#FRAGMENT]` 21 + /// - Authority: DID or handle identifying the repository (required) 22 + /// - Collection: NSID of the record type (optional) 23 + /// - Record key (rkey): specific record identifier (optional) 24 + /// - Fragment: sub-resource identifier (optional, limited support) 16 25 /// 17 - /// based on the regex here: https://github.com/bluesky-social/atproto/blob/main/packages/syntax/src/aturi_validation.ts 26 + /// Examples: 27 + /// - `at://alice.bsky.social` 28 + /// - `at://did:plc:abc123/app.bsky.feed.post/3jk5` 18 29 /// 19 - /// Doesn't support the query segment, but then neither does the Typescript SDK. 30 + /// See: <https://atproto.com/specs/at-uri-scheme> 20 31 #[derive(PartialEq, Eq, Debug)] 21 32 pub struct AtUri<'u> { 22 33 inner: Inner<'u>, ··· 31 42 pub authority: AtIdentifier<'this>, 32 43 #[borrows(uri)] 33 44 #[covariant] 34 - pub path: Option<UriPath<'this>>, 45 + pub path: Option<RepoPath<'this>>, 35 46 #[borrows(uri)] 36 47 #[covariant] 37 48 pub fragment: Option<CowStr<'this>>, ··· 58 69 } else { 59 70 None 60 71 }; 61 - Some(UriPath { collection, rkey }) 72 + Some(RepoPath { collection, rkey }) 62 73 } else { 63 74 None 64 75 } ··· 81 92 } 82 93 } 83 94 84 - /// at:// URI path component (current subset) 95 + /// Path component of an AT URI (collection and optional record key) 96 + /// 97 + /// Represents the `/COLLECTION[/RKEY]` portion of an AT URI. 85 98 #[derive(Clone, PartialEq, Eq, Hash, Debug)] 86 - pub struct UriPath<'u> { 99 + pub struct RepoPath<'u> { 100 + /// Collection NSID (e.g., `app.bsky.feed.post`) 87 101 pub collection: Nsid<'u>, 102 + /// Optional record key identifying a specific record 88 103 pub rkey: Option<RecordKey<Rkey<'u>>>, 89 104 } 90 105 91 - impl IntoStatic for UriPath<'_> { 92 - type Output = UriPath<'static>; 106 + impl IntoStatic for RepoPath<'_> { 107 + type Output = RepoPath<'static>; 93 108 94 109 fn into_static(self) -> Self::Output { 95 - UriPath { 110 + RepoPath { 96 111 collection: self.collection.into_static(), 97 112 rkey: self.rkey.map(|rkey| rkey.into_static()), 98 113 } 99 114 } 100 115 } 101 116 102 - pub type UriPathBuf = UriPath<'static>; 117 + /// Owned (static lifetime) version of `RepoPath` 118 + pub type UriPathBuf = RepoPath<'static>; 103 119 120 + /// Regex for AT URI validation per AT Protocol spec 104 121 pub static ATURI_REGEX: LazyLock<Regex> = LazyLock::new(|| { 105 122 // Fragment allows: / and \ and other special chars. In raw string, backslashes are literal. 106 123 Regex::new(r##"^at://(?<authority>[a-zA-Z0-9._:%-]+)(/(?<collection>[a-zA-Z0-9-.]+)(/(?<rkey>[a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(#(?<fragment>/[a-zA-Z0-9._~:@!$&%')(*+,;=\-\[\]/\\]*))?$"##).unwrap() ··· 125 142 } else { 126 143 None 127 144 }; 128 - Some(UriPath { collection, rkey }) 145 + Some(RepoPath { collection, rkey }) 129 146 } else { 130 147 None 131 148 }; ··· 154 171 } 155 172 } 156 173 174 + /// Infallible constructor for when you know the URI is valid 175 + /// 176 + /// Panics on invalid URIs. Use this when manually constructing URIs from trusted sources. 157 177 pub fn raw(uri: &'u str) -> Self { 158 178 if let Some(parts) = ATURI_REGEX.captures(uri) { 159 179 if let Some(authority) = parts.name("authority") { ··· 166 186 } else { 167 187 None 168 188 }; 169 - Some(UriPath { collection, rkey }) 189 + Some(RepoPath { collection, rkey }) 170 190 } else { 171 191 None 172 192 }; ··· 207 227 } else { 208 228 None 209 229 }; 210 - Some(UriPath { collection, rkey }) 230 + Some(RepoPath { collection, rkey }) 211 231 } else { 212 232 None 213 233 }; ··· 275 295 }) 276 296 } 277 297 298 + /// Get the full URI as a string slice 278 299 pub fn as_str(&self) -> &str { 279 300 { 280 301 let this = &self.inner.borrow_uri(); ··· 282 303 } 283 304 } 284 305 306 + /// Get the authority component (DID or handle) 285 307 pub fn authority(&self) -> &AtIdentifier<'_> { 286 308 self.inner.borrow_authority() 287 309 } 288 310 289 - pub fn path(&self) -> &Option<UriPath<'_>> { 311 + /// Get the path component (collection and optional rkey) 312 + pub fn path(&self) -> &Option<RepoPath<'_>> { 290 313 self.inner.borrow_path() 291 314 } 292 315 316 + /// Get the fragment component if present 293 317 pub fn fragment(&self) -> &Option<CowStr<'_>> { 294 318 self.inner.borrow_fragment() 295 319 } 296 320 321 + /// Get the collection NSID from the path, if present 297 322 pub fn collection(&self) -> Option<&Nsid<'_>> { 298 323 self.inner.borrow_path().as_ref().map(|p| &p.collection) 299 324 } 300 325 326 + /// Get the record key from the path, if present 301 327 pub fn rkey(&self) -> Option<&RecordKey<Rkey<'_>>> { 302 328 self.inner 303 329 .borrow_path() ··· 339 365 } else { 340 366 None 341 367 }; 342 - Some(UriPath { collection, rkey }) 368 + Some(RepoPath { collection, rkey }) 343 369 } else { 344 370 None 345 371 }; ··· 367 393 } else { 368 394 None 369 395 }; 370 - Some(UriPath { collection, rkey }) 396 + Some(RepoPath { collection, rkey }) 371 397 } else { 372 398 None 373 399 } ··· 400 426 } 401 427 } 402 428 429 + /// Fallible constructor, validates, doesn't allocate (static lifetime) 403 430 pub fn new_static(uri: &'static str) -> Result<Self, AtStrError> { 404 431 let uri = uri.as_ref(); 405 432 if let Some(parts) = ATURI_REGEX.captures(uri) { ··· 418 445 } else { 419 446 None 420 447 }; 421 - Some(UriPath { collection, rkey }) 448 + Some(RepoPath { collection, rkey }) 422 449 } else { 423 450 None 424 451 }; ··· 470 497 } else { 471 498 None 472 499 }; 473 - Some(UriPath { collection, rkey }) 500 + Some(RepoPath { collection, rkey }) 474 501 } else { 475 502 None 476 503 }; ··· 498 525 } else { 499 526 None 500 527 }; 501 - Some(UriPath { collection, rkey }) 528 + Some(RepoPath { collection, rkey }) 502 529 } else { 503 530 None 504 531 } ··· 555 582 } else { 556 583 None 557 584 }; 558 - Some(UriPath { collection, rkey }) 585 + Some(RepoPath { collection, rkey }) 559 586 } else { 560 587 None 561 588 } ··· 646 673 } else { 647 674 None 648 675 }; 649 - Some(UriPath { collection, rkey }) 676 + Some(RepoPath { collection, rkey }) 650 677 } else { 651 678 None 652 679 }; ··· 672 699 } else { 673 700 None 674 701 }; 675 - Some(UriPath { collection, rkey }) 702 + Some(RepoPath { collection, rkey }) 676 703 } else { 677 704 None 678 705 }
+25 -7
crates/jacquard-common/src/types/blob.rs
··· 12 12 str::FromStr, 13 13 }; 14 14 15 + /// Blob reference for binary data in AT Protocol 16 + /// 17 + /// Blobs represent uploaded binary data (images, videos, etc.) stored separately from records. 18 + /// They include a CID reference, MIME type, and size information. 19 + /// 20 + /// Serialization differs between formats: 21 + /// - JSON: `ref` is serialized as `{"$link": "cid_string"}` 22 + /// - CBOR: `ref` is the raw CID 15 23 #[derive(Deserialize, Debug, Clone, PartialEq, Eq, Hash)] 16 24 #[serde(rename_all = "camelCase")] 17 25 pub struct Blob<'b> { 26 + /// CID (Content Identifier) reference to the blob data 18 27 pub r#ref: Cid<'b>, 28 + /// MIME type of the blob (e.g., "image/png", "video/mp4") 19 29 #[serde(borrow)] 20 30 pub mime_type: MimeType<'b>, 31 + /// Size of the blob in bytes 21 32 pub size: usize, 22 33 } 23 34 ··· 65 76 } 66 77 } 67 78 68 - /// Current, typed blob reference. 69 - /// Quite dislike this nesting, but it serves the same purpose as it did in Atrium 70 - /// Couple of helper methods and conversions to make it less annoying. 71 - /// TODO: revisit nesting and maybe hand-roll a serde impl that supports this sans nesting 79 + /// Tagged blob reference with `$type` field for serde 80 + /// 81 + /// This enum provides the `{"$type": "blob"}` wrapper expected by AT Protocol's JSON format. 82 + /// Currently only contains the `Blob` variant, but the enum structure supports future extensions. 72 83 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 73 84 #[serde(tag = "$type", rename_all = "lowercase")] 74 85 pub enum BlobRef<'r> { 86 + /// Blob variant with embedded blob data 75 87 #[serde(borrow)] 76 88 Blob(Blob<'r>), 77 89 } 78 90 79 91 impl<'r> BlobRef<'r> { 92 + /// Get the inner blob reference 80 93 pub fn blob(&self) -> &Blob<'r> { 81 94 match self { 82 95 BlobRef::Blob(blob) => blob, ··· 108 121 } 109 122 } 110 123 111 - /// Wrapper for file type 124 + /// MIME type identifier for blob data 125 + /// 126 + /// Used to specify the content type of blobs. Supports patterns like "image/*" and "*/*". 112 127 #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] 113 128 #[serde(transparent)] 114 129 #[repr(transparent)] ··· 120 135 Ok(Self(CowStr::Borrowed(mime_type))) 121 136 } 122 137 138 + /// Fallible constructor, validates, takes ownership 123 139 pub fn new_owned(mime_type: impl AsRef<str>) -> Self { 124 140 Self(CowStr::Owned(mime_type.as_ref().to_smolstr())) 125 141 } 126 142 143 + /// Fallible constructor, validates, doesn't allocate 127 144 pub fn new_static(mime_type: &'static str) -> Self { 128 145 Self(CowStr::new_static(mime_type)) 129 146 } 130 147 131 - /// Fallible constructor from an existing CowStr, borrows 148 + /// Fallible constructor from an existing CowStr 132 149 pub fn from_cowstr(mime_type: CowStr<'m>) -> Result<MimeType<'m>, &'static str> { 133 150 Ok(Self(mime_type)) 134 151 } 135 152 136 - /// Infallible constructor 153 + /// Infallible constructor for trusted MIME type strings 137 154 pub fn raw(mime_type: &'m str) -> Self { 138 155 Self(CowStr::Borrowed(mime_type)) 139 156 } 140 157 158 + /// Get the MIME type as a string slice 141 159 pub fn as_str(&self) -> &str { 142 160 { 143 161 let this = &self.0;
+44 -10
crates/jacquard-common/src/types/cid.rs
··· 4 4 use smol_str::ToSmolStr; 5 5 use std::{convert::Infallible, fmt, marker::PhantomData, ops::Deref, str::FromStr}; 6 6 7 - /// raw 7 + /// CID codec for AT Protocol (raw) 8 8 pub const ATP_CID_CODEC: u64 = 0x55; 9 9 10 - /// SHA-256 10 + /// CID hash function for AT Protocol (SHA-256) 11 11 pub const ATP_CID_HASH: u64 = 0x12; 12 12 13 - /// base 32 13 + /// CID encoding base for AT Protocol (base32 lowercase) 14 14 pub const ATP_CID_BASE: multibase::Base = multibase::Base::Base32Lower; 15 15 16 - #[derive(Debug, Clone, PartialEq, Eq, Hash)] 17 - /// Either the string form of a cid or the ipld form 18 - /// For the IPLD form we also cache the string representation for later use. 16 + /// Content Identifier (CID) for IPLD data in AT Protocol 17 + /// 18 + /// CIDs are self-describing content addresses used to reference IPLD data. 19 + /// This type supports both string and parsed IPLD forms, with string caching 20 + /// for the parsed form to optimize serialization. 19 21 /// 20 - /// Default on deserialization matches the format (if we get bytes, we try to decode) 22 + /// Deserialization automatically detects the format (bytes trigger IPLD parsing). 23 + #[derive(Debug, Clone, PartialEq, Eq, Hash)] 21 24 pub enum Cid<'c> { 22 - Ipld { cid: IpldCid, s: CowStr<'c> }, 25 + /// Parsed IPLD CID with cached string representation 26 + Ipld { 27 + /// Parsed CID structure 28 + cid: IpldCid, 29 + /// Cached base32 string form 30 + s: CowStr<'c>, 31 + }, 32 + /// String-only form (not yet parsed) 23 33 Str(CowStr<'c>), 24 34 } 25 35 36 + /// Errors that can occur when working with CIDs 26 37 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 27 38 pub enum Error { 39 + /// Invalid IPLD CID structure 28 40 #[error("Invalid IPLD CID {:?}", 0)] 29 41 Ipld(#[from] cid::Error), 42 + /// Invalid UTF-8 in CID string 30 43 #[error("{:?}", 0)] 31 44 Utf8(#[from] std::str::Utf8Error), 32 45 } 33 46 34 47 impl<'c> Cid<'c> { 48 + /// Parse a CID from bytes (tries IPLD first, falls back to UTF-8 string) 35 49 pub fn new(cid: &'c [u8]) -> Result<Self, Error> { 36 50 if let Ok(cid) = IpldCid::try_from(cid.as_ref()) { 37 51 Ok(Self::ipld(cid)) ··· 41 55 } 42 56 } 43 57 58 + /// Parse a CID from bytes into an owned (static lifetime) value 44 59 pub fn new_owned(cid: &[u8]) -> Result<Cid<'static>, Error> { 45 60 if let Ok(cid) = IpldCid::try_from(cid.as_ref()) { 46 61 Ok(Self::ipld(cid)) ··· 50 65 } 51 66 } 52 67 68 + /// Construct a CID from a parsed IPLD CID 53 69 pub fn ipld(cid: IpldCid) -> Cid<'static> { 54 70 let s = CowStr::Owned( 55 71 cid.to_string_of_base(ATP_CID_BASE) ··· 59 75 Cid::Ipld { cid, s } 60 76 } 61 77 78 + /// Construct a CID from a string slice (borrows) 62 79 pub fn str(cid: &'c str) -> Self { 63 80 Self::Str(CowStr::Borrowed(cid)) 64 81 } 65 82 83 + /// Construct a CID from a CowStr 66 84 pub fn cow_str(cid: CowStr<'c>) -> Self { 67 85 Self::Str(cid) 68 86 } 69 87 88 + /// Convert to a parsed IPLD CID (parses if needed) 70 89 pub fn to_ipld(&self) -> Result<IpldCid, cid::Error> { 71 90 match self { 72 91 Cid::Ipld { cid, s: _ } => Ok(cid.clone()), ··· 74 93 } 75 94 } 76 95 96 + /// Get the CID as a string slice 77 97 pub fn as_str(&self) -> &str { 78 98 match self { 79 99 Cid::Ipld { cid: _, s } => s.as_ref(), ··· 218 238 } 219 239 } 220 240 221 - /// CID link wrapper that serializes as {"$link": "cid"} in JSON 222 - /// and as raw CID in CBOR 241 + /// CID link wrapper for JSON `{"$link": "cid"}` serialization 242 + /// 243 + /// Wraps a `Cid` and handles format-specific serialization: 244 + /// - JSON: `{"$link": "cid_string"}` 245 + /// - CBOR: raw CID bytes 246 + /// 247 + /// Used in the AT Protocol data model to represent IPLD links in JSON. 223 248 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 224 249 #[repr(transparent)] 225 250 pub struct CidLink<'c>(pub Cid<'c>); 226 251 227 252 impl<'c> CidLink<'c> { 253 + /// Parse a CID link from bytes 228 254 pub fn new(cid: &'c [u8]) -> Result<Self, Error> { 229 255 Ok(Self(Cid::new(cid)?)) 230 256 } 231 257 258 + /// Parse a CID link from bytes into an owned value 232 259 pub fn new_owned(cid: &[u8]) -> Result<CidLink<'static>, Error> { 233 260 Ok(CidLink(Cid::new_owned(cid)?)) 234 261 } 235 262 263 + /// Construct a CID link from a static string 236 264 pub fn new_static(cid: &'static str) -> Self { 237 265 Self(Cid::str(cid)) 238 266 } 239 267 268 + /// Construct a CID link from a parsed IPLD CID 240 269 pub fn ipld(cid: IpldCid) -> CidLink<'static> { 241 270 CidLink(Cid::ipld(cid)) 242 271 } 243 272 273 + /// Construct a CID link from a string slice 244 274 pub fn str(cid: &'c str) -> Self { 245 275 Self(Cid::str(cid)) 246 276 } 247 277 278 + /// Construct a CID link from a CowStr 248 279 pub fn cow_str(cid: CowStr<'c>) -> Self { 249 280 Self(Cid::cow_str(cid)) 250 281 } 251 282 283 + /// Get the CID as a string slice 252 284 pub fn as_str(&self) -> &str { 253 285 self.0.as_str() 254 286 } 255 287 288 + /// Convert to a parsed IPLD CID 256 289 pub fn to_ipld(&self) -> Result<IpldCid, cid::Error> { 257 290 self.0.to_ipld() 258 291 } 259 292 293 + /// Unwrap into the inner Cid 260 294 pub fn into_inner(self) -> Cid<'c> { 261 295 self.0 262 296 }
+5 -5
crates/jacquard-common/src/types/collection.rs
··· 3 3 use serde::Serialize; 4 4 5 5 use crate::types::{ 6 - aturi::UriPath, 6 + aturi::RepoPath, 7 7 nsid::Nsid, 8 8 recordkey::{RecordKey, RecordKeyType, Rkey}, 9 9 }; ··· 26 26 /// 27 27 /// Panics if [`Self::NSID`] is not a valid NSID. 28 28 /// 29 - /// [`Nsid`]: string::Nsid 29 + /// [`Nsid`]: crate::types::string::Nsid 30 30 fn nsid() -> crate::types::nsid::Nsid<'static> { 31 31 Nsid::new_static(Self::NSID).expect("should be valid NSID") 32 32 } ··· 39 39 /// > [`RecordKey`]. 40 40 /// 41 41 /// [Repo Data Structure v3]: https://atproto.com/specs/repository#repo-data-structure-v3 42 - /// [`Nsid`]: string::Nsid 42 + /// [`Nsid`]: crate::types::string::Nsid 43 43 fn repo_path<'u, T: RecordKeyType>( 44 44 rkey: &'u crate::types::recordkey::RecordKey<T>, 45 - ) -> UriPath<'u> { 46 - UriPath { 45 + ) -> RepoPath<'u> { 46 + RepoPath { 47 47 collection: Self::nsid(), 48 48 rkey: Some(RecordKey::from(Rkey::raw(rkey.as_ref()))), 49 49 }
+14 -3
crates/jacquard-common/src/types/datetime.rs
··· 9 9 use crate::{CowStr, IntoStatic}; 10 10 use regex::Regex; 11 11 12 + /// Regex for ISO 8601 datetime validation per AT Protocol spec 12 13 pub static ISO8601_REGEX: LazyLock<Regex> = LazyLock::new(|| { 13 14 Regex::new(r"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?(Z|(\+[0-9]{2}|\-[0-9][1-9]):[0-9]{2})$").unwrap() 14 15 }); 15 16 16 - /// A Lexicon timestamp. 17 + /// AT Protocol datetime (ISO 8601 with specific requirements) 18 + /// 19 + /// Lexicon datetimes use ISO 8601 format with these requirements: 20 + /// - Must include timezone (strongly prefer UTC with 'Z') 21 + /// - Requires whole seconds precision minimum 22 + /// - Supports millisecond and microsecond precision 23 + /// - Uses uppercase 'T' to separate date and time 24 + /// 25 + /// Examples: `"1985-04-12T23:20:50.123Z"`, `"2023-01-01T00:00:00+00:00"` 26 + /// 27 + /// The serialized form is preserved during parsing to ensure exact round-trip serialization. 17 28 #[derive(Clone, Debug, Eq, Hash)] 18 29 pub struct Datetime { 19 - /// Serialized form. Preserved during parsing to ensure round-trip re-serialization. 30 + /// Serialized form preserved from parsing for round-trip consistency 20 31 serialized: CowStr<'static>, 21 - /// Parsed form. 32 + /// Parsed datetime value for comparisons and operations 22 33 dt: chrono::DateTime<chrono::FixedOffset>, 23 34 } 24 35
+16 -1
crates/jacquard-common/src/types/did.rs
··· 7 7 use std::sync::LazyLock; 8 8 use std::{ops::Deref, str::FromStr}; 9 9 10 + /// Decentralized Identifier (DID) for AT Protocol accounts 11 + /// 12 + /// DIDs are the persistent, long-term account identifiers in AT Protocol. Unlike handles, 13 + /// which can change, a DID permanently identifies an account across the network. 14 + /// 15 + /// Supported DID methods: 16 + /// - `did:plc` - Bluesky's novel DID method 17 + /// - `did:web` - Based on HTTPS and DNS 18 + /// 19 + /// Validation enforces a maximum length of 2048 characters and uses the pattern: 20 + /// `did:[method]:[method-specific-id]` where the method is lowercase ASCII and the 21 + /// method-specific-id allows alphanumerics, dots, colons, hyphens, underscores, and percent signs. 22 + /// 23 + /// See: <https://atproto.com/specs/did> 10 24 #[derive(Clone, PartialEq, Eq, Serialize, Hash)] 11 25 #[serde(transparent)] 12 26 #[repr(transparent)] ··· 76 90 /// Infallible constructor for when you *know* the string is a valid DID. 77 91 /// Will panic on invalid DIDs. If you're manually decoding atproto records 78 92 /// or API values you know are valid (rather than using serde), this is the one to use. 79 - /// The From<String> and From<CowStr> impls use the same logic. 93 + /// The `From<String>` and `From<CowStr>` impls use the same logic. 80 94 pub fn raw(did: &'d str) -> Self { 81 95 let did = did.strip_prefix("at://").unwrap_or(did); 82 96 if did.len() > 2048 { ··· 94 108 Self(CowStr::Borrowed(did)) 95 109 } 96 110 111 + /// Get the DID as a string slice 97 112 pub fn as_str(&self) -> &str { 98 113 { 99 114 let this = &self.0;
+20 -3
crates/jacquard-common/src/types/handle.rs
··· 8 8 use std::sync::LazyLock; 9 9 use std::{ops::Deref, str::FromStr}; 10 10 11 + /// AT Protocol handle (human-readable account identifier) 12 + /// 13 + /// Handles are user-friendly account identifiers that must resolve to a DID through DNS 14 + /// or HTTPS. Unlike DIDs, handles can change over time, though they remain an important 15 + /// part of user identity. 16 + /// 17 + /// Format rules: 18 + /// - Maximum 253 characters 19 + /// - At least two segments separated by dots (e.g., "alice.bsky.social") 20 + /// - Each segment is 1-63 characters of ASCII letters, numbers, and hyphens 21 + /// - Segments cannot start or end with a hyphen 22 + /// - Final segment (TLD) cannot start with a digit 23 + /// - Case-insensitive (normalized to lowercase) 24 + /// 25 + /// Certain TLDs are disallowed (.local, .localhost, .arpa, .invalid, .internal, .example, .alt, .onion). 26 + /// 27 + /// See: <https://atproto.com/specs/handle> 11 28 #[derive(Clone, PartialEq, Eq, Serialize, Hash)] 12 29 #[serde(transparent)] 13 30 #[repr(transparent)] 14 31 pub struct Handle<'h>(CowStr<'h>); 15 32 33 + /// Regex for handle validation per AT Protocol spec 16 34 pub static HANDLE_REGEX: LazyLock<Regex> = LazyLock::new(|| { 17 35 Regex::new(r"^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$").unwrap() 18 36 }); 19 - 20 - /// AT Protocol handle 21 37 impl<'h> Handle<'h> { 22 38 /// Fallible constructor, validates, borrows from input 23 39 /// ··· 95 111 /// Infallible constructor for when you *know* the string is a valid handle. 96 112 /// Will panic on invalid handles. If you're manually decoding atproto records 97 113 /// or API values you know are valid (rather than using serde), this is the one to use. 98 - /// The From<String> and From<CowStr> impls use the same logic. 114 + /// The `From<String>` and `From<CowStr>` impls use the same logic. 99 115 /// 100 116 /// Accepts (and strips) preceding '@' or 'at://' if present 101 117 pub fn raw(handle: &'h str) -> Self { ··· 127 143 Self(CowStr::Borrowed(stripped)) 128 144 } 129 145 146 + /// Get the handle as a string slice 130 147 pub fn as_str(&self) -> &str { 131 148 { 132 149 let this = &self.0;
+11 -2
crates/jacquard-common/src/types/ident.rs
··· 8 8 9 9 use crate::CowStr; 10 10 11 - /// An AT Protocol identifier. 11 + /// AT Protocol identifier (either a DID or handle) 12 + /// 13 + /// Represents the union of DIDs and handles, which can both be used to identify 14 + /// accounts in AT Protocol. DIDs are permanent identifiers, while handles are 15 + /// human-friendly and can change. 16 + /// 17 + /// Automatically determines whether a string is a DID or a handle during parsing. 12 18 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Hash)] 13 19 #[serde(untagged)] 14 20 pub enum AtIdentifier<'i> { 21 + /// DID variant 15 22 #[serde(borrow)] 16 23 Did(Did<'i>), 24 + /// Handle variant 17 25 Handle(Handle<'i>), 18 26 } 19 27 ··· 49 57 /// Infallible constructor for when you *know* the string is a valid identifier. 50 58 /// Will panic on invalid identifiers. If you're manually decoding atproto records 51 59 /// or API values you know are valid (rather than using serde), this is the one to use. 52 - /// The From<String> and From<CowStr> impls use the same logic. 60 + /// The `From<String>` and `From<CowStr>` impls use the same logic. 53 61 pub fn raw(ident: &'i str) -> Self { 54 62 if let Ok(did) = ident.parse() { 55 63 AtIdentifier::Did(did) ··· 73 81 } 74 82 } 75 83 84 + /// Get the identifier as a string slice 76 85 pub fn as_str(&self) -> &str { 77 86 match self { 78 87 AtIdentifier::Did(did) => did.as_str(),
+8 -3
crates/jacquard-common/src/types/language.rs
··· 5 5 6 6 use crate::CowStr; 7 7 8 - /// An IETF language tag. 8 + /// IETF BCP 47 language tag for AT Protocol 9 + /// 10 + /// Language tags identify natural languages following the BCP 47 standard. They consist of 11 + /// a 2-3 character language code (e.g., "en", "ja") with optional regional subtags (e.g., "pt-BR"). 9 12 /// 10 - /// Uses langtag crate for validation, but is stored as a SmolStr for size/avoiding allocations 13 + /// Examples: `"ja"` (Japanese), `"pt-BR"` (Brazilian Portuguese), `"en-US"` (US English) 11 14 /// 15 + /// Language tags require semantic parsing rather than simple string comparison. 16 + /// Uses the `langtag` crate for validation but stores as `SmolStr` for efficiency. 12 17 /// TODO: Implement langtag-style semantic matching for this type, delegating to langtag 13 18 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Hash)] 14 19 #[serde(transparent)] ··· 34 39 /// Infallible constructor for when you *know* the string is a valid IETF language tag. 35 40 /// Will panic on invalid tag. If you're manually decoding atproto records 36 41 /// or API values you know are valid (rather than using serde), this is the one to use. 37 - /// The From<String> and From<CowStr> impls use the same logic. 42 + /// The `From<String>` and `From<CowStr>` impls use the same logic. 38 43 pub fn raw(lang: impl AsRef<str>) -> Self { 39 44 let lang = lang.as_ref(); 40 45 let tag = langtag::LangTag::new(lang).expect("valid IETF language tag");
+18 -4
crates/jacquard-common/src/types/nsid.rs
··· 8 8 use std::sync::LazyLock; 9 9 use std::{ops::Deref, str::FromStr}; 10 10 11 - /// Namespaced Identifier (NSID) 11 + /// Namespaced Identifier (NSID) for Lexicon schemas and XRPC endpoints 12 + /// 13 + /// NSIDs provide globally unique identifiers for Lexicon schemas, record types, and XRPC methods. 14 + /// They're structured as reversed domain names with a camelCase name segment. 15 + /// 16 + /// Format: `domain.authority.name` (e.g., `com.example.fooBar`) 17 + /// - Domain authority: reversed domain name (โ‰ค253 chars, lowercase, dots separate segments) 18 + /// - Name: camelCase identifier (letters and numbers only, cannot start with a digit) 19 + /// 20 + /// Validation rules: 21 + /// - Minimum 3 segments 22 + /// - Maximum 317 characters total 23 + /// - Each domain segment is 1-63 characters 24 + /// - Case-sensitive 12 25 /// 13 - /// Stored as SmolStr to ease lifetime issues and because, despite the fact that NSIDs *can* be 317 characters, most are quite short 14 - /// TODO: consider if this should go back to CowStr, or be broken up into segments 26 + /// See: <https://atproto.com/specs/nsid> 15 27 #[derive(Clone, PartialEq, Eq, Serialize, Hash)] 16 28 #[serde(transparent)] 17 29 #[repr(transparent)] 18 30 pub struct Nsid<'n>(CowStr<'n>); 19 31 32 + /// Regex for NSID validation per AT Protocol spec 20 33 pub static NSID_REGEX: LazyLock<Regex> = LazyLock::new(|| { 21 34 Regex::new(r"^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z][a-zA-Z0-9]{0,62})$").unwrap() 22 35 }); ··· 71 84 /// Infallible constructor for when you *know* the string is a valid NSID. 72 85 /// Will panic on invalid NSIDs. If you're manually decoding atproto records 73 86 /// or API values you know are valid (rather than using serde), this is the one to use. 74 - /// The From<String> and From<CowStr> impls use the same logic. 87 + /// The `From<String>` and `From<CowStr>` impls use the same logic. 75 88 pub fn raw(nsid: &'n str) -> Self { 76 89 if nsid.len() > 317 { 77 90 panic!("NSID too long") ··· 100 113 &self.0[split + 1..] 101 114 } 102 115 116 + /// Get the NSID as a string slice 103 117 pub fn as_str(&self) -> &str { 104 118 { 105 119 let this = &self.0;
+31 -11
crates/jacquard-common/src/types/recordkey.rs
··· 9 9 use std::sync::LazyLock; 10 10 use std::{ops::Deref, str::FromStr}; 11 11 12 - /// Trait for generic typed record keys 12 + /// Trait for typed record key implementations 13 13 /// 14 - /// This is deliberately public (so that consumers can develop specialized record key types), 15 - /// but is marked as unsafe, because the implementer is expected to uphold the invariants 16 - /// required by this trait, namely compliance with the [spec](https://atproto.com/specs/record-key) 17 - /// as described by [`RKEY_REGEX`](RKEY_REGEX). 14 + /// Allows different record key types (TID, NSID, literals, generic strings) while 15 + /// maintaining validation guarantees. Implementers must ensure compliance with the 16 + /// AT Protocol [record key specification](https://atproto.com/specs/record-key). 18 17 /// 19 - /// This crate provides implementations for TID, NSID, literals, and generic strings 18 + /// # Safety 19 + /// Implementations must ensure the string representation matches [`RKEY_REGEX`] and 20 + /// is not "." or "..". Built-in implementations: `Tid`, `Nsid`, `Literal<T>`, `Rkey<'_>`. 20 21 pub unsafe trait RecordKeyType: Clone + Serialize { 22 + /// Get the record key as a string slice 21 23 fn as_str(&self) -> &str; 22 24 } 23 25 26 + /// Wrapper for typed record keys 27 + /// 28 + /// Provides a generic container for different record key types while preserving their 29 + /// specific validation guarantees through the `RecordKeyType` trait. 24 30 #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Debug)] 25 31 #[serde(transparent)] 26 32 #[repr(transparent)] ··· 56 62 } 57 63 } 58 64 59 - /// ATProto Record Key (type `any`) 60 - /// Catch-all for any string meeting the overall Record Key requirements detailed https://atproto.com/specs/record-key 65 + /// AT Protocol record key (generic "any" type) 66 + /// 67 + /// Record keys uniquely identify records within a collection. This is the catch-all 68 + /// type for any valid record key string (1-512 characters of alphanumerics, dots, 69 + /// hyphens, underscores, colons, tildes). 70 + /// 71 + /// Common record key types: 72 + /// - TID: timestamp-based (most common) 73 + /// - Literal: fixed keys like "self" 74 + /// - NSID: namespaced identifiers 75 + /// - Any: flexible strings matching the validation rules 76 + /// 77 + /// See: <https://atproto.com/specs/record-key> 61 78 #[derive(Clone, PartialEq, Eq, Serialize, Hash)] 62 79 #[serde(transparent)] 63 80 #[repr(transparent)] ··· 69 86 } 70 87 } 71 88 89 + /// Regex for record key validation per AT Protocol spec 72 90 pub static RKEY_REGEX: LazyLock<Regex> = 73 91 LazyLock::new(|| Regex::new(r"^[a-zA-Z0-9.\-_:~]{1,512}$").unwrap()); 74 92 75 - /// AT Protocol rkey 76 93 impl<'r> Rkey<'r> { 77 94 /// Fallible constructor, validates, borrows from input 78 95 pub fn new(rkey: &'r str) -> Result<Self, AtStrError> { ··· 89 106 } 90 107 } 91 108 92 - /// Fallible constructor, validates, borrows from input 109 + /// Fallible constructor, validates, takes ownership 93 110 pub fn new_owned(rkey: impl AsRef<str>) -> Result<Self, AtStrError> { 94 111 let rkey = rkey.as_ref(); 95 112 if [".", ".."].contains(&rkey) { ··· 140 157 Self(CowStr::Borrowed(rkey)) 141 158 } 142 159 160 + /// Get the record key as a string slice 143 161 pub fn as_str(&self) -> &str { 144 162 { 145 163 let this = &self.0; ··· 265 283 } 266 284 267 285 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 286 + /// Key for a record where only one of an NSID is supposed to exist 268 287 pub struct SelfRecord; 269 288 270 289 impl Literal for SelfRecord { ··· 298 317 /// Infallible constructor for when you *know* the string is a valid rkey. 299 318 /// Will panic on invalid rkeys. If you're manually decoding atproto records 300 319 /// or API values you know are valid (rather than using serde), this is the one to use. 301 - /// The From<String> and From<CowStr> impls use the same logic. 320 + /// The `From<String>` and `From<CowStr>` impls use the same logic. 302 321 pub fn raw(rkey: &str) -> Self { 303 322 if !rkey.eq_ignore_ascii_case(T::LITERAL) { 304 323 panic!( ··· 326 345 } 327 346 } 328 347 348 + /// Get the literal record key as a string slice 329 349 pub fn as_str(&self) -> &str { 330 350 T::LITERAL 331 351 }
+57 -3
crates/jacquard-common/src/types/string.rs
··· 21 21 }, 22 22 }; 23 23 24 - /// ATProto string value 24 + /// Polymorphic AT Protocol string value 25 + /// 26 + /// Represents any AT Protocol string type, automatically detecting and parsing 27 + /// into the appropriate variant. Used internally for generic value handling. 28 + /// 29 + /// Variants are checked in order from most specific to least specific. Note that 30 + /// record keys are intentionally NOT parsed from bare strings as the validation 31 + /// is too permissive and would catch too many values. 25 32 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 26 33 pub enum AtprotoStr<'s> { 34 + /// ISO 8601 datetime 27 35 Datetime(Datetime), 36 + /// BCP 47 language tag 28 37 Language(Language), 38 + /// Timestamp identifier 29 39 Tid(Tid), 40 + /// Namespaced identifier 30 41 Nsid(Nsid<'s>), 42 + /// Decentralized identifier 31 43 Did(Did<'s>), 44 + /// Account handle 32 45 Handle(Handle<'s>), 46 + /// Identifier (DID or handle) 33 47 AtIdentifier(AtIdentifier<'s>), 48 + /// AT URI 34 49 AtUri(AtUri<'s>), 50 + /// Generic URI 35 51 Uri(Uri<'s>), 52 + /// Content identifier 36 53 Cid(Cid<'s>), 54 + /// Record key 37 55 RecordKey(RecordKey<Rkey<'s>>), 56 + /// Plain string (fallback) 38 57 String(CowStr<'s>), 39 58 } 40 59 ··· 77 96 } 78 97 } 79 98 99 + /// Get the string value regardless of variant 80 100 pub fn as_str(&self) -> &str { 81 101 match self { 82 102 Self::Datetime(datetime) => datetime.as_str(), ··· 238 258 help("if something doesn't match the spec, contact the crate author") 239 259 )] 240 260 pub struct AtStrError { 261 + /// AT Protocol spec name this error relates to 241 262 pub spec: SmolStr, 263 + /// The source string that failed to parse 242 264 #[source_code] 243 265 pub source: String, 266 + /// The specific kind of parsing error 244 267 #[source] 245 268 #[diagnostic_source] 246 269 pub kind: StrParseKind, 247 270 } 248 271 249 272 impl AtStrError { 273 + /// Create a new AT string parsing error 250 274 pub fn new(spec: &'static str, source: String, kind: StrParseKind) -> Self { 251 275 Self { 252 276 spec: SmolStr::new_static(spec), ··· 255 279 } 256 280 } 257 281 282 + /// Wrap an existing error with a new spec context 258 283 pub fn wrap(spec: &'static str, source: String, error: AtStrError) -> Self { 259 284 if let Some(span) = match &error.kind { 260 285 StrParseKind::Disallowed { problem, .. } => problem, ··· 309 334 } 310 335 } 311 336 337 + /// Create an error for a string that exceeds the maximum length 312 338 pub fn too_long(spec: &'static str, source: &str, max: usize, actual: usize) -> Self { 313 339 Self { 314 340 spec: SmolStr::new_static(spec), ··· 317 343 } 318 344 } 319 345 346 + /// Create an error for a string below the minimum length 320 347 pub fn too_short(spec: &'static str, source: &str, min: usize, actual: usize) -> Self { 321 348 Self { 322 349 spec: SmolStr::new_static(spec), ··· 348 375 } 349 376 350 377 /// missing component, with the span where it was expected to be founf 378 + /// Create an error for a missing component at a specific span 351 379 pub fn missing_from( 352 380 spec: &'static str, 353 381 source: &str, ··· 364 392 } 365 393 } 366 394 395 + /// Create an error for a regex validation failure 367 396 pub fn regex(spec: &'static str, source: &str, message: SmolStr) -> Self { 368 397 Self { 369 398 spec: SmolStr::new_static(spec), ··· 376 405 } 377 406 } 378 407 408 + /// Kinds of parsing errors for AT Protocol string types 379 409 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 380 410 pub enum StrParseKind { 411 + /// Regex pattern validation failed 381 412 #[error("regex failure - {message}")] 382 413 #[diagnostic(code(jacquard::types::string::regex_fail))] 383 414 RegexFail { 415 + /// Optional span highlighting the problem area 384 416 #[label] 385 417 span: Option<SourceSpan>, 418 + /// Help message explaining the failure 386 419 #[help] 387 420 message: SmolStr, 388 421 }, 422 + /// String exceeds maximum allowed length 389 423 #[error("string too long (allowed: {max}, actual: {actual})")] 390 424 #[diagnostic(code(jacquard::types::string::wrong_length))] 391 - TooLong { max: usize, actual: usize }, 425 + TooLong { 426 + /// Maximum allowed length 427 + max: usize, 428 + /// Actual string length 429 + actual: usize, 430 + }, 392 431 432 + /// String is below minimum required length 393 433 #[error("string too short (allowed: {min}, actual: {actual})")] 394 434 #[diagnostic(code(jacquard::types::string::wrong_length))] 395 - TooShort { min: usize, actual: usize }, 435 + TooShort { 436 + /// Minimum required length 437 + min: usize, 438 + /// Actual string length 439 + actual: usize, 440 + }, 441 + /// String contains disallowed values 396 442 #[error("disallowed - {message}")] 397 443 #[diagnostic(code(jacquard::types::string::disallowed))] 398 444 Disallowed { 445 + /// Optional span highlighting the disallowed content 399 446 #[label] 400 447 problem: Option<SourceSpan>, 448 + /// Help message about what's disallowed 401 449 #[help] 402 450 message: SmolStr, 403 451 }, 452 + /// Required component is missing 404 453 #[error("missing - {message}")] 405 454 #[diagnostic(code(jacquard::atstr::missing_component))] 406 455 MissingComponent { 456 + /// Optional span where the component should be 407 457 #[label] 408 458 span: Option<SourceSpan>, 459 + /// Help message about what's missing 409 460 #[help] 410 461 message: SmolStr, 411 462 }, 463 + /// Wraps another error with additional context 412 464 #[error("{err:?}")] 413 465 #[diagnostic(code(jacquard::atstr::inner))] 414 466 Wrap { 467 + /// Optional span in the outer context 415 468 #[label] 416 469 span: Option<SourceSpan>, 470 + /// The wrapped inner error 417 471 #[source] 418 472 err: Arc<AtStrError>, 419 473 },
+27 -4
crates/jacquard-common/src/types/tid.rs
··· 28 28 builder.finish() 29 29 } 30 30 31 + /// Regex for TID validation per AT Protocol spec 31 32 static TID_REGEX: LazyLock<Regex> = LazyLock::new(|| { 32 33 Regex::new(r"^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$").unwrap() 33 34 }); 34 35 35 - /// A [Timestamp Identifier]. 36 + /// Timestamp Identifier (TID) for record keys and commit revisions 36 37 /// 37 - /// [Timestamp Identifier]: https://atproto.com/specs/tid 38 + /// TIDs are compact, sortable identifiers based on timestamps. They're used as record keys 39 + /// and repository commit revision numbers in AT Protocol. 40 + /// 41 + /// Format: 42 + /// - Always 13 ASCII characters 43 + /// - Base32-sortable encoding (`234567abcdefghijklmnopqrstuvwxyz`) 44 + /// - First 53 bits: microseconds since UNIX epoch 45 + /// - Final 10 bits: random clock identifier for collision resistance 46 + /// 47 + /// TIDs are sortable by timestamp and suitable for use in URLs. Generate new TIDs with 48 + /// `Tid::now()` or `Tid::now_with_clock_id()`. 49 + /// 50 + /// See: <https://atproto.com/specs/tid> 38 51 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Hash)] 39 52 #[serde(transparent)] 40 53 #[repr(transparent)] ··· 71 84 /// Infallible constructor for when you *know* the string is a valid TID. 72 85 /// Will panic on invalid TID. If you're manually decoding atproto records 73 86 /// or API values you know are valid (rather than using serde), this is the one to use. 74 - /// The From<String> and From<CowStr> impls use the same logic. 87 + /// The `From<String>` and `From<CowStr>` impls use the same logic. 75 88 pub fn raw(tid: impl AsRef<str>) -> Self { 76 89 let tid = tid.as_ref(); 77 90 if tid.len() != 13 { ··· 105 118 Self(s32_encode(tid)) 106 119 } 107 120 121 + /// Construct a TID from a timestamp (in microseconds) and clock ID 108 122 pub fn from_time(timestamp: usize, clkid: u32) -> Self { 109 123 let str = smol_str::format_smolstr!( 110 124 "{0}{1:2>2}", ··· 114 128 Self(str) 115 129 } 116 130 131 + /// Extract the timestamp component (microseconds since UNIX epoch) 117 132 pub fn timestamp(&self) -> usize { 118 133 s32decode(self.0[0..11].to_owned()) 119 134 } 120 135 121 - // newer > older 136 + /// Compare two TIDs chronologically (newer > older) 137 + /// 138 + /// Returns 1 if self is newer, -1 if older, 0 if equal 122 139 pub fn compare_to(&self, other: &Tid) -> i8 { 123 140 if self.0 > other.0 { 124 141 return 1; ··· 129 146 0 130 147 } 131 148 149 + /// Check if this TID is newer than another 132 150 pub fn newer_than(&self, other: &Tid) -> bool { 133 151 self.compare_to(other) > 0 134 152 } 135 153 154 + /// Check if this TID is older than another 136 155 pub fn older_than(&self, other: &Tid) -> bool { 137 156 self.compare_to(other) < 0 138 157 } 139 158 159 + /// Generate the next TID in sequence after the given TID 140 160 pub fn next_str(prev: Option<Tid>) -> Result<Self, AtStrError> { 141 161 let prev = match prev { 142 162 None => None, ··· 173 193 } 174 194 } 175 195 196 + /// Decode a base32-sortable string into a usize 176 197 pub fn s32decode(s: String) -> usize { 177 198 let mut i: usize = 0; 178 199 for c in s.chars() { ··· 273 294 } 274 295 275 296 impl Ticker { 297 + /// Create a new TID generator with random clock ID 276 298 pub fn new() -> Self { 277 299 let mut ticker = Self { 278 300 last_timestamp: 0, ··· 284 306 ticker 285 307 } 286 308 309 + /// Generate the next TID, optionally ensuring it's after the given TID 287 310 pub fn next(&mut self, prev: Option<Tid>) -> Tid { 288 311 let now = SystemTime::now() 289 312 .duration_since(SystemTime::UNIX_EPOCH)
+19 -2
crates/jacquard-common/src/types/uri.rs
··· 7 7 types::{aturi::AtUri, cid::Cid, did::Did, string::AtStrError}, 8 8 }; 9 9 10 - /// URI with best-available contextual type 11 - /// TODO: figure out wtf a DNS uri should look like 10 + /// Generic URI with type-specific parsing 11 + /// 12 + /// Automatically detects and parses URIs into the appropriate variant based on 13 + /// the scheme prefix. Used in lexicon where URIs can be of various types. 14 + /// 15 + /// Variants are checked by prefix: `did:`, `at://`, `https://`, `wss://`, `ipld://` 12 16 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 13 17 pub enum Uri<'u> { 18 + /// DID URI (did:) 14 19 Did(Did<'u>), 20 + /// AT Protocol URI (at://) 15 21 At(AtUri<'u>), 22 + /// HTTPS URL 16 23 Https(Url), 24 + /// WebSocket Secure URL 17 25 Wss(Url), 26 + /// IPLD CID URI 18 27 Cid(Cid<'u>), 28 + /// Unrecognized URI scheme (catch-all) 19 29 Any(CowStr<'u>), 20 30 } 21 31 32 + /// Errors that can occur when parsing URIs 22 33 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 23 34 pub enum UriParseError { 35 + /// AT Protocol string parsing error 24 36 #[error("Invalid atproto string: {0}")] 25 37 At(#[from] AtStrError), 38 + /// Generic URL parsing error 26 39 #[error(transparent)] 27 40 Url(#[from] url::ParseError), 41 + /// CID parsing error 28 42 #[error(transparent)] 29 43 Cid(#[from] crate::types::cid::Error), 30 44 } 31 45 32 46 impl<'u> Uri<'u> { 47 + /// Parse a URI from a string slice, borrowing 33 48 pub fn new(uri: &'u str) -> Result<Self, UriParseError> { 34 49 if uri.starts_with("did:") { 35 50 Ok(Uri::Did(Did::new(uri)?)) ··· 46 61 } 47 62 } 48 63 64 + /// Parse a URI from a string, taking ownership 49 65 pub fn new_owned(uri: impl AsRef<str>) -> Result<Uri<'static>, UriParseError> { 50 66 let uri = uri.as_ref(); 51 67 if uri.starts_with("did:") { ··· 63 79 } 64 80 } 65 81 82 + /// Get the URI as a string slice 66 83 pub fn as_str(&self) -> &str { 67 84 match self { 68 85 Uri::Did(did) => did.as_str(),
+6
crates/jacquard-common/src/types/value/parsing.rs
··· 17 17 use std::{collections::BTreeMap, str::FromStr}; 18 18 use url::Url; 19 19 20 + /// Insert a string into an at:// `Data<'_>` map, inferring its type. 20 21 pub fn insert_string<'s>( 21 22 map: &mut BTreeMap<SmolStr, Data<'s>>, 22 23 key: &'s str, ··· 231 232 } 232 233 } 233 234 235 + /// Convert an ipld map to a atproto data model blob if it matches the format 234 236 pub fn cbor_to_blob<'b>(blob: &'b BTreeMap<String, Ipld>) -> Option<Blob<'b>> { 235 237 let mime_type = blob.get("mimeType").and_then(|o| { 236 238 if let Ipld::String(string) = o { ··· 267 269 None 268 270 } 269 271 272 + /// convert a JSON object to an atproto data model blob if it matches the format 270 273 pub fn json_to_blob<'b>(blob: &'b serde_json::Map<String, serde_json::Value>) -> Option<Blob<'b>> { 271 274 let mime_type = blob.get("mimeType").and_then(|v| v.as_str()); 272 275 if let Some(value) = blob.get("ref") { ··· 297 300 None 298 301 } 299 302 303 + /// Infer if something with a "$type" field is a blob or an object 300 304 pub fn infer_from_type(type_field: &str) -> DataModelType { 301 305 match type_field { 302 306 "blob" => DataModelType::Blob, ··· 304 308 } 305 309 } 306 310 311 + /// decode a base64 byte string into atproto data 307 312 pub fn decode_bytes<'s>(bytes: &str) -> Data<'s> { 308 313 // First one should just work. rest are insurance. 309 314 if let Ok(bytes) = BASE64_STANDARD.decode(bytes) { ··· 319 324 } 320 325 } 321 326 327 + /// decode a base64 byte string into atproto raw unvalidated data 322 328 pub fn decode_raw_bytes<'s>(bytes: &str) -> RawData<'s> { 323 329 // First one should just work. rest are insurance. 324 330 if let Ok(bytes) = BASE64_STANDARD.decode(bytes) {
+47
crates/jacquard-common/src/types/value.rs
··· 7 7 use smol_str::{SmolStr, ToSmolStr}; 8 8 use std::collections::BTreeMap; 9 9 10 + /// Conversion utilities for Data types 10 11 pub mod convert; 12 + /// String parsing for AT Protocol types 11 13 pub mod parsing; 14 + /// Serde implementations for Data types 12 15 pub mod serde_impl; 13 16 14 17 #[cfg(test)] 15 18 mod tests; 16 19 20 + /// AT Protocol data model value 21 + /// 22 + /// Represents any valid value in the AT Protocol data model, which supports JSON and CBOR 23 + /// serialization with specific constraints (no floats, CID links, blobs with metadata). 24 + /// 25 + /// This is the generic "unknown data" type used for lexicon values, extra fields captured 26 + /// by `#[lexicon]`, and IPLD data structures. 17 27 #[derive(Debug, Clone, PartialEq, Eq)] 18 28 pub enum Data<'s> { 29 + /// Null value 19 30 Null, 31 + /// Boolean value 20 32 Boolean(bool), 33 + /// Integer value (no floats in AT Protocol) 21 34 Integer(i64), 35 + /// String value (parsed into specific AT Protocol types when possible) 22 36 String(AtprotoStr<'s>), 37 + /// Raw bytes 23 38 Bytes(Bytes), 39 + /// CID link reference 24 40 CidLink(Cid<'s>), 41 + /// Array of values 25 42 Array(Array<'s>), 43 + /// Object/map of values 26 44 Object(Object<'s>), 45 + /// Blob reference with metadata 27 46 Blob(Blob<'s>), 28 47 } 29 48 49 + /// Errors that can occur when working with AT Protocol data 30 50 #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, miette::Diagnostic)] 31 51 pub enum AtDataError { 52 + /// Floating point numbers are not allowed in AT Protocol 32 53 #[error("floating point numbers not allowed in AT protocol data")] 33 54 FloatNotAllowed, 34 55 } 35 56 36 57 impl<'s> Data<'s> { 58 + /// Get the data model type of this value 37 59 pub fn data_type(&self) -> DataModelType { 38 60 match self { 39 61 Data::Null => DataModelType::Null, ··· 69 91 Data::Blob(_) => DataModelType::Blob, 70 92 } 71 93 } 94 + /// Parse a Data value from a JSON value 72 95 pub fn from_json(json: &'s serde_json::Value) -> Result<Self, AtDataError> { 73 96 Ok(if let Some(value) = json.as_bool() { 74 97 Self::Boolean(value) ··· 87 110 }) 88 111 } 89 112 113 + /// Parse a Data value from an IPLD value (CBOR) 90 114 pub fn from_cbor(cbor: &'s Ipld) -> Result<Self, AtDataError> { 91 115 Ok(match cbor { 92 116 Ipld::Null => Data::Null, ··· 121 145 } 122 146 } 123 147 148 + /// Array of AT Protocol data values 124 149 #[derive(Debug, Clone, PartialEq, Eq)] 125 150 pub struct Array<'s>(pub Vec<Data<'s>>); 126 151 ··· 132 157 } 133 158 134 159 impl<'s> Array<'s> { 160 + /// Parse an array from JSON values 135 161 pub fn from_json(json: &'s Vec<serde_json::Value>) -> Result<Self, AtDataError> { 136 162 let mut array = Vec::with_capacity(json.len()); 137 163 for item in json { ··· 139 165 } 140 166 Ok(Self(array)) 141 167 } 168 + /// Parse an array from IPLD values (CBOR) 142 169 pub fn from_cbor(cbor: &'s Vec<Ipld>) -> Result<Self, AtDataError> { 143 170 let mut array = Vec::with_capacity(cbor.len()); 144 171 for item in cbor { ··· 148 175 } 149 176 } 150 177 178 + /// Object/map of AT Protocol data values 151 179 #[derive(Debug, Clone, PartialEq, Eq)] 152 180 pub struct Object<'s>(pub BTreeMap<SmolStr, Data<'s>>); 153 181 ··· 159 187 } 160 188 161 189 impl<'s> Object<'s> { 190 + /// Parse an object from a JSON map with type inference 191 + /// 192 + /// Uses key names to infer the appropriate AT Protocol types for values. 162 193 pub fn from_json( 163 194 json: &'s serde_json::Map<String, serde_json::Value>, 164 195 ) -> Result<Data<'s>, AtDataError> { ··· 232 263 Ok(Data::Object(Object(map))) 233 264 } 234 265 266 + /// Parse an object from IPLD (CBOR) with type inference 267 + /// 268 + /// Uses key names to infer the appropriate AT Protocol types for values. 235 269 pub fn from_cbor(cbor: &'s BTreeMap<String, Ipld>) -> Result<Data<'s>, AtDataError> { 236 270 if let Some(Ipld::String(type_field)) = cbor.get("$type") { 237 271 if parsing::infer_from_type(type_field) == DataModelType::Blob { ··· 288 322 /// E.g. lower-level services, PDS implementations, firehose indexers, relay implementations. 289 323 #[derive(Debug, Clone, PartialEq, Eq)] 290 324 pub enum RawData<'s> { 325 + /// Null value 291 326 Null, 327 + /// Boolean value 292 328 Boolean(bool), 329 + /// Signed integer 293 330 SignedInt(i64), 331 + /// Unsigned integer 294 332 UnsignedInt(u64), 333 + /// String value (no type inference) 295 334 String(CowStr<'s>), 335 + /// Raw bytes 296 336 Bytes(Bytes), 337 + /// CID link reference 297 338 CidLink(Cid<'s>), 339 + /// Array of raw values 298 340 Array(Vec<RawData<'s>>), 341 + /// Object/map of raw values 299 342 Object(BTreeMap<SmolStr, RawData<'s>>), 343 + /// Valid blob reference 300 344 Blob(Blob<'s>), 345 + /// Invalid blob structure (captured for debugging) 301 346 InvalidBlob(Box<RawData<'s>>), 347 + /// Invalid number format, generally a floating point number (captured as bytes) 302 348 InvalidNumber(Bytes), 349 + /// Invalid/unknown data (captured as bytes) 303 350 InvalidData(Bytes), 304 351 }
+30 -1
crates/jacquard-common/src/types/xrpc.rs
··· 1 - use serde::de::DeserializeOwned; 2 1 use serde::{Deserialize, Serialize}; 3 2 use std::error::Error; 4 3 use std::fmt::{self, Debug}; ··· 6 5 use crate::IntoStatic; 7 6 use crate::types::value::Data; 8 7 8 + /// Error type for encoding XRPC requests 9 + #[derive(Debug, thiserror::Error, miette::Diagnostic)] 10 + pub enum EncodeError { 11 + /// Failed to serialize query parameters 12 + #[error("Failed to serialize query: {0}")] 13 + Query( 14 + #[from] 15 + #[source] 16 + serde_html_form::ser::Error, 17 + ), 18 + /// Failed to serialize JSON body 19 + #[error("Failed to serialize JSON: {0}")] 20 + Json( 21 + #[from] 22 + #[source] 23 + serde_json::Error, 24 + ), 25 + /// Other encoding error 26 + #[error("Encoding error: {0}")] 27 + Other(String), 28 + } 29 + 9 30 /// XRPC method type 10 31 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 11 32 pub enum XrpcMethod { ··· 24 45 } 25 46 } 26 47 48 + /// Get the body encoding type for this method (procedures only) 27 49 pub const fn body_encoding(&self) -> Option<&'static str> { 28 50 match self { 29 51 Self::Query => None, ··· 53 75 54 76 /// Error type for this request 55 77 type Err<'de>: Error + Deserialize<'de> + IntoStatic; 78 + 79 + /// Encode the request body for procedures. 80 + /// 81 + /// Default implementation serializes to JSON. Override for non-JSON encodings. 82 + fn encode_body(&self) -> Result<Vec<u8>, EncodeError> { 83 + Ok(serde_json::to_vec(self)?) 84 + } 56 85 } 57 86 58 87 /// Error type for XRPC endpoints that don't define any errors
+51 -16
crates/jacquard-common/src/types.rs
··· 1 1 use serde::{Deserialize, Serialize}; 2 2 3 + /// AT Protocol URI (at://) types and validation 3 4 pub mod aturi; 5 + /// Blob references for binary data 4 6 pub mod blob; 7 + /// Content Identifier (CID) types for IPLD 5 8 pub mod cid; 9 + /// Repository collection trait for records 6 10 pub mod collection; 11 + /// AT Protocol datetime string type 7 12 pub mod datetime; 13 + /// Decentralized Identifier (DID) types and validation 8 14 pub mod did; 15 + /// AT Protocol handle types and validation 9 16 pub mod handle; 17 + /// AT Protocol identifier types (handle or DID) 10 18 pub mod ident; 19 + /// Integer type with validation 11 20 pub mod integer; 21 + /// Language tag types per BCP 47 12 22 pub mod language; 23 + /// CID link wrapper for JSON serialization 13 24 pub mod link; 25 + /// Namespaced Identifier (NSID) types and validation 14 26 pub mod nsid; 27 + /// Record key types and validation 15 28 pub mod recordkey; 29 + /// String types with format validation 16 30 pub mod string; 31 + /// Timestamp Identifier (TID) types and generation 17 32 pub mod tid; 33 + /// URI types with scheme validation 18 34 pub mod uri; 35 + /// Generic data value types for lexicon data model 19 36 pub mod value; 37 + /// XRPC protocol types and traits 20 38 pub mod xrpc; 21 39 22 40 /// Trait for a constant string literal type ··· 25 43 const LITERAL: &'static str; 26 44 } 27 45 46 + /// top-level domains which are not allowed in at:// handles or dids 28 47 pub const DISALLOWED_TLDS: &[&str] = &[ 29 48 ".local", 30 49 ".arpa", ··· 39 58 // "should" "never" actually resolve and get registered in production 40 59 ]; 41 60 61 + /// checks if a string ends with anything from the provided list of strings. 42 62 pub fn ends_with(string: impl AsRef<str>, list: &[&str]) -> bool { 43 63 let string = string.as_ref(); 44 64 for item in list { ··· 51 71 52 72 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)] 53 73 #[serde(rename_all = "kebab-case")] 74 + /// Valid types in the AT protocol [data model](https://atproto.com/specs/data-model). Type marker only, used in concert with `[Data<'_>]`. 54 75 pub enum DataModelType { 76 + /// Null type. IPLD type `null`, JSON type `Null`, CBOR Special Value (major 7) 55 77 Null, 78 + /// Boolean type. IPLD type `boolean`, JSON type Boolean, CBOR Special Value (major 7) 56 79 Boolean, 80 + /// Integer type. IPLD type `integer`, JSON type Number, CBOR Special Value (major 7) 57 81 Integer, 82 + /// Byte type. IPLD type `bytes`, in JSON a `{ "$bytes": bytes }` Object, CBOR Byte String (major 2) 58 83 Bytes, 84 + /// CID (content identifier) link. IPLD type `link`, in JSON a `{ "$link": cid }` Object, CBOR CID (tag 42) 59 85 CidLink, 86 + /// Blob type. No special IPLD type. in JSON a `{ "$type": "blob" }` Object. in CBOR a `{ "$type": "blob" }` Map. 60 87 Blob, 88 + /// Array type. IPLD type `list`. JSON type `Array`, CBOR type Array (major 4) 61 89 Array, 90 + /// Object type. IPLD type `map`. JSON type `Object`, CBOR type Map (major 5). keys are always SmolStr. 62 91 Object, 63 92 #[serde(untagged)] 93 + /// String type (lots of variants). JSON String, CBOR UTF-8 String (major 3) 64 94 String(LexiconStringType), 65 95 } 66 96 67 - #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)] 68 - #[serde(rename_all = "kebab-case")] 69 - pub enum LexiconType { 70 - Params, 71 - Token, 72 - Ref, 73 - Union, 74 - Unknown, 75 - Record, 76 - Query, 77 - Procedure, 78 - Subscription, 79 - #[serde(untagged)] 80 - DataModel(DataModelType), 81 - } 82 - 97 + /// Lexicon string format types for typed strings in the AT Protocol data model 83 98 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)] 84 99 #[serde(rename_all = "kebab-case")] 85 100 pub enum LexiconStringType { 101 + /// ISO 8601 datetime string 86 102 Datetime, 103 + /// AT Protocol URI (at://) 87 104 AtUri, 105 + /// Decentralized Identifier 88 106 Did, 107 + /// AT Protocol handle 89 108 Handle, 109 + /// Handle or DID 90 110 AtIdentifier, 111 + /// Namespaced Identifier 91 112 Nsid, 113 + /// Content Identifier 92 114 Cid, 115 + /// BCP 47 language tag 93 116 Language, 117 + /// Timestamp Identifier 94 118 Tid, 119 + /// Record key 95 120 RecordKey, 121 + /// URI with type constraint 96 122 Uri(UriType), 123 + /// Plain string 97 124 #[serde(untagged)] 98 125 String, 99 126 } 100 127 128 + /// URI scheme types for lexicon URI format constraints 101 129 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] 102 130 #[serde(tag = "type")] 103 131 pub enum UriType { 132 + /// DID URI (did:) 104 133 Did, 134 + /// AT Protocol URI (at://) 105 135 At, 136 + /// HTTPS URI 106 137 Https, 138 + /// WebSocket Secure URI 107 139 Wss, 140 + /// CID URI 108 141 Cid, 142 + /// DNS name 109 143 Dns, 144 + /// Any valid URI 110 145 Any, 111 146 }
+12 -12
crates/jacquard-derive/Cargo.toml
··· 1 1 [package] 2 2 name = "jacquard-derive" 3 + description = "Procedural macros for Jacquard lexicon types" 3 4 edition.workspace = true 4 5 version.workspace = true 5 6 authors.workspace = true ··· 7 8 keywords.workspace = true 8 9 categories.workspace = true 9 10 readme.workspace = true 10 - documentation.workspace = true 11 11 exclude.workspace = true 12 - description.workspace = true 12 + license-file.workspace = true 13 13 14 14 [lib] 15 15 proc-macro = true 16 16 17 17 [dependencies] 18 - heck = "0.5.0" 19 - itertools = "0.14.0" 20 - prettyplease = "0.2.37" 21 - proc-macro2 = "1.0.101" 22 - quote = "1.0.41" 23 - serde = { version = "1.0.228", features = ["derive"] } 24 - serde_json = "1.0.145" 25 - serde_repr = "0.1.20" 26 - serde_with = "3.14.1" 27 - syn = "2.0.106" 18 + heck.workspace = true 19 + itertools.workspace = true 20 + prettyplease.workspace = true 21 + proc-macro2.workspace = true 22 + quote.workspace = true 23 + serde.workspace = true 24 + serde_json.workspace = true 25 + serde_repr.workspace = true 26 + serde_with.workspace = true 27 + syn.workspace = true 28 28 29 29 30 30 [dev-dependencies]
+1 -1
crates/jacquard-derive/tests/open_union.rs
··· 24 24 25 25 #[test] 26 26 fn test_open_union_unknown_variant() { 27 - use jacquard_common::types::value::{Data, Object}; 27 + use jacquard_common::types::value::Data; 28 28 29 29 let json = r#"{"$type":"com.example.unknown","data":"something"}"#; 30 30 let union: TestUnion = serde_json::from_str(json).unwrap();
+18 -15
crates/jacquard-lexicon/Cargo.toml
··· 1 1 [package] 2 2 name = "jacquard-lexicon" 3 + description = "Lexicon schema parsing and code generation for Jacquard" 3 4 edition.workspace = true 4 5 version.workspace = true 5 6 authors.workspace = true ··· 7 8 keywords.workspace = true 8 9 categories.workspace = true 9 10 readme.workspace = true 10 - documentation.workspace = true 11 11 exclude.workspace = true 12 - description.workspace = true 12 + license-file.workspace = true 13 13 14 14 [[bin]] 15 15 name = "jacquard-codegen" 16 16 path = "src/bin/codegen.rs" 17 17 18 18 [dependencies] 19 - clap = { workspace = true } 20 - heck = "0.5.0" 21 - itertools = "0.14.0" 19 + clap.workspace = true 20 + heck.workspace = true 21 + itertools.workspace = true 22 22 jacquard-common = { version = "0.1.0", path = "../jacquard-common" } 23 - miette = { version = "7.6.0", features = ["fancy"] } 24 - prettyplease = "0.2.37" 25 - proc-macro2 = "1.0.101" 26 - quote = "1.0.41" 27 - serde = { version = "1.0.228", features = ["derive"] } 28 - serde_json = "1.0.145" 29 - serde_repr = "0.1.20" 30 - serde_with = "3.14.1" 31 - syn = "2.0.106" 32 - thiserror = "2.0.17" 23 + miette = { workspace = true, features = ["fancy"] } 24 + prettyplease.workspace = true 25 + proc-macro2.workspace = true 26 + quote.workspace = true 27 + serde.workspace = true 28 + serde_json.workspace = true 29 + serde_repr.workspace = true 30 + serde_with.workspace = true 31 + syn.workspace = true 32 + thiserror.workspace = true 33 + 34 + [dev-dependencies] 35 + tempfile = { version = "3.23.0" }
+150 -74
crates/jacquard-lexicon/src/codegen.rs
··· 152 152 let ident = syn::Ident::new(&type_name, proc_macro2::Span::call_site()); 153 153 154 154 // Generate main struct fields 155 - let fields = self.generate_object_fields(nsid, &type_name, obj)?; 155 + let fields = self.generate_object_fields(nsid, &type_name, obj, false)?; 156 156 let doc = self.generate_doc_comment(record.description.as_ref()); 157 157 158 158 // Records always get a lifetime since they have the #[lexicon] attribute ··· 213 213 let type_name = self.def_to_type_name(nsid, def_name); 214 214 let ident = syn::Ident::new(&type_name, proc_macro2::Span::call_site()); 215 215 216 - let fields = self.generate_object_fields(nsid, &type_name, obj)?; 216 + let fields = self.generate_object_fields(nsid, &type_name, obj, false)?; 217 217 let doc = self.generate_doc_comment(obj.description.as_ref()); 218 218 219 219 // Objects always get a lifetime since they have the #[lexicon] attribute ··· 257 257 nsid: &str, 258 258 parent_type_name: &str, 259 259 obj: &LexObject<'static>, 260 + is_builder: bool, 260 261 ) -> Result<TokenStream> { 261 262 let required = obj.required.as_ref().map(|r| r.as_slice()).unwrap_or(&[]); 262 263 263 264 let mut fields = Vec::new(); 264 265 for (field_name, field_type) in &obj.properties { 265 266 let is_required = required.contains(field_name); 266 - let field_tokens = 267 - self.generate_field(nsid, parent_type_name, field_name, field_type, is_required)?; 267 + let field_tokens = self.generate_field( 268 + nsid, 269 + parent_type_name, 270 + field_name, 271 + field_type, 272 + is_required, 273 + is_builder, 274 + )?; 268 275 fields.push(field_tokens); 269 276 } 270 277 ··· 279 286 field_name: &str, 280 287 field_type: &LexObjectProperty<'static>, 281 288 is_required: bool, 289 + is_builder: bool, 282 290 ) -> Result<TokenStream> { 283 291 let field_ident = make_ident(&field_name.to_snake_case()); 284 292 ··· 286 294 self.property_to_rust_type(nsid, parent_type_name, field_name, field_type)?; 287 295 let needs_lifetime = self.property_needs_lifetime(field_type); 288 296 297 + // Check if this is a CowStr field for builder(into) attribute 298 + let is_cowstr = matches!(field_type, LexObjectProperty::String(s) if s.format.is_none()); 299 + 289 300 let rust_type = if is_required { 290 301 rust_type 291 302 } else { ··· 316 327 // Add serde(borrow) to all fields with lifetimes 317 328 if needs_lifetime { 318 329 attrs.push(quote! { #[serde(borrow)] }); 330 + } 331 + 332 + // Add builder(into) for CowStr fields to allow String, &str, etc., but only for builder structs 333 + if is_builder && is_cowstr { 334 + attrs.push(quote! { #[builder(into)] }); 319 335 } 320 336 321 337 Ok(quote! { ··· 662 678 params_has_lifetime, 663 679 has_output, 664 680 has_errors, 681 + false, // queries never have binary inputs 665 682 )?; 666 683 output.push(xrpc_impl); 667 684 ··· 680 697 let type_base = self.def_to_type_name(nsid, def_name); 681 698 let mut output = Vec::new(); 682 699 683 - // Input bodies always have lifetimes (they get #[lexicon] attribute) 684 - let params_has_lifetime = proc.input.is_some(); 700 + // Check if input is a binary body (no schema) 701 + let is_binary_input = proc 702 + .input 703 + .as_ref() 704 + .map(|i| i.schema.is_none()) 705 + .unwrap_or(false); 706 + 707 + // Input bodies with schemas have lifetimes (they get #[lexicon] attribute) 708 + // Binary inputs don't have lifetimes 709 + let params_has_lifetime = proc.input.is_some() && !is_binary_input; 685 710 let has_input = proc.input.is_some(); 686 711 let has_output = proc.output.is_some(); 687 712 let has_errors = proc.errors.is_some(); ··· 726 751 params_has_lifetime, 727 752 has_output, 728 753 has_errors, 754 + is_binary_input, 729 755 )?; 730 756 output.push(xrpc_impl); 731 757 ··· 855 881 let struct_name = format!("{}Message", type_base); 856 882 let struct_ident = syn::Ident::new(&struct_name, proc_macro2::Span::call_site()); 857 883 858 - let fields = self.generate_object_fields("", &struct_name, obj)?; 884 + let fields = self.generate_object_fields("", &struct_name, obj, false)?; 859 885 let doc = self.generate_doc_comment(obj.description.as_ref()); 860 886 861 887 // Subscription message structs always get a lifetime since they have the #[lexicon] attribute ··· 1069 1095 path 1070 1096 }; 1071 1097 1098 + let is_root = dir.components().count() == 0; 1072 1099 let mods: Vec<_> = module_names 1073 1100 .iter() 1074 1101 .map(|name| { 1075 1102 let ident = syn::Ident::new(name, proc_macro2::Span::call_site()); 1076 - quote! { pub mod #ident; } 1103 + if is_root { 1104 + // Top-level modules get feature gates 1105 + quote! { 1106 + #[cfg(feature = #name)] 1107 + pub mod #ident; 1108 + } 1109 + } else { 1110 + quote! { pub mod #ident; } 1111 + } 1077 1112 }) 1078 1113 .collect(); 1079 1114 ··· 1253 1288 let doc = self.generate_doc_comment(p.description.as_ref()); 1254 1289 let needs_lifetime = self.params_need_lifetime(p); 1255 1290 1256 - let derives = 1257 - quote! { #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] }; 1291 + let derives = quote! { 1292 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, bon::Builder)] 1293 + #[builder(start_fn = new)] 1294 + }; 1258 1295 1259 1296 // Generate IntoStatic impl 1260 1297 let field_names: Vec<&str> = p.properties.keys().map(|k| k.as_str()).collect(); ··· 1424 1461 ) -> Result<TokenStream> { 1425 1462 let ident = syn::Ident::new(type_base, proc_macro2::Span::call_site()); 1426 1463 1464 + // Check if this is a binary body (no schema, just raw bytes) 1465 + let is_binary_body = body.schema.is_none(); 1466 + 1427 1467 let fields = if let Some(schema) = &body.schema { 1428 - self.generate_body_fields("", type_base, schema)? 1468 + self.generate_body_fields("", type_base, schema, true)? 1429 1469 } else { 1430 - quote! {} 1470 + // Binary body: just a bytes field 1471 + quote! { 1472 + pub body: bytes::Bytes, 1473 + } 1431 1474 }; 1432 1475 1433 1476 let doc = self.generate_doc_comment(body.description.as_ref()); 1434 1477 1435 - // Input structs always get a lifetime since they have the #[lexicon] attribute 1436 - // which adds extra_data: BTreeMap<..., Data<'a>> 1437 - let struct_def = quote! { 1438 - #doc 1439 - #[jacquard_derive::lexicon] 1440 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 1441 - #[serde(rename_all = "camelCase")] 1442 - pub struct #ident<'a> { 1443 - #fields 1478 + // Binary bodies don't need #[lexicon] attribute or lifetime 1479 + let struct_def = if is_binary_body { 1480 + quote! { 1481 + #doc 1482 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, bon::Builder)] 1483 + #[builder(start_fn = new)] 1484 + #[serde(rename_all = "camelCase")] 1485 + pub struct #ident { 1486 + #fields 1487 + } 1488 + } 1489 + } else { 1490 + // Input structs with schemas: manually add extra_data field with #[builder(default)] 1491 + // for bon compatibility. The #[lexicon] macro will see it exists and skip adding it. 1492 + quote! { 1493 + #doc 1494 + #[jacquard_derive::lexicon] 1495 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, bon::Builder)] 1496 + #[serde(rename_all = "camelCase")] 1497 + #[builder(start_fn = new)] 1498 + pub struct #ident<'a> { 1499 + #fields 1500 + #[serde(flatten)] 1501 + #[serde(borrow)] 1502 + #[builder(default)] 1503 + pub extra_data: ::std::collections::BTreeMap< 1504 + ::jacquard_common::smol_str::SmolStr, 1505 + ::jacquard_common::types::value::Data<'a> 1506 + >, 1507 + } 1444 1508 } 1445 1509 }; 1446 1510 ··· 1458 1522 } 1459 1523 1460 1524 // Generate IntoStatic impl 1461 - let field_names: Vec<&str> = match &body.schema { 1462 - Some(crate::lexicon::LexXrpcBodySchema::Object(obj)) => { 1463 - obj.properties.keys().map(|k| k.as_str()).collect() 1464 - } 1465 - Some(_) => { 1466 - // For Ref or Union schemas, there's just a single flattened field 1467 - vec!["value"] 1468 - } 1469 - None => { 1470 - // No schema means no fields, just extra_data 1471 - vec![] 1525 + let into_static_impl = if is_binary_body { 1526 + // Binary bodies: simple clone of the Bytes field 1527 + quote! { 1528 + impl jacquard_common::IntoStatic for #ident { 1529 + type Output = #ident; 1530 + fn into_static(self) -> Self::Output { 1531 + self 1532 + } 1533 + } 1472 1534 } 1535 + } else { 1536 + let field_names: Vec<&str> = match &body.schema { 1537 + Some(crate::lexicon::LexXrpcBodySchema::Object(obj)) => { 1538 + obj.properties.keys().map(|k| k.as_str()).collect() 1539 + } 1540 + Some(_) => { 1541 + // For Ref or Union schemas, there's just a single flattened field 1542 + vec!["value"] 1543 + } 1544 + None => { 1545 + // No schema means no fields, just extra_data 1546 + vec![] 1547 + } 1548 + }; 1549 + self.generate_into_static_for_struct(type_base, &field_names, true, true) 1473 1550 }; 1474 - let into_static_impl = 1475 - self.generate_into_static_for_struct(type_base, &field_names, true, true); 1476 1551 1477 1552 Ok(quote! { 1478 1553 #struct_def ··· 1491 1566 let ident = syn::Ident::new(&struct_name, proc_macro2::Span::call_site()); 1492 1567 1493 1568 let fields = if let Some(schema) = &body.schema { 1494 - self.generate_body_fields("", &struct_name, schema)? 1569 + self.generate_body_fields("", &struct_name, schema, false)? 1495 1570 } else { 1496 1571 quote! {} 1497 1572 }; ··· 1554 1629 nsid: &str, 1555 1630 parent_type_name: &str, 1556 1631 schema: &LexXrpcBodySchema<'static>, 1632 + is_builder: bool, 1557 1633 ) -> Result<TokenStream> { 1558 1634 use crate::lexicon::LexXrpcBodySchema; 1559 1635 1560 1636 match schema { 1561 1637 LexXrpcBodySchema::Object(obj) => { 1562 - self.generate_object_fields(nsid, parent_type_name, obj) 1638 + self.generate_object_fields(nsid, parent_type_name, obj, is_builder) 1563 1639 } 1564 1640 LexXrpcBodySchema::Ref(ref_type) => { 1565 1641 let rust_type = self.ref_to_rust_type(&ref_type.r#ref)?; ··· 1592 1668 1593 1669 let field_ident = make_ident(&field_name.to_snake_case()); 1594 1670 1595 - let (rust_type, needs_lifetime) = match field_type { 1596 - LexXrpcParametersProperty::Boolean(_) => (quote! { bool }, false), 1597 - LexXrpcParametersProperty::Integer(_) => (quote! { i64 }, false), 1671 + let (rust_type, needs_lifetime, is_cowstr) = match field_type { 1672 + LexXrpcParametersProperty::Boolean(_) => (quote! { bool }, false, false), 1673 + LexXrpcParametersProperty::Integer(_) => (quote! { i64 }, false, false), 1598 1674 LexXrpcParametersProperty::String(s) => { 1599 - (self.string_to_rust_type(s), self.string_needs_lifetime(s)) 1600 - } 1601 - LexXrpcParametersProperty::Unknown(_) => { 1602 - (quote! { jacquard_common::types::value::Data<'a> }, true) 1675 + let is_cowstr = s.format.is_none(); // CowStr for plain strings 1676 + ( 1677 + self.string_to_rust_type(s), 1678 + self.string_needs_lifetime(s), 1679 + is_cowstr, 1680 + ) 1603 1681 } 1682 + LexXrpcParametersProperty::Unknown(_) => ( 1683 + quote! { jacquard_common::types::value::Data<'a> }, 1684 + true, 1685 + false, 1686 + ), 1604 1687 LexXrpcParametersProperty::Array(arr) => { 1605 1688 let needs_lifetime = match &arr.items { 1606 1689 crate::lexicon::LexPrimitiveArrayItem::Boolean(_) ··· 1618 1701 quote! { jacquard_common::types::value::Data<'a> } 1619 1702 } 1620 1703 }; 1621 - (quote! { Vec<#item_type> }, needs_lifetime) 1704 + (quote! { Vec<#item_type> }, needs_lifetime, false) 1622 1705 } 1623 1706 }; 1624 1707 ··· 1637 1720 // Add serde(borrow) to all fields with lifetimes 1638 1721 if needs_lifetime { 1639 1722 attrs.push(quote! { #[serde(borrow)] }); 1723 + } 1724 + 1725 + // Add builder(into) for CowStr fields to allow String, &str, etc. 1726 + if is_cowstr { 1727 + attrs.push(quote! { #[builder(into)] }); 1640 1728 } 1641 1729 1642 1730 Ok(quote! { ··· 1923 2011 params_has_lifetime: bool, 1924 2012 has_output: bool, 1925 2013 has_errors: bool, 2014 + is_binary_input: bool, 1926 2015 ) -> Result<TokenStream> { 1927 2016 let output_type = if has_output { 1928 2017 let output_ident = syn::Ident::new( ··· 1944 2033 quote! { jacquard_common::types::xrpc::GenericError<'de> } 1945 2034 }; 1946 2035 2036 + // Generate encode_body() method for binary inputs 2037 + let encode_body_method = if is_binary_input { 2038 + quote! { 2039 + fn encode_body(&self) -> Result<Vec<u8>, jacquard_common::types::xrpc::EncodeError> { 2040 + Ok(self.body.to_vec()) 2041 + } 2042 + } 2043 + } else { 2044 + quote! {} 2045 + }; 2046 + 1947 2047 if has_params { 1948 2048 // Implement on the params/input struct itself 1949 2049 let request_ident = syn::Ident::new(type_base, proc_macro2::Span::call_site()); ··· 1961 2061 1962 2062 type Output<'de> = #output_type; 1963 2063 type Err<'de> = #error_type; 2064 + 2065 + #encode_body_method 1964 2066 } 1965 2067 }) 1966 2068 } else { ··· 2311 2413 println!("\n{}\n", formatted); 2312 2414 2313 2415 // Check structure 2314 - assert!(formatted.contains("struct GetAuthorFeedParams")); 2416 + assert!(formatted.contains("struct GetAuthorFeed")); 2315 2417 assert!(formatted.contains("struct GetAuthorFeedOutput")); 2316 2418 assert!(formatted.contains("enum GetAuthorFeedError")); 2317 2419 assert!(formatted.contains("pub actor")); ··· 2382 2484 LexiconCorpus::load_from_dir("tests/fixtures/test_lexicons").expect("load corpus"); 2383 2485 let codegen = CodeGenerator::new(&corpus, "test_generated"); 2384 2486 2385 - let output_dir = std::path::PathBuf::from("target/test_codegen_output"); 2487 + let tmp_dir = 2488 + tempfile::tempdir().expect("should be able to create temp directory for output"); 2489 + let output_dir = std::path::PathBuf::from(tmp_dir.path()); 2386 2490 2387 2491 // Clean up any previous test output 2388 2492 let _ = std::fs::remove_dir_all(&output_dir); ··· 2404 2508 .expect("read post.rs"); 2405 2509 assert!(post_content.contains("pub struct Post")); 2406 2510 assert!(post_content.contains("jacquard_common")); 2407 - } 2408 - 2409 - #[test] 2410 - #[ignore] // run manually: cargo test test_generate_full_atproto -- --ignored 2411 - fn test_generate_full_atproto() { 2412 - let corpus = LexiconCorpus::load_from_dir("tests/fixtures/lexicons/atproto/lexicons") 2413 - .expect("load atproto corpus"); 2414 - let codegen = CodeGenerator::new(&corpus, "crate"); 2415 - 2416 - let output_dir = std::path::PathBuf::from("../jacquard-api/src"); 2417 - 2418 - // Clean up existing generated code 2419 - if output_dir.exists() { 2420 - for entry in std::fs::read_dir(&output_dir).expect("read output dir") { 2421 - let entry = entry.expect("dir entry"); 2422 - let path = entry.path(); 2423 - if path.is_dir() { 2424 - std::fs::remove_dir_all(&path).ok(); 2425 - } else if path.extension().map_or(false, |e| e == "rs") { 2426 - std::fs::remove_file(&path).ok(); 2427 - } 2428 - } 2429 - } 2430 - 2431 - // Generate and write 2432 - codegen.write_to_disk(&output_dir).expect("write to disk"); 2433 - 2434 - println!("\nโœจ Generated full atproto API to {:?}", output_dir); 2435 2511 } 2436 2512 }
-47
crates/jacquard-lexicon/src/lib.rs
··· 4 4 pub mod fs; 5 5 pub mod lexicon; 6 6 pub mod union_registry; 7 - 8 - // #[lexicon] 9 - // #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 - // #[serde(rename_all = "camelCase")] 11 - // pub struct Post<'s> { 12 - // ///Client-declared timestamp when this post was originally created. 13 - // pub created_at: jacquard_common::types::string::Datetime, 14 - // #[serde(skip_serializing_if = "core::option::Option::is_none")] 15 - // pub embed: core::option::Option<RecordEmbed<'s>>, 16 - // ///DEPRECATED: replaced by app.bsky.richtext.facet. 17 - // #[serde(skip_serializing_if = "core::option::Option::is_none")] 18 - // pub entities: core::option::Option<Vec<Entity<'s>>>, 19 - // ///Annotations of text (mentions, URLs, hashtags, etc) 20 - // #[serde(skip_serializing_if = "core::option::Option::is_none")] 21 - // pub facets: core::option::Option<Vec<jacquard_api::app_bsky::richtext::Facet<'s>>>, 22 - // ///Self-label values for this post. Effectively content warnings. 23 - // #[serde(skip_serializing_if = "core::option::Option::is_none")] 24 - // pub labels: core::option::Option<RecordLabels<'s>>, 25 - // ///Indicates human language of post primary text content. 26 - // #[serde(skip_serializing_if = "core::option::Option::is_none")] 27 - // pub langs: core::option::Option<Vec<jacquard_common::types::string::Language>>, 28 - // #[serde(skip_serializing_if = "core::option::Option::is_none")] 29 - // pub reply: core::option::Option<ReplyRef<'s>>, 30 - // ///Additional hashtags, in addition to any included in post text and facets. 31 - // #[serde(skip_serializing_if = "core::option::Option::is_none")] 32 - // pub tags: core::option::Option<Vec<jacquard_common::CowStr<'s>>>, 33 - // ///The primary post content. May be an empty string, if there are embeds. 34 - // #[serde(borrow)] 35 - // pub text: jacquard_common::CowStr<'s>, 36 - // } 37 - 38 - // #[open_union] 39 - // #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 40 - // #[serde(tag = "$type")] 41 - // pub enum RecordEmbed<'s> { 42 - // #[serde(borrow)] 43 - // #[serde(rename = "app.bsky.embed.images")] 44 - // EmbedImages(Box<jacquard_api::app_bsky::embed::Images<'s>>), 45 - // #[serde(rename = "app.bsky.embed.video")] 46 - // EmbedVideo(Box<jacquard_api::app_bsky::embed::Video<'s>>), 47 - // #[serde(rename = "app.bsky.embed.external")] 48 - // EmbedExternal(Box<jacquard_api::app_bsky::embed::External<'s>>), 49 - // #[serde(rename = "app.bsky.embed.record")] 50 - // EmbedRecord(Box<jacquard_api::app_bsky::embed::Record<'s>>), 51 - // #[serde(rename = "app.bsky.embed.recordWithMedia")] 52 - // EmbedRecordWithMedia(Box<jacquard_api::app_bsky::embed::RecordWithMedia<'s>>), 53 - // }
-29
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/external.rs
··· 1 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 - #[serde(rename_all = "camelCase")] 3 - pub struct External<'a> { 4 - pub description: jacquard_common::CowStr<'a>, 5 - #[serde(skip_serializing_if = "Option::is_none")] 6 - pub thumb: Option<jacquard_common::types::blob::Blob<'a>>, 7 - pub title: jacquard_common::CowStr<'a>, 8 - pub uri: jacquard_common::types::string::Uri<'a>, 9 - } 10 - ///A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). 11 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 12 - #[serde(rename_all = "camelCase")] 13 - pub struct External<'a> { 14 - pub external: jacquard_common::types::value::Data<'a>, 15 - } 16 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 17 - #[serde(rename_all = "camelCase")] 18 - pub struct View<'a> { 19 - pub external: jacquard_common::types::value::Data<'a>, 20 - } 21 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 22 - #[serde(rename_all = "camelCase")] 23 - pub struct ViewExternal<'a> { 24 - pub description: jacquard_common::CowStr<'a>, 25 - #[serde(skip_serializing_if = "Option::is_none")] 26 - pub thumb: Option<jacquard_common::types::string::Uri<'a>>, 27 - pub title: jacquard_common::CowStr<'a>, 28 - pub uri: jacquard_common::types::string::Uri<'a>, 29 - }
-27
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/images.rs
··· 1 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 - #[serde(rename_all = "camelCase")] 3 - pub struct Image<'a> { 4 - pub alt: jacquard_common::CowStr<'a>, 5 - #[serde(skip_serializing_if = "Option::is_none")] 6 - pub aspect_ratio: Option<jacquard_common::types::value::Data<'a>>, 7 - pub image: jacquard_common::types::blob::Blob<'a>, 8 - } 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 - #[serde(rename_all = "camelCase")] 11 - pub struct Images<'a> { 12 - pub images: Vec<jacquard_common::types::value::Data<'a>>, 13 - } 14 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 15 - #[serde(rename_all = "camelCase")] 16 - pub struct View<'a> { 17 - pub images: Vec<jacquard_common::types::value::Data<'a>>, 18 - } 19 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 20 - #[serde(rename_all = "camelCase")] 21 - pub struct ViewImage<'a> { 22 - pub alt: jacquard_common::CowStr<'a>, 23 - #[serde(skip_serializing_if = "Option::is_none")] 24 - pub aspect_ratio: Option<jacquard_common::types::value::Data<'a>>, 25 - pub fullsize: jacquard_common::types::string::Uri<'a>, 26 - pub thumb: jacquard_common::types::string::Uri<'a>, 27 - }
-50
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/record.rs
··· 1 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 - #[serde(rename_all = "camelCase")] 3 - pub struct Record<'a> { 4 - pub record: test_generated::com_atproto::repo::StrongRef<'a>, 5 - } 6 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 7 - #[serde(rename_all = "camelCase")] 8 - pub struct View<'a> { 9 - pub record: RecordRecord<'a>, 10 - } 11 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 12 - #[serde(rename_all = "camelCase")] 13 - pub struct ViewBlocked<'a> { 14 - pub author: jacquard_common::types::value::Data<'a>, 15 - pub blocked: bool, 16 - pub uri: jacquard_common::types::string::AtUri<'a>, 17 - } 18 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 19 - #[serde(rename_all = "camelCase")] 20 - pub struct ViewDetached<'a> { 21 - pub detached: bool, 22 - pub uri: jacquard_common::types::string::AtUri<'a>, 23 - } 24 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 25 - #[serde(rename_all = "camelCase")] 26 - pub struct ViewNotFound<'a> { 27 - pub not_found: bool, 28 - pub uri: jacquard_common::types::string::AtUri<'a>, 29 - } 30 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 31 - #[serde(rename_all = "camelCase")] 32 - pub struct ViewRecord<'a> { 33 - pub author: jacquard_common::types::value::Data<'a>, 34 - pub cid: jacquard_common::types::string::Cid<'a>, 35 - #[serde(skip_serializing_if = "Option::is_none")] 36 - pub embeds: Option<Vec<jacquard_common::types::value::Data<'a>>>, 37 - pub indexed_at: jacquard_common::types::string::Datetime, 38 - #[serde(skip_serializing_if = "Option::is_none")] 39 - pub labels: Option<Vec<test_generated::com_atproto::label::Label<'a>>>, 40 - #[serde(skip_serializing_if = "Option::is_none")] 41 - pub like_count: Option<i64>, 42 - #[serde(skip_serializing_if = "Option::is_none")] 43 - pub quote_count: Option<i64>, 44 - #[serde(skip_serializing_if = "Option::is_none")] 45 - pub reply_count: Option<i64>, 46 - #[serde(skip_serializing_if = "Option::is_none")] 47 - pub repost_count: Option<i64>, 48 - pub uri: jacquard_common::types::string::AtUri<'a>, 49 - pub value: jacquard_common::types::value::Data<'a>, 50 - }
-12
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/record_with_media.rs
··· 1 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 - #[serde(rename_all = "camelCase")] 3 - pub struct RecordWithMedia<'a> { 4 - pub media: RecordMedia<'a>, 5 - pub record: test_generated::app_bsky::embed::Record<'a>, 6 - } 7 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 - #[serde(rename_all = "camelCase")] 9 - pub struct View<'a> { 10 - pub media: RecordMedia<'a>, 11 - pub record: test_generated::app_bsky::embed::View<'a>, 12 - }
-29
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/video.rs
··· 1 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 - #[serde(rename_all = "camelCase")] 3 - pub struct Caption<'a> { 4 - pub file: jacquard_common::types::blob::Blob<'a>, 5 - pub lang: jacquard_common::types::string::Language, 6 - } 7 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 - #[serde(rename_all = "camelCase")] 9 - pub struct Video<'a> { 10 - #[serde(skip_serializing_if = "Option::is_none")] 11 - pub alt: Option<jacquard_common::CowStr<'a>>, 12 - #[serde(skip_serializing_if = "Option::is_none")] 13 - pub aspect_ratio: Option<jacquard_common::types::value::Data<'a>>, 14 - #[serde(skip_serializing_if = "Option::is_none")] 15 - pub captions: Option<Vec<jacquard_common::types::value::Data<'a>>>, 16 - pub video: jacquard_common::types::blob::Blob<'a>, 17 - } 18 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 19 - #[serde(rename_all = "camelCase")] 20 - pub struct View<'a> { 21 - #[serde(skip_serializing_if = "Option::is_none")] 22 - pub alt: Option<jacquard_common::CowStr<'a>>, 23 - #[serde(skip_serializing_if = "Option::is_none")] 24 - pub aspect_ratio: Option<jacquard_common::types::value::Data<'a>>, 25 - pub cid: jacquard_common::types::string::Cid<'a>, 26 - pub playlist: jacquard_common::types::string::Uri<'a>, 27 - #[serde(skip_serializing_if = "Option::is_none")] 28 - pub thumbnail: Option<jacquard_common::types::string::Uri<'a>>, 29 - }
-5
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed.rs
··· 1 - pub mod external; 2 - pub mod images; 3 - pub mod record; 4 - pub mod record_with_media; 5 - pub mod video;
-57
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed/get_author_feed.rs
··· 1 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 - #[serde(rename_all = "camelCase")] 3 - pub struct GetAuthorFeedParams<'a> { 4 - pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 5 - #[serde(skip_serializing_if = "Option::is_none")] 6 - pub cursor: Option<jacquard_common::CowStr<'a>>, 7 - #[serde(skip_serializing_if = "Option::is_none")] 8 - pub filter: Option<jacquard_common::CowStr<'a>>, 9 - #[serde(skip_serializing_if = "Option::is_none")] 10 - pub include_pins: Option<bool>, 11 - #[serde(skip_serializing_if = "Option::is_none")] 12 - pub limit: Option<i64>, 13 - } 14 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 15 - #[serde(rename_all = "camelCase")] 16 - pub struct GetAuthorFeedOutput<'a> { 17 - #[serde(skip_serializing_if = "Option::is_none")] 18 - pub cursor: Option<jacquard_common::CowStr<'a>>, 19 - pub feed: Vec<jacquard_common::types::value::Data<'a>>, 20 - } 21 - #[derive( 22 - serde::Serialize, 23 - serde::Deserialize, 24 - Debug, 25 - Clone, 26 - PartialEq, 27 - Eq, 28 - thiserror::Error, 29 - miette::Diagnostic 30 - )] 31 - #[serde(tag = "error", content = "message")] 32 - pub enum GetAuthorFeedError { 33 - #[serde(rename = "BlockedActor")] 34 - BlockedActor(Option<jacquard_common::CowStr<'static>>), 35 - #[serde(rename = "BlockedByActor")] 36 - BlockedByActor(Option<jacquard_common::CowStr<'static>>), 37 - } 38 - impl std::fmt::Display for GetAuthorFeedError { 39 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 40 - match self { 41 - Self::BlockedActor(msg) => { 42 - write!(f, "BlockedActor")?; 43 - if let Some(msg) = msg { 44 - write!(f, ": {}", msg)?; 45 - } 46 - Ok(()) 47 - } 48 - Self::BlockedByActor(msg) => { 49 - write!(f, "BlockedByActor")?; 50 - if let Some(msg) = msg { 51 - write!(f, ": {}", msg)?; 52 - } 53 - Ok(()) 54 - } 55 - } 56 - } 57 - }
-65
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed/post.rs
··· 1 - ///Deprecated: use facets instead. 2 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 3 - #[serde(rename_all = "camelCase")] 4 - pub struct Entity<'a> { 5 - pub index: jacquard_common::types::value::Data<'a>, 6 - pub r#type: jacquard_common::CowStr<'a>, 7 - pub value: jacquard_common::CowStr<'a>, 8 - } 9 - ///Record containing a Bluesky post. 10 - #[jacquard_derive::lexicon] 11 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 12 - #[serde(rename_all = "camelCase")] 13 - pub struct Post<'a> { 14 - pub created_at: jacquard_common::types::string::Datetime, 15 - #[serde(skip_serializing_if = "Option::is_none")] 16 - pub embed: Option<RecordEmbed<'a>>, 17 - #[serde(skip_serializing_if = "Option::is_none")] 18 - pub entities: Option<Vec<jacquard_common::types::value::Data<'a>>>, 19 - #[serde(skip_serializing_if = "Option::is_none")] 20 - pub facets: Option<Vec<test_generated::app_bsky::richtext::Facet<'a>>>, 21 - #[serde(skip_serializing_if = "Option::is_none")] 22 - pub labels: Option<RecordLabels<'a>>, 23 - #[serde(skip_serializing_if = "Option::is_none")] 24 - pub langs: Option<Vec<jacquard_common::types::string::Language>>, 25 - #[serde(skip_serializing_if = "Option::is_none")] 26 - pub reply: Option<jacquard_common::types::value::Data<'a>>, 27 - #[serde(skip_serializing_if = "Option::is_none")] 28 - pub tags: Option<Vec<jacquard_common::CowStr<'a>>>, 29 - pub text: jacquard_common::CowStr<'a>, 30 - } 31 - #[jacquard_derive::open_union] 32 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 33 - #[serde(tag = "$type")] 34 - pub enum RecordEmbed<'a> { 35 - #[serde(rename = "app.bsky.embed.images")] 36 - Images(Box<test_generated::app_bsky::embed::Images<'a>>), 37 - #[serde(rename = "app.bsky.embed.video")] 38 - Video(Box<test_generated::app_bsky::embed::Video<'a>>), 39 - #[serde(rename = "app.bsky.embed.external")] 40 - External(Box<test_generated::app_bsky::embed::External<'a>>), 41 - #[serde(rename = "app.bsky.embed.record")] 42 - Record(Box<test_generated::app_bsky::embed::Record<'a>>), 43 - #[serde(rename = "app.bsky.embed.recordWithMedia")] 44 - RecordWithMedia(Box<test_generated::app_bsky::embed::RecordWithMedia<'a>>), 45 - } 46 - #[jacquard_derive::open_union] 47 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 48 - #[serde(tag = "$type")] 49 - pub enum RecordLabels<'a> { 50 - #[serde(rename = "com.atproto.label.defs#selfLabels")] 51 - SelfLabels(Box<test_generated::com_atproto::label::SelfLabels<'a>>), 52 - } 53 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 54 - #[serde(rename_all = "camelCase")] 55 - pub struct ReplyRef<'a> { 56 - pub parent: test_generated::com_atproto::repo::StrongRef<'a>, 57 - pub root: test_generated::com_atproto::repo::StrongRef<'a>, 58 - } 59 - ///Deprecated. Use app.bsky.richtext instead -- A text segment. Start is inclusive, end is exclusive. Indices are for utf16-encoded strings. 60 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 61 - #[serde(rename_all = "camelCase")] 62 - pub struct TextSlice<'a> { 63 - pub end: i64, 64 - pub start: i64, 65 - }
-2
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed.rs
··· 1 - pub mod get_author_feed; 2 - pub mod post;
-32
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/richtext/facet.rs
··· 1 - ///Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. 2 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 3 - #[serde(rename_all = "camelCase")] 4 - pub struct ByteSlice<'a> { 5 - pub byte_end: i64, 6 - pub byte_start: i64, 7 - } 8 - ///Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. 9 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 - #[serde(rename_all = "camelCase")] 11 - pub struct Link<'a> { 12 - pub uri: jacquard_common::types::string::Uri<'a>, 13 - } 14 - ///Annotation of a sub-string within rich text. 15 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 16 - #[serde(rename_all = "camelCase")] 17 - pub struct Facet<'a> { 18 - pub features: Vec<jacquard_common::types::value::Data<'a>>, 19 - pub index: jacquard_common::types::value::Data<'a>, 20 - } 21 - ///Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID. 22 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 23 - #[serde(rename_all = "camelCase")] 24 - pub struct Mention<'a> { 25 - pub did: jacquard_common::types::string::Did<'a>, 26 - } 27 - ///Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). 28 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 29 - #[serde(rename_all = "camelCase")] 30 - pub struct Tag<'a> { 31 - pub tag: jacquard_common::CowStr<'a>, 32 - }
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/richtext.rs
··· 1 - pub mod facet;
-3
crates/jacquard-lexicon/target/test_codegen_output/app_bsky.rs
··· 1 - pub mod embed; 2 - pub mod feed; 3 - pub mod richtext;
-158
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/label.rs
··· 1 - ///Metadata tag on an atproto resource (eg, repo or record). 2 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 3 - #[serde(rename_all = "camelCase")] 4 - pub struct Label<'a> { 5 - #[serde(skip_serializing_if = "Option::is_none")] 6 - pub cid: Option<jacquard_common::types::string::Cid<'a>>, 7 - pub cts: jacquard_common::types::string::Datetime, 8 - #[serde(skip_serializing_if = "Option::is_none")] 9 - pub exp: Option<jacquard_common::types::string::Datetime>, 10 - #[serde(skip_serializing_if = "Option::is_none")] 11 - pub neg: Option<bool>, 12 - #[serde(skip_serializing_if = "Option::is_none")] 13 - pub sig: Option<jacquard_common::types::value::Bytes>, 14 - pub src: jacquard_common::types::string::Did<'a>, 15 - pub uri: jacquard_common::types::string::Uri<'a>, 16 - pub val: jacquard_common::CowStr<'a>, 17 - #[serde(skip_serializing_if = "Option::is_none")] 18 - pub ver: Option<i64>, 19 - } 20 - #[derive(Debug, Clone, PartialEq, Eq, Hash)] 21 - pub enum LabelValue<'a> { 22 - #[serde(rename = "!hide")] 23 - Hide, 24 - #[serde(rename = "!no-promote")] 25 - NoPromote, 26 - #[serde(rename = "!warn")] 27 - Warn, 28 - #[serde(rename = "!no-unauthenticated")] 29 - NoUnauthenticated, 30 - #[serde(rename = "dmca-violation")] 31 - DmcaViolation, 32 - #[serde(rename = "doxxing")] 33 - Doxxing, 34 - #[serde(rename = "porn")] 35 - Porn, 36 - #[serde(rename = "sexual")] 37 - Sexual, 38 - #[serde(rename = "nudity")] 39 - Nudity, 40 - #[serde(rename = "nsfl")] 41 - Nsfl, 42 - #[serde(rename = "gore")] 43 - Gore, 44 - #[serde(untagged)] 45 - Other(jacquard_common::CowStr<'a>), 46 - } 47 - impl<'a> LabelValue<'a> { 48 - pub fn as_str(&self) -> &str { 49 - match self { 50 - Self::Hide => "!hide", 51 - Self::NoPromote => "!no-promote", 52 - Self::Warn => "!warn", 53 - Self::NoUnauthenticated => "!no-unauthenticated", 54 - Self::DmcaViolation => "dmca-violation", 55 - Self::Doxxing => "doxxing", 56 - Self::Porn => "porn", 57 - Self::Sexual => "sexual", 58 - Self::Nudity => "nudity", 59 - Self::Nsfl => "nsfl", 60 - Self::Gore => "gore", 61 - Self::Other(s) => s.as_ref(), 62 - } 63 - } 64 - } 65 - impl<'a> From<&'a str> for LabelValue<'a> { 66 - fn from(s: &'a str) -> Self { 67 - match s { 68 - "!hide" => Self::Hide, 69 - "!no-promote" => Self::NoPromote, 70 - "!warn" => Self::Warn, 71 - "!no-unauthenticated" => Self::NoUnauthenticated, 72 - "dmca-violation" => Self::DmcaViolation, 73 - "doxxing" => Self::Doxxing, 74 - "porn" => Self::Porn, 75 - "sexual" => Self::Sexual, 76 - "nudity" => Self::Nudity, 77 - "nsfl" => Self::Nsfl, 78 - "gore" => Self::Gore, 79 - _ => Self::Other(jacquard_common::CowStr::from(s)), 80 - } 81 - } 82 - } 83 - impl<'a> From<String> for LabelValue<'a> { 84 - fn from(s: String) -> Self { 85 - match s.as_str() { 86 - "!hide" => Self::Hide, 87 - "!no-promote" => Self::NoPromote, 88 - "!warn" => Self::Warn, 89 - "!no-unauthenticated" => Self::NoUnauthenticated, 90 - "dmca-violation" => Self::DmcaViolation, 91 - "doxxing" => Self::Doxxing, 92 - "porn" => Self::Porn, 93 - "sexual" => Self::Sexual, 94 - "nudity" => Self::Nudity, 95 - "nsfl" => Self::Nsfl, 96 - "gore" => Self::Gore, 97 - _ => Self::Other(jacquard_common::CowStr::from(s)), 98 - } 99 - } 100 - } 101 - impl<'a> AsRef<str> for LabelValue<'a> { 102 - fn as_ref(&self) -> &str { 103 - self.as_str() 104 - } 105 - } 106 - impl<'a> serde::Serialize for LabelValue<'a> { 107 - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 108 - where 109 - S: serde::Serializer, 110 - { 111 - serializer.serialize_str(self.as_str()) 112 - } 113 - } 114 - impl<'de, 'a> serde::Deserialize<'de> for LabelValue<'a> 115 - where 116 - 'de: 'a, 117 - { 118 - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 119 - where 120 - D: serde::Deserializer<'de>, 121 - { 122 - let s = <&'de str>::deserialize(deserializer)?; 123 - Ok(Self::from(s)) 124 - } 125 - } 126 - ///Declares a label value and its expected interpretations and behaviors. 127 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 128 - #[serde(rename_all = "camelCase")] 129 - pub struct LabelValueDefinition<'a> { 130 - #[serde(skip_serializing_if = "Option::is_none")] 131 - pub adult_only: Option<bool>, 132 - pub blurs: jacquard_common::CowStr<'a>, 133 - #[serde(skip_serializing_if = "Option::is_none")] 134 - pub default_setting: Option<jacquard_common::CowStr<'a>>, 135 - pub identifier: jacquard_common::CowStr<'a>, 136 - pub locales: Vec<jacquard_common::types::value::Data<'a>>, 137 - pub severity: jacquard_common::CowStr<'a>, 138 - } 139 - ///Strings which describe the label in the UI, localized into a specific language. 140 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 141 - #[serde(rename_all = "camelCase")] 142 - pub struct LabelValueDefinitionStrings<'a> { 143 - pub description: jacquard_common::CowStr<'a>, 144 - pub lang: jacquard_common::types::string::Language, 145 - pub name: jacquard_common::CowStr<'a>, 146 - } 147 - ///Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel. 148 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 149 - #[serde(rename_all = "camelCase")] 150 - pub struct SelfLabel<'a> { 151 - pub val: jacquard_common::CowStr<'a>, 152 - } 153 - ///Metadata tags on an atproto record, published by the author within the record. 154 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 155 - #[serde(rename_all = "camelCase")] 156 - pub struct SelfLabels<'a> { 157 - pub values: Vec<jacquard_common::types::value::Data<'a>>, 158 - }
-6
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/repo/strong_ref.rs
··· 1 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 - #[serde(rename_all = "camelCase")] 3 - pub struct StrongRef<'a> { 4 - pub cid: jacquard_common::types::string::Cid<'a>, 5 - pub uri: jacquard_common::types::string::AtUri<'a>, 6 - }
-1
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/repo.rs
··· 1 - pub mod strong_ref;
-2
crates/jacquard-lexicon/target/test_codegen_output/com_atproto.rs
··· 1 - pub mod label; 2 - pub mod repo;
-2
crates/jacquard-lexicon/target/test_codegen_output/lib.rs
··· 1 - pub mod app_bsky; 2 - pub mod com_atproto;
-15
crates/jacquard-lexicon/tests/regen_api.rs
··· 1 - use jacquard_lexicon::codegen::CodeGenerator; 2 - use jacquard_lexicon::corpus::LexiconCorpus; 3 - 4 - #[test] 5 - #[ignore] // Run with: cargo test --test regen_api -- --ignored 6 - fn regenerate_api() { 7 - let corpus = LexiconCorpus::load_from_dir("tests/fixtures/lexicons/atproto/lexicons").expect("load corpus"); 8 - let codegen = CodeGenerator::new(&corpus, "crate"); 9 - 10 - codegen 11 - .write_to_disk(std::path::Path::new("../jacquard-api/src")) 12 - .expect("write to disk"); 13 - 14 - println!("Generated {} lexicons", corpus.len()); 15 - }
+1
nix/modules/devshell.nix
··· 17 17 nixd # Nix language server 18 18 bacon 19 19 rust-analyzer 20 + cargo-release 20 21 ]; 21 22 }; 22 23 };
-120
regen.rs
··· 1 - use jacquard_lexicon::codegen::CodeGenerator; 2 - use jacquard_lexicon::corpus::LexiconCorpus; 3 - use prettyplease; 4 - use std::collections::BTreeMap; 5 - use std::fs; 6 - use std::path::Path; 7 - 8 - fn main() -> Result<(), Box<dyn std::error::Error>> { 9 - let lexicons_path = "lexicons/atproto"; 10 - let output_path = "crates/jacquard-api/src"; 11 - let root_module = "crate"; 12 - 13 - println!("Loading lexicons from {}...", lexicons_path); 14 - let corpus = LexiconCorpus::load_from_dir(lexicons_path)?; 15 - println!("Loaded {} lexicons", corpus.len()); 16 - 17 - println!("Generating code..."); 18 - let generator = CodeGenerator::new(&corpus, root_module); 19 - 20 - // Group by module 21 - let mut modules: BTreeMap<String, Vec<(String, String)>> = BTreeMap::new(); 22 - 23 - for (nsid, doc) in corpus.iter() { 24 - let nsid_str = nsid.as_str(); 25 - 26 - // Get module path: app.bsky.feed.post -> app_bsky/feed 27 - let parts: Vec<&str> = nsid_str.split('.').collect(); 28 - let module_path = if parts.len() >= 3 { 29 - let first_two = format!("{}_{}", parts[0], parts[1]); 30 - if parts.len() > 3 { 31 - let middle: Vec<&str> = parts[2..parts.len() - 1].iter().copied().collect(); 32 - format!("{}/{}", first_two, middle.join("/")) 33 - } else { 34 - first_two 35 - } 36 - } else { 37 - parts.join("_") 38 - }; 39 - 40 - let file_name = parts.last().unwrap().to_string(); 41 - 42 - for (def_name, def) in &doc.defs { 43 - match generator.generate_def(nsid_str, def_name, def) { 44 - Ok(tokens) => { 45 - let code = prettyplease::unparse(&syn::parse_file(&tokens.to_string())?); 46 - modules 47 - .entry(format!("{}/{}.rs", module_path, file_name)) 48 - .or_default() 49 - .push((def_name.to_string(), code)); 50 - } 51 - Err(e) => { 52 - eprintln!("Error generating {}.{}: {:?}", nsid_str, def_name, e); 53 - } 54 - } 55 - } 56 - } 57 - 58 - // Write files 59 - for (file_path, defs) in modules { 60 - let full_path = Path::new(output_path).join(&file_path); 61 - 62 - // Create parent directory 63 - if let Some(parent) = full_path.parent() { 64 - fs::create_dir_all(parent)?; 65 - } 66 - 67 - let content = defs.iter().map(|(_, code)| code.as_str()).collect::<Vec<_>>().join("\n"); 68 - fs::write(&full_path, content)?; 69 - println!("Wrote {}", file_path); 70 - } 71 - 72 - // Generate mod.rs files 73 - println!("Generating mod.rs files..."); 74 - generate_mod_files(Path::new(output_path))?; 75 - 76 - println!("Done!"); 77 - Ok(()) 78 - } 79 - 80 - fn generate_mod_files(root: &Path) -> Result<(), Box<dyn std::error::Error>> { 81 - // Find all directories 82 - for entry in fs::read_dir(root)? { 83 - let entry = entry?; 84 - let path = entry.path(); 85 - 86 - if path.is_dir() { 87 - let dir_name = path.file_name().unwrap().to_str().unwrap(); 88 - 89 - // Recursively generate for subdirectories 90 - generate_mod_files(&path)?; 91 - 92 - // Generate mod.rs for this directory 93 - let mut mods = Vec::new(); 94 - for sub_entry in fs::read_dir(&path)? { 95 - let sub_entry = sub_entry?; 96 - let sub_path = sub_entry.path(); 97 - 98 - if sub_path.is_file() { 99 - if let Some(name) = sub_path.file_stem() { 100 - let name_str = name.to_str().unwrap(); 101 - if name_str != "mod" { 102 - mods.push(format!("pub mod {};", name_str)); 103 - } 104 - } 105 - } else if sub_path.is_dir() { 106 - if let Some(name) = sub_path.file_name() { 107 - mods.push(format!("pub mod {};", name.to_str().unwrap())); 108 - } 109 - } 110 - } 111 - 112 - if !mods.is_empty() { 113 - let mod_content = mods.join("\n") + "\n"; 114 - fs::write(path.join("mod.rs"), mod_content)?; 115 - } 116 - } 117 - } 118 - 119 - Ok(()) 120 - }
+1 -1
rust-toolchain.toml
··· 1 1 [toolchain] 2 2 channel = "stable" 3 - profile = "complete" 3 + profile = "default"