Skip to main content

max / makenotwork

MNW synckit-client/bento/mnw-cli/pom: adopt lint block, fix clippy, fmt Adopt the shared clippy::pedantic block and reach green under 'cargo clippy --all-targets -- -D warnings': format!-push to write!, #[must_use] on builders, Option<&T> over &Option<T>, borrow unused-by-value params, name concrete Default types, epsilon float compares. Scoped #[allow]s (with reasons) only for serde-bound field names, rhai's boxed error type, and a serde skip_serializing_if signature.
Co-Authored-By
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-24 15:01 UTC
Signed with PGP, not checked
Commit: 28eedb8ab7fda843637a96f3c8c75128095a9bf5
Parent: 1dce76f
151 files changed, +1803 insertions, -1181 deletions
@@ -19,3 +19,35 @@
19 19 bytes = "1"
20 20 synckit-client = { path = "../shared/synckit-client", default-features = false }
21 21 uuid = "1"
22 +
23 + [lints.rust]
24 + unused = "warn"
25 + unreachable_pub = "warn"
26 +
27 + [lints.clippy]
28 + pedantic = { level = "warn", priority = -1 }
29 + # Allow-list tuned from a measured breakdown across server/multithreaded/pter
30 + # (2026-07-22). These are the high-churn / low-signal pedantic lints; everything
31 + # else in `pedantic` stays a warning. Keep this block identical across repos.
32 + module_name_repetitions = "allow"
33 + # Doc lints. No docs-completeness push is underway.
34 + missing_errors_doc = "allow"
35 + missing_panics_doc = "allow"
36 + doc_markdown = "allow"
37 + # Numeric casts. Endemic and mostly intentional in size and byte math.
38 + cast_possible_truncation = "allow"
39 + cast_sign_loss = "allow"
40 + cast_precision_loss = "allow"
41 + cast_possible_wrap = "allow"
42 + cast_lossless = "allow"
43 + # Subjective structure and style nags. High churn, low signal.
44 + must_use_candidate = "allow"
45 + too_many_lines = "allow"
46 + struct_excessive_bools = "allow"
47 + similar_names = "allow"
48 + items_after_statements = "allow"
49 + single_match_else = "allow"
50 + # Frequent false-positives in TUI and router-heavy code.
51 + match_same_arms = "allow"
52 + unnecessary_wraps = "allow"
53 + type_complexity = "allow"
@@ -79,3 +79,35 @@
79 79 tower = { version = "0.5", features = ["util"] }
80 80 http-body-util = "0.1"
81 81 rcgen = "0.14.7"
82 +
83 + [lints.rust]
84 + unused = "warn"
85 + unreachable_pub = "warn"
86 +
87 + [lints.clippy]
88 + pedantic = { level = "warn", priority = -1 }
89 + # Allow-list tuned from a measured breakdown across server/multithreaded/pter
90 + # (2026-07-22). These are the high-churn / low-signal pedantic lints; everything
91 + # else in `pedantic` stays a warning. Keep this block identical across repos.
92 + module_name_repetitions = "allow"
93 + # Doc lints. No docs-completeness push is underway.
94 + missing_errors_doc = "allow"
95 + missing_panics_doc = "allow"
96 + doc_markdown = "allow"
97 + # Numeric casts. Endemic and mostly intentional in size and byte math.
98 + cast_possible_truncation = "allow"
99 + cast_sign_loss = "allow"
100 + cast_precision_loss = "allow"
101 + cast_possible_wrap = "allow"
102 + cast_lossless = "allow"
103 + # Subjective structure and style nags. High churn, low signal.
104 + must_use_candidate = "allow"
105 + too_many_lines = "allow"
106 + struct_excessive_bools = "allow"
107 + similar_names = "allow"
108 + items_after_statements = "allow"
109 + single_match_else = "allow"
110 + # Frequent false-positives in TUI and router-heavy code.
111 + match_same_arms = "allow"
112 + unnecessary_wraps = "allow"
113 + type_complexity = "allow"
@@ -37,3 +37,35 @@
37 37 tower = { version = "0.5", features = ["util"] }
38 38 http-body-util = "0.1"
39 39 reqwest = { version = "0.13", default-features = false, features = ["json", "rustls"] }
40 +
41 + [lints.rust]
42 + unused = "warn"
43 + unreachable_pub = "warn"
44 +
45 + [lints.clippy]
46 + pedantic = { level = "warn", priority = -1 }
47 + # Allow-list tuned from a measured breakdown across server/multithreaded/pter
48 + # (2026-07-22). These are the high-churn / low-signal pedantic lints; everything
49 + # else in `pedantic` stays a warning. Keep this block identical across repos.
50 + module_name_repetitions = "allow"
51 + # Doc lints. No docs-completeness push is underway.
52 + missing_errors_doc = "allow"
53 + missing_panics_doc = "allow"
54 + doc_markdown = "allow"
55 + # Numeric casts. Endemic and mostly intentional in size and byte math.
56 + cast_possible_truncation = "allow"
57 + cast_sign_loss = "allow"
58 + cast_precision_loss = "allow"
59 + cast_possible_wrap = "allow"
60 + cast_lossless = "allow"
61 + # Subjective structure and style nags. High churn, low signal.
62 + must_use_candidate = "allow"
63 + too_many_lines = "allow"
64 + struct_excessive_bools = "allow"
65 + similar_names = "allow"
66 + items_after_statements = "allow"
67 + single_match_else = "allow"
68 + # Frequent false-positives in TUI and router-heavy code.
69 + match_same_arms = "allow"
70 + unnecessary_wraps = "allow"
71 + type_complexity = "allow"
@@ -34,6 +34,29 @@
34 34 source = "registry+https://github.com/rust-lang/crates.io-index"
35 35 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
36 36
37 + [[package]]
38 + name = "aws-lc-rs"
39 + version = "1.17.3"
40 + source = "registry+https://github.com/rust-lang/crates.io-index"
41 + checksum = "00bdb5da18dac48ca2cc7cd4a98e533e8635a58e2361d13a1a4ee3888e0d72f1"
42 + dependencies = [
43 + "aws-lc-sys",
44 + "zeroize",
45 + ]
46 +
47 + [[package]]
48 + name = "aws-lc-sys"
49 + version = "0.43.0"
50 + source = "registry+https://github.com/rust-lang/crates.io-index"
51 + checksum = "43103168cc76fe62678a375e722fc9cb3a0146159ac5828bc4f0dfd755c2224c"
52 + dependencies = [
53 + "cc",
54 + "cmake",
55 + "dunce",
56 + "fs_extra",
57 + "pkg-config",
58 + ]
59 +
37 60 [[package]]
38 61 name = "base64"
39 62 version = "0.22.1"
@@ -80,6 +103,8 @@
80 103 checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
81 104 dependencies = [
82 105 "find-msvc-tools",
106 + "jobserver",
107 + "libc",
83 108 "shlex",
84 109 ]
85 110
@@ -95,6 +120,41 @@
95 120 source = "registry+https://github.com/rust-lang/crates.io-index"
96 121 checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
97 122
123 + [[package]]
124 + name = "cmake"
125 + version = "0.1.58"
126 + source = "registry+https://github.com/rust-lang/crates.io-index"
127 + checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
128 + dependencies = [
129 + "cc",
130 + ]
131 +
132 + [[package]]
133 + name = "combine"
134 + version = "4.6.7"
135 + source = "registry+https://github.com/rust-lang/crates.io-index"
136 + checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
137 + dependencies = [
138 + "bytes",
139 + "memchr",
140 + ]
141 +
142 + [[package]]
143 + name = "core-foundation"
144 + version = "0.10.1"
145 + source = "registry+https://github.com/rust-lang/crates.io-index"
146 + checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
147 + dependencies = [
148 + "core-foundation-sys",
149 + "libc",
150 + ]
151 +
152 + [[package]]
153 + name = "core-foundation-sys"
154 + version = "0.8.7"
155 + source = "registry+https://github.com/rust-lang/crates.io-index"
156 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
157 +
98 158 [[package]]
99 159 name = "displaydoc"
100 160 version = "0.2.6"
@@ -106,6 +166,12 @@
106 166 "syn",
107 167 ]
108 168
169 + [[package]]
170 + name = "dunce"
171 + version = "1.0.5"
172 + source = "registry+https://github.com/rust-lang/crates.io-index"
173 + checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
174 +
109 175 [[package]]
110 176 name = "equivalent"
111 177 version = "1.0.2"
@@ -149,6 +215,12 @@
149 215 "percent-encoding",
150 216 ]
151 217
218 + [[package]]
219 + name = "fs_extra"
220 + version = "1.3.0"
221 + source = "registry+https://github.com/rust-lang/crates.io-index"
222 + checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
223 +
152 224 [[package]]
153 225 name = "futures-channel"
154 226 version = "0.3.32"
@@ -348,7 +420,6 @@
348 420 "tokio",
349 421 "tokio-rustls",
350 422 "tower-service",
351 - "webpki-roots",
352 423 ]
353 424
354 425 [[package]]
@@ -507,6 +578,65 @@
507 578 source = "registry+https://github.com/rust-lang/crates.io-index"
508 579 checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
509 580
581 + [[package]]
582 + name = "jni"
583 + version = "0.22.4"
584 + source = "registry+https://github.com/rust-lang/crates.io-index"
585 + checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
586 + dependencies = [
587 + "cfg-if",
588 + "combine",
589 + "jni-macros",
590 + "jni-sys",
591 + "log",
592 + "simd_cesu8",
593 + "thiserror",
594 + "walkdir",
595 + "windows-link",
596 + ]
597 +
598 + [[package]]
599 + name = "jni-macros"
600 + version = "0.22.4"
601 + source = "registry+https://github.com/rust-lang/crates.io-index"
602 + checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
603 + dependencies = [
604 + "proc-macro2",
605 + "quote",
606 + "rustc_version",
607 + "simd_cesu8",
608 + "syn",
609 + ]
610 +
611 + [[package]]
612 + name = "jni-sys"
613 + version = "0.4.1"
614 + source = "registry+https://github.com/rust-lang/crates.io-index"
615 + checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
616 + dependencies = [
617 + "jni-sys-macros",
618 + ]
619 +
620 + [[package]]
621 + name = "jni-sys-macros"
622 + version = "0.4.1"
623 + source = "registry+https://github.com/rust-lang/crates.io-index"
624 + checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
625 + dependencies = [
626 + "quote",
627 + "syn",
628 + ]
629 +
630 + [[package]]
631 + name = "jobserver"
632 + version = "0.1.35"
633 + source = "registry+https://github.com/rust-lang/crates.io-index"
634 + checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3"
635 + dependencies = [
636 + "getrandom 0.4.2",
637 + "libc",
638 + ]
639 +
510 640 [[package]]
511 641 name = "js-sys"
512 642 version = "0.3.99"
@@ -602,6 +732,12 @@
602 732 source = "registry+https://github.com/rust-lang/crates.io-index"
603 733 checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
604 734
735 + [[package]]
736 + name = "openssl-probe"
737 + version = "0.2.1"
738 + source = "registry+https://github.com/rust-lang/crates.io-index"
739 + checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
740 +
605 741 [[package]]
606 742 name = "ops-exec"
607 743 version = "0.1.0"
@@ -630,6 +766,12 @@
630 766 source = "registry+https://github.com/rust-lang/crates.io-index"
631 767 checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
632 768
769 + [[package]]
770 + name = "pkg-config"
771 + version = "0.3.33"
772 + source = "registry+https://github.com/rust-lang/crates.io-index"
773 + checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
774 +
633 775 [[package]]
634 776 name = "potential_utf"
635 777 version = "0.1.5"
@@ -693,6 +835,7 @@
693 835 source = "registry+https://github.com/rust-lang/crates.io-index"
694 836 checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
695 837 dependencies = [
838 + "aws-lc-rs",
696 839 "bytes",
697 840 "getrandom 0.3.4",
698 841 "lru-slab",
@@ -791,9 +934,9 @@
791 934
792 935 [[package]]
793 936 name = "reqwest"
794 - version = "0.12.28"
937 + version = "0.13.4"
795 938 source = "registry+https://github.com/rust-lang/crates.io-index"
796 - checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
939 + checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
797 940 dependencies = [
798 941 "base64",
799 942 "bytes",
@@ -812,6 +955,7 @@
812 955 "quinn",
813 956 "rustls",
814 957 "rustls-pki-types",
958 + "rustls-platform-verifier",
815 959 "serde",
816 960 "serde_json",
817 961 "serde_urlencoded",
@@ -827,7 +971,6 @@
827 971 "wasm-bindgen-futures",
828 972 "wasm-streams",
829 973 "web-sys",
830 - "webpki-roots",
831 974 ]
832 975
833 976 [[package]]
@@ -850,6 +993,15 @@
850 993 source = "registry+https://github.com/rust-lang/crates.io-index"
851 994 checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
852 995
996 + [[package]]
997 + name = "rustc_version"
998 + version = "0.4.1"
999 + source = "registry+https://github.com/rust-lang/crates.io-index"
1000 + checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
1001 + dependencies = [
1002 + "semver",
1003 + ]
1004 +
853 1005 [[package]]
854 1006 name = "rustix"
855 1007 version = "1.1.4"
@@ -869,14 +1021,26 @@
869 1021 source = "registry+https://github.com/rust-lang/crates.io-index"
870 1022 checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
871 1023 dependencies = [
1024 + "aws-lc-rs",
872 1025 "once_cell",
873 - "ring",
874 1026 "rustls-pki-types",
875 1027 "rustls-webpki",
876 1028 "subtle",
877 1029 "zeroize",
878 1030 ]
879 1031
1032 + [[package]]
1033 + name = "rustls-native-certs"
1034 + version = "0.8.4"
1035 + source = "registry+https://github.com/rust-lang/crates.io-index"
1036 + checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
1037 + dependencies = [
1038 + "openssl-probe",
1039 + "rustls-pki-types",
1040 + "schannel",
1041 + "security-framework",
1042 + ]
1043 +
880 1044 [[package]]
881 1045 name = "rustls-pki-types"
882 1046 version = "1.14.1"
@@ -887,12 +1051,40 @@
887 1051 "zeroize",
888 1052 ]
889 1053
1054 + [[package]]
1055 + name = "rustls-platform-verifier"
1056 + version = "0.7.0"
1057 + source = "registry+https://github.com/rust-lang/crates.io-index"
1058 + checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
1059 + dependencies = [
1060 + "core-foundation",
1061 + "core-foundation-sys",
1062 + "jni",
1063 + "log",
1064 + "once_cell",
1065 + "rustls",
1066 + "rustls-native-certs",
1067 + "rustls-platform-verifier-android",
1068 + "rustls-webpki",
1069 + "security-framework",
1070 + "security-framework-sys",
1071 + "webpki-root-certs",
1072 + "windows-sys 0.52.0",
1073 + ]
1074 +
1075 + [[package]]
1076 + name = "rustls-platform-verifier-android"
1077 + version = "0.1.1"
1078 + source = "registry+https://github.com/rust-lang/crates.io-index"
1079 + checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
1080 +
890 1081 [[package]]
891 1082 name = "rustls-webpki"
892 1083 version = "0.103.13"
893 1084 source = "registry+https://github.com/rust-lang/crates.io-index"
894 1085 checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
895 1086 dependencies = [
1087 + "aws-lc-rs",
896 1088 "ring",
897 1089 "rustls-pki-types",
898 1090 "untrusted",
@@ -910,6 +1102,47 @@
910 1102 source = "registry+https://github.com/rust-lang/crates.io-index"
911 1103 checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
912 1104
1105 + [[package]]
1106 + name = "same-file"
1107 + version = "1.0.6"
1108 + source = "registry+https://github.com/rust-lang/crates.io-index"
1109 + checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1110 + dependencies = [
1111 + "winapi-util",
1112 + ]
1113 +
1114 + [[package]]
1115 + name = "schannel"
1116 + version = "0.1.29"
1117 + source = "registry+https://github.com/rust-lang/crates.io-index"
1118 + checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
1119 + dependencies = [
1120 + "windows-sys 0.61.2",
1121 + ]
1122 +
1123 + [[package]]
1124 + name = "security-framework"
1125 + version = "3.7.0"
1126 + source = "registry+https://github.com/rust-lang/crates.io-index"
1127 + checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
1128 + dependencies = [
1129 + "bitflags",
1130 + "core-foundation",
1131 + "core-foundation-sys",
1132 + "libc",
1133 + "security-framework-sys",
1134 + ]
1135 +
1136 + [[package]]
1137 + name = "security-framework-sys"
1138 + version = "2.17.0"
1139 + source = "registry+https://github.com/rust-lang/crates.io-index"
1140 + checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
1141 + dependencies = [
1142 + "core-foundation-sys",
1143 + "libc",
1144 + ]
1145 +
913 1146 [[package]]
914 1147 name = "semver"
915 1148 version = "1.0.28"
@@ -1005,6 +1238,22 @@
1005 1238 "libc",
1006 1239 ]
1007 1240
1241 + [[package]]
1242 + name = "simd_cesu8"
1243 + version = "1.2.0"
1244 + source = "registry+https://github.com/rust-lang/crates.io-index"
1245 + checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520"
1246 + dependencies = [
1247 + "rustc_version",
1248 + "simdutf8",
1249 + ]
1250 +
1251 + [[package]]
1252 + name = "simdutf8"
1253 + version = "0.1.5"
1254 + source = "registry+https://github.com/rust-lang/crates.io-index"
1255 + checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
1256 +
1008 1257 [[package]]
1009 1258 name = "slab"
1010 1259 version = "0.4.12"
@@ -1380,6 +1629,16 @@
1380 1629 source = "registry+https://github.com/rust-lang/crates.io-index"
1381 1630 checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
1382 1631
1632 + [[package]]
1633 + name = "walkdir"
1634 + version = "2.5.0"
1635 + source = "registry+https://github.com/rust-lang/crates.io-index"
1636 + checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
1637 + dependencies = [
1638 + "same-file",
1639 + "winapi-util",
1640 + ]
1641 +
1383 1642 [[package]]
1384 1643 name = "want"
1385 1644 version = "0.3.1"
@@ -1492,9 +1751,9 @@
1492 1751
1493 1752 [[package]]
1494 1753 name = "wasm-streams"
1495 - version = "0.4.2"
1754 + version = "0.5.0"
1496 1755 source = "registry+https://github.com/rust-lang/crates.io-index"
1497 - checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
1756 + checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb"
1498 1757 dependencies = [
1499 1758 "futures-util",
1500 1759 "js-sys",
@@ -1536,14 +1795,23 @@
1536 1795 ]
1537 1796
1538 1797 [[package]]
1539 - name = "webpki-roots"
1540 - version = "1.0.7"
1798 + name = "webpki-root-certs"
1799 + version = "1.0.9"
1541 1800 source = "registry+https://github.com/rust-lang/crates.io-index"
1542 - checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d"
1801 + checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
1543 1802 dependencies = [
1544 1803 "rustls-pki-types",
1545 1804 ]
1546 1805
1806 + [[package]]
1807 + name = "winapi-util"
1808 + version = "0.1.11"
1809 + source = "registry+https://github.com/rust-lang/crates.io-index"
1810 + checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
1811 + dependencies = [
1812 + "windows-sys 0.52.0",
1813 + ]
1814 +
1547 1815 [[package]]
1548 1816 name = "windows-link"
1549 1817 version = "0.2.1"
@@ -21,3 +21,35 @@
21 21
22 22 [dev-dependencies]
23 23 tempfile = "3.20"
24 +
25 + [lints.rust]
26 + unused = "warn"
27 + unreachable_pub = "warn"
28 +
29 + [lints.clippy]
30 + pedantic = { level = "warn", priority = -1 }
31 + # Allow-list tuned from a measured breakdown across server/multithreaded/pter
32 + # (2026-07-22). These are the high-churn / low-signal pedantic lints; everything
33 + # else in `pedantic` stays a warning. Keep this block identical across repos.
34 + module_name_repetitions = "allow"
35 + # Doc lints. No docs-completeness push is underway.
36 + missing_errors_doc = "allow"
37 + missing_panics_doc = "allow"
38 + doc_markdown = "allow"
39 + # Numeric casts. Endemic and mostly intentional in size and byte math.
40 + cast_possible_truncation = "allow"
41 + cast_sign_loss = "allow"
42 + cast_precision_loss = "allow"
43 + cast_possible_wrap = "allow"
44 + cast_lossless = "allow"
45 + # Subjective structure and style nags. High churn, low signal.
46 + must_use_candidate = "allow"
47 + too_many_lines = "allow"
48 + struct_excessive_bools = "allow"
49 + similar_names = "allow"
50 + items_after_statements = "allow"
51 + single_match_else = "allow"
52 + # Frequent false-positives in TUI and router-heavy code.
53 + match_same_arms = "allow"
54 + unnecessary_wraps = "allow"
55 + type_complexity = "allow"
M mnw-cli/src/api.rs +97 -58
@@ -4,7 +4,7 @@
4 4
5 5 /// User info returned from the SSH key lookup endpoint.
6 6 #[derive(Debug, Clone, Deserialize, Serialize)]
7 - pub struct UserInfo {
7 + pub(crate) struct UserInfo {
8 8 pub user_id: String,
9 9 pub username: String,
10 10 pub display_name: Option<String>,
@@ -20,7 +20,11 @@
20 20
21 21 /// A creator's project with item count and revenue.
22 22 #[derive(Debug, Clone, Deserialize, Serialize)]
23 - pub struct Project {
23 + #[allow(
24 + clippy::struct_field_names,
25 + reason = "project_type mirrors the server JSON/DB schema; renaming would diverge the field from the wire contract"
26 + )]
27 + pub(crate) struct Project {
24 28 pub id: String,
25 29 pub slug: String,
26 30 pub title: String,
@@ -32,7 +36,11 @@
32 36
33 37 /// An item within a project.
34 38 #[derive(Debug, Clone, Deserialize, Serialize)]
35 - pub struct Item {
39 + #[allow(
40 + clippy::struct_field_names,
41 + reason = "item_type mirrors the server JSON/DB schema; renaming would diverge the field from the wire contract"
42 + )]
43 + pub(crate) struct Item {
36 44 pub id: String,
37 45 pub title: String,
38 46 pub item_type: String,
@@ -43,7 +51,7 @@
43 51
44 52 /// Period comparison stats for the creator.
45 53 #[derive(Debug, Clone, Deserialize, Serialize)]
46 - pub struct CreatorStats {
54 + pub(crate) struct CreatorStats {
47 55 pub current_revenue_cents: i64,
48 56 pub previous_revenue_cents: i64,
49 57 pub current_sales: i64,
@@ -57,7 +65,7 @@
57 65 /// Response from the create-item internal endpoint.
58 66 #[derive(Debug, Deserialize)]
59 67 #[allow(dead_code)]
60 - pub struct ItemCreated {
68 + pub(crate) struct ItemCreated {
61 69 pub item_id: String,
62 70 pub project_id: String,
63 71 }
@@ -65,7 +73,7 @@
65 73 /// Response from the presign-upload internal endpoint.
66 74 #[derive(Debug, Deserialize)]
67 75 #[allow(dead_code)]
68 - pub struct PresignResponse {
76 + pub(crate) struct PresignResponse {
69 77 pub upload_url: String,
70 78 pub s3_key: String,
71 79 pub expires_in: u64,
@@ -77,7 +85,7 @@
77 85 /// fine for a small file and unacceptable for a multi-GB one; the multipart path
78 86 /// holds one part at a time. It is also the only path that can carry a file past
79 87 /// S3's 5 GiB single-PUT ceiling, which is what the tier limits allow for.
80 - pub const MULTIPART_THRESHOLD_BYTES: u64 = 64 * 1024 * 1024;
88 + pub(crate) const MULTIPART_THRESHOLD_BYTES: u64 = 64 * 1024 * 1024;
81 89
82 90 /// How many presigned part URLs to request at a time. Must not exceed the
83 91 /// server's own window cap.
@@ -85,7 +93,7 @@
85 93
86 94 /// An opened multipart upload session.
87 95 #[derive(Debug, Clone, Deserialize)]
88 - pub struct MultipartStart {
96 + pub(crate) struct MultipartStart {
89 97 pub upload_id: String,
90 98 pub s3_key: String,
91 99 pub part_size: u64,
@@ -95,7 +103,7 @@
95 103
96 104 /// One presigned part target, with the exact length the signature binds.
97 105 #[derive(Debug, Clone, Deserialize)]
98 - pub struct MultipartPartUrl {
106 + pub(crate) struct MultipartPartUrl {
99 107 pub part_number: i32,
100 108 pub content_length: u64,
101 109 pub url: String,
@@ -108,7 +116,7 @@
108 116
109 117 /// Full item detail returned from the get/update endpoints.
110 118 #[derive(Debug, Clone, Deserialize, Serialize)]
111 - pub struct ItemDetail {
119 + pub(crate) struct ItemDetail {
112 120 pub id: String,
113 121 pub title: String,
114 122 pub description: Option<String>,
@@ -130,7 +138,11 @@
130 138
131 139 /// A version of an item.
132 140 #[derive(Debug, Clone, Deserialize, Serialize)]
133 - pub struct Version {
141 + #[allow(
142 + clippy::struct_field_names,
143 + reason = "version_number mirrors the server JSON/DB schema; renaming would diverge the field from the wire contract"
144 + )]
145 + pub(crate) struct Version {
134 146 pub id: String,
135 147 pub version_number: String,
136 148 pub changelog: Option<String>,
@@ -143,7 +155,7 @@
143 155
144 156 /// A blog post summary.
145 157 #[derive(Debug, Clone, Deserialize, Serialize)]
146 - pub struct BlogPost {
158 + pub(crate) struct BlogPost {
147 159 pub id: String,
148 160 pub title: String,
149 161 pub slug: String,
@@ -155,7 +167,7 @@
155 167
156 168 /// A promo code.
157 169 #[derive(Debug, Clone, Deserialize, Serialize)]
158 - pub struct PromoCode {
170 + pub(crate) struct PromoCode {
159 171 pub id: String,
160 172 pub code: String,
161 173 pub code_purpose: String,
@@ -170,7 +182,7 @@
170 182
171 183 /// A license key.
172 184 #[derive(Debug, Clone, Deserialize, Serialize)]
173 - pub struct LicenseKey {
185 + pub(crate) struct LicenseKey {
174 186 pub id: String,
175 187 pub key_code: String,
176 188 pub activation_count: i32,
@@ -181,7 +193,7 @@
181 193
182 194 /// Response from the storage-info internal endpoint.
183 195 #[derive(Debug, Clone, Deserialize, Serialize)]
184 - pub struct StorageInfo {
196 + pub(crate) struct StorageInfo {
185 197 pub storage_used_bytes: i64,
186 198 pub max_storage_bytes: i64,
187 199 pub allows_file_uploads: bool,
@@ -189,7 +201,7 @@
189 201
190 202 /// A revenue bucket for analytics timeseries.
191 203 #[derive(Debug, Clone, Deserialize, Serialize)]
192 - pub struct AnalyticsBucket {
204 + pub(crate) struct AnalyticsBucket {
193 205 pub label: String,
194 206 pub revenue_cents: i64,
195 207 pub sales_count: i64,
@@ -197,7 +209,7 @@
197 209
198 210 /// Per-project revenue summary.
199 211 #[derive(Debug, Clone, Deserialize, Serialize)]
200 - pub struct ProjectRevenue {
212 + pub(crate) struct ProjectRevenue {
201 213 pub id: String,
202 214 pub title: String,
203 215 pub revenue_cents: i64,
@@ -205,7 +217,7 @@
205 217
206 218 /// Analytics response with timeseries, comparison, and top projects.
207 219 #[derive(Debug, Clone, Deserialize, Serialize)]
208 - pub struct AnalyticsData {
220 + pub(crate) struct AnalyticsData {
209 221 pub buckets: Vec<AnalyticsBucket>,
210 222 pub current_revenue_cents: i64,
211 223 pub previous_revenue_cents: i64,
@@ -218,7 +230,7 @@
218 230
219 231 /// A seller transaction.
220 232 #[derive(Debug, Clone, Deserialize, Serialize)]
221 - pub struct Transaction {
233 + pub(crate) struct Transaction {
222 234 pub id: String,
223 235 pub item_title: Option<String>,
224 236 pub amount_cents: i32,
@@ -229,14 +241,14 @@
229 241
230 242 /// CSV export result.
231 243 #[derive(Debug, Clone, Deserialize, Serialize)]
232 - pub struct ExportResult {
244 + pub(crate) struct ExportResult {
233 245 pub csv: String,
234 246 pub row_count: usize,
235 247 }
236 248
237 249 /// A registered SSH key.
238 250 #[derive(Debug, Clone, Deserialize, Serialize)]
239 - pub struct SshKeyInfo {
251 + pub(crate) struct SshKeyInfo {
240 252 pub id: String,
241 253 pub label: String,
242 254 pub fingerprint: String,
@@ -245,7 +257,7 @@
245 257
246 258 /// A tag on an item or from search.
247 259 #[derive(Debug, Clone, Deserialize, Serialize)]
248 - pub struct TagInfo {
260 + pub(crate) struct TagInfo {
249 261 pub id: String,
250 262 pub name: String,
251 263 pub slug: String,
@@ -255,14 +267,14 @@
255 267 /// Result of a broadcast send.
256 268 #[derive(Debug, Deserialize)]
257 269 #[allow(dead_code)] // wire contract: every field the endpoint returns, read or not
258 - pub struct BroadcastResult {
270 + pub(crate) struct BroadcastResult {
259 271 pub success: bool,
260 272 pub recipient_count: usize,
261 273 }
262 274
263 275 /// A subscription tier.
264 276 #[derive(Debug, Clone, Deserialize, Serialize)]
265 - pub struct TierInfo {
277 + pub(crate) struct TierInfo {
266 278 pub id: String,
267 279 pub name: String,
268 280 pub description: String,
@@ -272,7 +284,7 @@
272 284
273 285 /// A collection.
274 286 #[derive(Debug, Clone, Deserialize, Serialize)]
275 - pub struct CollectionInfo {
287 + pub(crate) struct CollectionInfo {
276 288 pub id: String,
277 289 pub slug: String,
278 290 pub title: String,
@@ -283,7 +295,7 @@
283 295
284 296 /// Custom domain info.
285 297 #[derive(Debug, Clone, Deserialize, Serialize)]
286 - pub struct DomainInfo {
298 + pub(crate) struct DomainInfo {
287 299 pub id: String,
288 300 pub domain: String,
289 301 pub verified: bool,
@@ -294,14 +306,14 @@
294 306 /// Domain verification result.
295 307 #[derive(Debug, Deserialize)]
296 308 #[allow(dead_code)] // wire contract: every field the endpoint returns, read or not
297 - pub struct DomainVerifyResult {
309 + pub(crate) struct DomainVerifyResult {
298 310 pub verified: bool,
299 311 pub message: String,
300 312 }
301 313
302 314 /// Response from the git authorize endpoint.
303 315 #[derive(Debug, Deserialize)]
304 - pub struct GitAuthResponse {
316 + pub(crate) struct GitAuthResponse {
305 317 pub repo_path: String,
306 318 }
307 319
@@ -342,7 +354,7 @@
342 354
343 355 /// Client for calling MNW internal API endpoints.
344 356 #[derive(Clone)]
345 - pub struct MnwApiClient {
357 + pub(crate) struct MnwApiClient {
346 358 http: reqwest::Client,
347 359 base_url: String,
348 360 service_token: String,
@@ -352,7 +364,7 @@
352 364 }
353 365
354 366 impl MnwApiClient {
355 - pub fn new(base_url: String, service_token: String) -> Self {
367 + pub(crate) fn new(base_url: String, service_token: String) -> Self {
356 368 let http = reqwest::Client::builder()
357 369 .timeout(std::time::Duration::from_secs(5))
358 370 .build()
@@ -368,7 +380,7 @@
368 380
369 381 /// Record the actor assertion for the authenticated session. Subsequent
370 382 /// internal calls forward it so the server can verify the acting identity.
371 - pub fn set_actor_token(&mut self, token: String) {
383 + pub(crate) fn set_actor_token(&mut self, token: String) {
372 384 self.actor_token = Some(token);
373 385 }
374 386
@@ -379,7 +391,10 @@
379 391
380 392 /// Look up a user by SSH key fingerprint.
381 393 /// Returns `Ok(Some(info))` if found, `Ok(None)` if not found.
382 - pub async fn lookup_ssh_key(&self, fingerprint: &str) -> anyhow::Result<Option<UserInfo>> {
394 + pub(crate) async fn lookup_ssh_key(
395 + &self,
396 + fingerprint: &str,
397 + ) -> anyhow::Result<Option<UserInfo>> {
383 398 let url = format!("{}/api/internal/ssh-key-lookup", self.base_url);
384 399 let resp = self
385 400 .http
@@ -403,7 +418,7 @@
403 418 }
404 419
405 420 /// Fetch all projects for a creator with item counts and revenue.
406 - pub async fn get_projects(&self, user_id: &str) -> anyhow::Result<Vec<Project>> {
421 + pub(crate) async fn get_projects(&self, user_id: &str) -> anyhow::Result<Vec<Project>> {
407 422 let url = format!("{}/api/internal/creator/projects", self.base_url);
408 423 let resp = self
409 424 .http
@@ -418,7 +433,7 @@
418 433 }
419 434
420 435 /// Create a new project.
421 - pub async fn create_project(
436 + pub(crate) async fn create_project(
422 437 &self,
423 438 user_id: &str,
424 439 title: &str,
@@ -447,7 +462,7 @@
447 462 }
448 463
449 464 /// Fetch items in a project.
450 - pub async fn get_project_items(
465 + pub(crate) async fn get_project_items(
451 466 &self,
452 467 project_id: &str,
453 468 user_id: &str,
@@ -469,7 +484,11 @@
469 484 }
470 485
471 486 /// Fetch period comparison stats for a creator.
472 - pub async fn get_stats(&self, user_id: &str, range: &str) -> anyhow::Result<CreatorStats> {
487 + pub(crate) async fn get_stats(
488 + &self,
489 + user_id: &str,
490 + range: &str,
491 + ) -> anyhow::Result<CreatorStats> {
473 492 let url = format!("{}/api/internal/creator/stats", self.base_url);
474 493 let resp = self
475 494 .http
@@ -484,7 +503,7 @@
484 503 }
485 504
486 505 /// Fetch storage usage and limits for a creator.
487 - pub async fn get_storage_info(&self, user_id: &str) -> anyhow::Result<StorageInfo> {
506 + pub(crate) async fn get_storage_info(&self, user_id: &str) -> anyhow::Result<StorageInfo> {
488 507 let url = format!("{}/api/internal/creator/storage", self.base_url);
489 508 let resp = self
490 509 .http
@@ -499,7 +518,7 @@
499 518 }
500 519
501 520 /// Create an item in a project.
502 - pub async fn create_item(
521 + pub(crate) async fn create_item(
503 522 &self,
504 523 user_id: &str,
505 524 project_id: &str,
@@ -527,7 +546,7 @@
527 546 }
528 547
529 548 /// Get a presigned S3 upload URL.
530 - pub async fn presign_upload(
549 + pub(crate) async fn presign_upload(
531 550 &self,
532 551 user_id: &str,
533 552 item_id: &str,
@@ -555,7 +574,7 @@
555 574 }
556 575
557 576 /// Confirm a completed S3 upload.
558 - pub async fn confirm_upload(
577 + pub(crate) async fn confirm_upload(
559 578 &self,
560 579 user_id: &str,
561 580 item_id: &str,
@@ -586,7 +605,7 @@
586 605 }
587 606
588 607 /// Fetch full item detail.
589 - pub async fn get_item_detail(
608 + pub(crate) async fn get_item_detail(
590 609 &self,
591 610 user_id: &str,
592 611 item_id: &str,
@@ -605,7 +624,7 @@
605 624 }
606 625
607 626 /// Update item fields. Only non-None fields are changed.
608 - pub async fn update_item(
627 + pub(crate) async fn update_item(
609 628 &self,
610 629 user_id: &str,
611 630 item_id: &str,
@@ -642,7 +661,7 @@
642 661 }
643 662
644 663 /// Delete an item permanently.
645 - pub async fn delete_item(&self, user_id: &str, item_id: &str) -> anyhow::Result<()> {
664 + pub(crate) async fn delete_item(&self, user_id: &str, item_id: &str) -> anyhow::Result<()> {
646 665 let url = format!("{}/api/internal/creator/items/{}", self.base_url, item_id);
647 666 let resp = self
648 667 .http
@@ -657,7 +676,11 @@
657 676 }
658 677
659 678 /// Publish an item (set is_public=true).
660 - pub async fn publish_item(&self, user_id: &str, item_id: &str) -> anyhow::Result<ItemDetail> {
679 + pub(crate) async fn publish_item(
680 + &self,
681 + user_id: &str,
682 + item_id: &str,
683 + ) -> anyhow::Result<ItemDetail> {
661 684 let url = format!(
662 685 "{}/api/internal/creator/items/{}/publish",
663 686 self.base_url, item_id
@@ -675,7 +698,11 @@
675 698 }
676 699
677 700 /// Unpublish an item (set is_public=false).
678 - pub async fn unpublish_item(&self, user_id: &str, item_id: &str) -> anyhow::Result<ItemDetail> {
701 + pub(crate) async fn unpublish_item(
702 + &self,
703 + user_id: &str,
704 + item_id: &str,
705 + ) -> anyhow::Result<ItemDetail> {
679 706 let url = format!(
680 707 "{}/api/internal/creator/items/{}/unpublish",
681 708 self.base_url, item_id
@@ -693,7 +720,7 @@
693 720 }
694 721
695 722 /// Fetch versions for an item.
696 - pub async fn get_item_versions(
723 + pub(crate) async fn get_item_versions(
697 724 &self,
698 725 user_id: &str,
699 726 item_id: &str,
@@ -717,7 +744,7 @@
717 744 // ── Multipart upload session (large files) ──
718 745
719 746 /// Open a multipart upload session and get the part geometry.
720 - pub async fn multipart_start(
747 + pub(crate) async fn multipart_start(
721 748 &self,
722 749 item_id: &str,
723 750 file_type: &str,
@@ -810,7 +837,11 @@
810 837
811 838 /// Release the parts of an abandoned session. Incomplete multipart uploads
812 839 /// bill for their parts until aborted.
813 - pub async fn multipart_abort(&self, s3_key: &str, upload_id: &str) -> anyhow::Result<()> {
840 + pub(crate) async fn multipart_abort(
841 + &self,
842 + s3_key: &str,
843 + upload_id: &str,
844 + ) -> anyhow::Result<()> {
814 845 let url = format!("{}/api/internal/upload/multipart/abort", self.base_url);
815 846 let resp = self
816 847 .http
@@ -835,7 +866,7 @@
835 866 /// does not leave parts billing indefinitely — the single abort site means a
836 867 /// future failure path added inside cannot forget to.
837 868 #[allow(clippy::too_many_arguments)]
838 - pub async fn upload_file_multipart(
869 + pub(crate) async fn upload_file_multipart(
839 870 &self,
840 871 item_id: &str,
841 872 file_type: &str,
@@ -993,7 +1024,7 @@
993 1024 }
994 1025
995 1026 /// Upload a file to S3 using a presigned URL.
996 - pub async fn upload_to_s3(
1027 + pub(crate) async fn upload_to_s3(
997 1028 &self,
998 1029 presigned_url: &str,
999 1030 file_path: &std::path::Path,
@@ -1023,7 +1054,7 @@
1023 1054 // ── Blog posts ──
1024 1055
1025 1056 /// List blog posts for a project.
1026 - pub async fn list_blog_posts(
1057 + pub(crate) async fn list_blog_posts(
1027 1058 &self,
1028 1059 user_id: &str,
1029 1060 project_id: &str,
@@ -1045,7 +1076,7 @@
1045 1076 }
1046 1077
1047 1078 /// Create a blog post, optionally scheduled for future publication.
1048 - pub async fn create_blog_post(
1079 + pub(crate) async fn create_blog_post(
1049 1080 &self,
1050 1081 user_id: &str,
1051 1082 project_id: &str,
@@ -1078,7 +1109,11 @@
1078 1109 }
1079 1110
1080 1111 /// Delete a blog post.
1081 - pub async fn delete_blog_post(&self, user_id: &str, post_id: &str) -> anyhow::Result<()> {
1112 + pub(crate) async fn delete_blog_post(
1113 + &self,
1114 + user_id: &str,
1115 + post_id: &str,
1116 + ) -> anyhow::Result<()> {
1082 1117 let url = format!("{}/api/internal/creator/blog/{}", self.base_url, post_id);
1083 1118 let resp = self
1084 1119 .http
@@ -1095,7 +1130,7 @@
1095 1130 // ── Promo codes ──
1096 1131
1097 1132 /// List promo codes for a creator.
1098 - pub async fn list_promo_codes(&self, user_id: &str) -> anyhow::Result<Vec<PromoCode>> {
1133 + pub(crate) async fn list_promo_codes(&self, user_id: &str) -> anyhow::Result<Vec<PromoCode>> {
1099 1134 let url = format!("{}/api/internal/creator/promo-codes", self.base_url);
1100 1135 let resp = self
1101 1136 .http
@@ -1110,7 +1145,7 @@
1110 1145 }
1111 1146
1112 1147 /// Create a promo code.
1113 - pub async fn create_promo_code(
1148 + pub(crate) async fn create_promo_code(
1114 1149 &self,
1115 1150 user_id: &str,
1116 1151 code: &str,
@@ -1147,7 +1182,11 @@
1147 1182 }
1148 1183
1149 1184 /// Delete a promo code.
1150 - pub async fn delete_promo_code(&self, user_id: &str, code_id: &str) -> anyhow::Result<()> {
1185 + pub(crate) async fn delete_promo_code(
1186 + &self,
1187 + user_id: &str,
1188 + code_id: &str,
1189 + ) -> anyhow::Result<()> {
1151 1190 let url = format!(
1152 1191 "{}/api/internal/creator/promo-codes/{}",
1153 1192 self.base_url, code_id
@@ -1167,7 +1206,7 @@
1167 1206 // ── License keys ──
1168 1207
1169 1208 /// List license keys for an item.
1170 - pub async fn list_license_keys(
1209 + pub(crate) async fn list_license_keys(
1171 1210 &self,
1172 1211 user_id: &str,
1173 1212 item_id: &str,
@@ -1189,7 +1228,7 @@
1189 1228 }
1190 1229
1191 1230 /// Generate a new license key for an item.
1192 - pub async fn generate_license_key(
1231 + pub(crate) async fn generate_license_key(
Lines truncated
@@ -4,6 +4,8 @@
4 4 //! dispatches to this module. All commands write output to a byte buffer and
5 5 //! return it for the SSH channel.
6 6
7 + use std::fmt::Write as _;
8 +
7 9 use crate::api::{MnwApiClient, UserInfo};
8 10 use crate::format;
9 11 use crate::staging;
@@ -29,7 +31,7 @@
29 31 }
30 32
31 33 /// Execute a non-interactive command and return the output bytes.
32 - pub async fn execute(command_line: &str, user: &UserInfo, api: &MnwApiClient) -> Vec<u8> {
34 + pub(crate) async fn execute(command_line: &str, user: &UserInfo, api: &MnwApiClient) -> Vec<u8> {
33 35 let parts: Vec<&str> = command_line.split_whitespace().collect();
34 36 if parts.is_empty() {
35 37 return help_text();
@@ -142,14 +144,16 @@
142 144 for p in &projects {
143 145 let status = if p.is_public { "public" } else { "draft" };
144 146 let revenue = format::format_cents(p.revenue_cents);
145 - out.push_str(&format!(
147 + write!(
148 + out,
146 149 "{:<30} {:<12} {:<8} {:<6} {:<10}\r\n",
147 150 truncate(&p.title, 29),
148 151 p.project_type,
149 152 status,
150 153 p.item_count,
151 154 revenue,
152 - ));
155 + )
156 + .unwrap();
153 157 }
154 158 out.into_bytes()
155 159 }
@@ -165,28 +169,34 @@
165 169 }
166 170
167 171 let mut out = String::new();
168 - out.push_str(&format!("Analytics ({range})\r\n\r\n"));
172 + write!(out, "Analytics ({range})\r\n\r\n").unwrap();
169 173
170 174 let rev = format::format_cents(data.current_revenue_cents);
171 175 let prev_rev = format::format_cents(data.previous_revenue_cents);
172 - out.push_str(&format!("Revenue: {rev} (prev: {prev_rev})\r\n"));
173 - out.push_str(&format!(
176 + write!(out, "Revenue: {rev} (prev: {prev_rev})\r\n").unwrap();
177 + write!(
178 + out,
174 179 "Sales: {} (prev: {})\r\n",
175 180 data.current_sales, data.previous_sales
176 - ));
177 - out.push_str(&format!(
181 + )
182 + .unwrap();
183 + write!(
184 + out,
178 185 "Followers: {} (prev: {})\r\n",
179 186 data.current_followers, data.previous_followers
180 - ));
187 + )
188 + .unwrap();
181 189
182 190 if !data.top_projects.is_empty() {
183 191 out.push_str("\r\nTop Projects:\r\n");
184 192 for p in &data.top_projects {
185 - out.push_str(&format!(
193 + write!(
194 + out,
186 195 " {:<30} {}\r\n",
187 196 truncate(&p.title, 29),
188 197 format::format_cents(p.revenue_cents)
189 - ));
198 + )
199 + .unwrap();
190 200 }
191 201 }
192 202
@@ -215,13 +225,15 @@
215 225 let title = tx.item_title.as_deref().unwrap_or("--");
216 226 let amount = format::format_cents(tx.amount_cents as i64);
217 227 let date = tx.created_at.get(..10).unwrap_or(&tx.created_at);
218 - out.push_str(&format!(
228 + write!(
229 + out,
219 230 "{:<30} {:<10} {:<12} {:<12}\r\n",
220 231 truncate(title, 29),
221 232 amount,
222 233 tx.status,
223 234 date,
224 - ));
235 + )
236 + .unwrap();
225 237 }
226 238 out.into_bytes()
227 239 }
@@ -253,7 +265,7 @@
253 265 out.push_str("\r\n");
254 266 for c in &codes {
255 267 let discount = match (c.discount_type.as_deref(), c.discount_value) {
256 - (Some("percentage"), Some(v)) => format!("{}% off", v),
268 + (Some("percentage"), Some(v)) => format!("{v}% off"),
257 269 (Some("fixed"), Some(v)) => format!("${}.{:02} off", v / 100, v % 100),
258 270 _ => "Free".to_string(),
259 271 };
@@ -266,13 +278,15 @@
266 278 Some(max) => format!("{}/{}", c.use_count, max),
267 279 None => c.use_count.to_string(),
268 280 };
269 - out.push_str(&format!(
281 + write!(
282 + out,
270 283 "{:<20} {:<12} {:<20} {:<10}\r\n",
271 284 truncate(&c.code, 19),
272 285 discount,
273 286 truncate(scope, 19),
274 287 uses,
275 - ));
288 + )
289 + .unwrap();
276 290 }
277 291 out.into_bytes()
278 292 }
@@ -326,13 +340,15 @@
326 340 for p in &posts {
327 341 let status = if p.is_published { "published" } else { "draft" };
328 342 let date = p.created_at.get(..10).unwrap_or(&p.created_at);
329 - out.push_str(&format!(
343 + write!(
344 + out,
330 345 "{:<30} {:<20} {:<10} {:<12}\r\n",
331 346 truncate(&p.title, 29),
332 347 truncate(&p.slug, 19),
333 348 status,
334 349 date,
335 - ));
350 + )
351 + .unwrap();
336 352 }
337 353 out.into_bytes()
338 354 }
@@ -374,13 +390,15 @@
374 390 out.push_str("\r\n");
375 391 for c in &collections {
376 392 let status = if c.is_public { "public" } else { "draft" };
377 - out.push_str(&format!(
393 + write!(
394 + out,
378 395 "{:<25} {:<25} {:<8} {:<6}\r\n",
379 396 truncate(&c.title, 24),
380 397 truncate(&c.slug, 24),
381 398 status,
382 399 c.item_count,
383 - ));
400 + )
401 + .unwrap();
384 402 }
385 403 out.into_bytes()
386 404 }
@@ -396,7 +414,7 @@
396 414 if !d.verified
397 415 && let Some(ref instr) = d.instructions
398 416 {
399 - out.push_str(&format!("{}\r\n", instr));
417 + write!(out, "{instr}\r\n").unwrap();
400 418 }
401 419 out.into_bytes()
402 420 }
@@ -413,7 +431,7 @@
413 431 Ok(d) => {
414 432 let mut out = format!("Domain added: {}\r\n", d.domain);
415 433 if let Some(ref instr) = d.instructions {
416 - out.push_str(&format!("{}\r\n", instr));
434 + write!(out, "{instr}\r\n").unwrap();
417 435 }
418 436 out.push_str("Run `domain verify` after adding the DNS record.\r\n");
419 437 out.into_bytes()
@@ -437,7 +455,7 @@
437 455 }
438 456
439 457 /// Execute a pipe-mode file upload (called from handler after stdin EOF).
440 - pub async fn execute_pipe_upload(
458 + pub(crate) async fn execute_pipe_upload(
441 459 api: &MnwApiClient,
442 460 upload: crate::ssh::handler::PipeUpload,
443 461 ) -> anyhow::Result<String> {
@@ -518,7 +536,7 @@
518 536 ))
519 537 }
520 538
521 - pub fn help_text() -> Vec<u8> {
539 + pub(crate) fn help_text() -> Vec<u8> {
522 540 b"Usage: ssh cli.makenot.work <command>\r\n\
523 541 \r\n\
524 542 Commands:\r\n\
M pom/src/api.rs +31 -29
M pom/src/config.rs +26 -27
M pom/src/display.rs +26 -24
M pom/src/lib.rs +1 -1
M pom/src/main.rs +2 -2
M pom/src/peer.rs +41 -32
M pom/src/types.rs +12 -14