sdragly commited on
Commit
401b2c8
·
0 Parent(s):

Initial commit

Browse files
Files changed (8) hide show
  1. .gitignore +4 -0
  2. Cargo.lock +2663 -0
  3. Cargo.toml +59 -0
  4. PLAN.md +1169 -0
  5. src/app.rs +46 -0
  6. src/lib.rs +8 -0
  7. src/main.rs +30 -0
  8. style/main.css +81 -0
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ /target
2
+ .env
3
+ *.swp
4
+ *.swo
Cargo.lock ADDED
@@ -0,0 +1,2663 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "aho-corasick"
7
+ version = "1.1.4"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
10
+ dependencies = [
11
+ "memchr",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "any_spawner"
16
+ version = "0.3.0"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "1384d3fe1eecb464229fcf6eebb72306591c56bf27b373561489458a7c73027d"
19
+ dependencies = [
20
+ "futures",
21
+ "thiserror 2.0.18",
22
+ "tokio",
23
+ "wasm-bindgen-futures",
24
+ ]
25
+
26
+ [[package]]
27
+ name = "anyhow"
28
+ version = "1.0.102"
29
+ source = "registry+https://github.com/rust-lang/crates.io-index"
30
+ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
31
+
32
+ [[package]]
33
+ name = "async-lock"
34
+ version = "3.4.2"
35
+ source = "registry+https://github.com/rust-lang/crates.io-index"
36
+ checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
37
+ dependencies = [
38
+ "event-listener",
39
+ "event-listener-strategy",
40
+ "pin-project-lite",
41
+ ]
42
+
43
+ [[package]]
44
+ name = "async-once-cell"
45
+ version = "0.5.4"
46
+ source = "registry+https://github.com/rust-lang/crates.io-index"
47
+ checksum = "4288f83726785267c6f2ef073a3d83dc3f9b81464e9f99898240cced85fce35a"
48
+
49
+ [[package]]
50
+ name = "async-trait"
51
+ version = "0.1.89"
52
+ source = "registry+https://github.com/rust-lang/crates.io-index"
53
+ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
54
+ dependencies = [
55
+ "proc-macro2",
56
+ "quote",
57
+ "syn",
58
+ ]
59
+
60
+ [[package]]
61
+ name = "atomic-waker"
62
+ version = "1.1.2"
63
+ source = "registry+https://github.com/rust-lang/crates.io-index"
64
+ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
65
+
66
+ [[package]]
67
+ name = "attribute-derive"
68
+ version = "0.10.5"
69
+ source = "registry+https://github.com/rust-lang/crates.io-index"
70
+ checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77"
71
+ dependencies = [
72
+ "attribute-derive-macro",
73
+ "derive-where",
74
+ "manyhow",
75
+ "proc-macro2",
76
+ "quote",
77
+ "syn",
78
+ ]
79
+
80
+ [[package]]
81
+ name = "attribute-derive-macro"
82
+ version = "0.10.5"
83
+ source = "registry+https://github.com/rust-lang/crates.io-index"
84
+ checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61"
85
+ dependencies = [
86
+ "collection_literals",
87
+ "interpolator",
88
+ "manyhow",
89
+ "proc-macro-utils",
90
+ "proc-macro2",
91
+ "quote",
92
+ "quote-use",
93
+ "syn",
94
+ ]
95
+
96
+ [[package]]
97
+ name = "axum"
98
+ version = "0.8.8"
99
+ source = "registry+https://github.com/rust-lang/crates.io-index"
100
+ checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
101
+ dependencies = [
102
+ "axum-core",
103
+ "base64",
104
+ "bytes",
105
+ "form_urlencoded",
106
+ "futures-util",
107
+ "http",
108
+ "http-body",
109
+ "http-body-util",
110
+ "hyper",
111
+ "hyper-util",
112
+ "itoa",
113
+ "matchit",
114
+ "memchr",
115
+ "mime",
116
+ "multer",
117
+ "percent-encoding",
118
+ "pin-project-lite",
119
+ "serde_core",
120
+ "serde_json",
121
+ "serde_path_to_error",
122
+ "serde_urlencoded",
123
+ "sha1",
124
+ "sync_wrapper",
125
+ "tokio",
126
+ "tokio-tungstenite",
127
+ "tower",
128
+ "tower-layer",
129
+ "tower-service",
130
+ "tracing",
131
+ ]
132
+
133
+ [[package]]
134
+ name = "axum-core"
135
+ version = "0.5.6"
136
+ source = "registry+https://github.com/rust-lang/crates.io-index"
137
+ checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
138
+ dependencies = [
139
+ "bytes",
140
+ "futures-core",
141
+ "http",
142
+ "http-body",
143
+ "http-body-util",
144
+ "mime",
145
+ "pin-project-lite",
146
+ "sync_wrapper",
147
+ "tower-layer",
148
+ "tower-service",
149
+ "tracing",
150
+ ]
151
+
152
+ [[package]]
153
+ name = "base16"
154
+ version = "0.2.1"
155
+ source = "registry+https://github.com/rust-lang/crates.io-index"
156
+ checksum = "d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8"
157
+
158
+ [[package]]
159
+ name = "base64"
160
+ version = "0.22.1"
161
+ source = "registry+https://github.com/rust-lang/crates.io-index"
162
+ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
163
+
164
+ [[package]]
165
+ name = "bitflags"
166
+ version = "2.11.0"
167
+ source = "registry+https://github.com/rust-lang/crates.io-index"
168
+ checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
169
+
170
+ [[package]]
171
+ name = "block-buffer"
172
+ version = "0.10.4"
173
+ source = "registry+https://github.com/rust-lang/crates.io-index"
174
+ checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
175
+ dependencies = [
176
+ "generic-array",
177
+ ]
178
+
179
+ [[package]]
180
+ name = "bumpalo"
181
+ version = "3.20.2"
182
+ source = "registry+https://github.com/rust-lang/crates.io-index"
183
+ checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
184
+
185
+ [[package]]
186
+ name = "bytes"
187
+ version = "1.11.1"
188
+ source = "registry+https://github.com/rust-lang/crates.io-index"
189
+ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
190
+
191
+ [[package]]
192
+ name = "camino"
193
+ version = "1.2.2"
194
+ source = "registry+https://github.com/rust-lang/crates.io-index"
195
+ checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
196
+
197
+ [[package]]
198
+ name = "cfg-if"
199
+ version = "1.0.4"
200
+ source = "registry+https://github.com/rust-lang/crates.io-index"
201
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
202
+
203
+ [[package]]
204
+ name = "codee"
205
+ version = "0.3.5"
206
+ source = "registry+https://github.com/rust-lang/crates.io-index"
207
+ checksum = "a9dbbdc4b4d349732bc6690de10a9de952bd39ba6a065c586e26600b6b0b91f5"
208
+ dependencies = [
209
+ "serde",
210
+ "serde_json",
211
+ "thiserror 2.0.18",
212
+ ]
213
+
214
+ [[package]]
215
+ name = "collection_literals"
216
+ version = "1.0.3"
217
+ source = "registry+https://github.com/rust-lang/crates.io-index"
218
+ checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084"
219
+
220
+ [[package]]
221
+ name = "concurrent-queue"
222
+ version = "2.5.0"
223
+ source = "registry+https://github.com/rust-lang/crates.io-index"
224
+ checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
225
+ dependencies = [
226
+ "crossbeam-utils",
227
+ ]
228
+
229
+ [[package]]
230
+ name = "config"
231
+ version = "0.15.22"
232
+ source = "registry+https://github.com/rust-lang/crates.io-index"
233
+ checksum = "8e68cfe19cd7d23ffde002c24ffa5cda73931913ef394d5eaaa32037dc940c0c"
234
+ dependencies = [
235
+ "convert_case 0.6.0",
236
+ "pathdiff",
237
+ "serde_core",
238
+ "toml",
239
+ "winnow",
240
+ ]
241
+
242
+ [[package]]
243
+ name = "console_error_panic_hook"
244
+ version = "0.1.7"
245
+ source = "registry+https://github.com/rust-lang/crates.io-index"
246
+ checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
247
+ dependencies = [
248
+ "cfg-if",
249
+ "wasm-bindgen",
250
+ ]
251
+
252
+ [[package]]
253
+ name = "const-str"
254
+ version = "1.1.0"
255
+ source = "registry+https://github.com/rust-lang/crates.io-index"
256
+ checksum = "18f12cc9948ed9604230cdddc7c86e270f9401ccbe3c2e98a4378c5e7632212f"
257
+
258
+ [[package]]
259
+ name = "const_format"
260
+ version = "0.2.35"
261
+ source = "registry+https://github.com/rust-lang/crates.io-index"
262
+ checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad"
263
+ dependencies = [
264
+ "const_format_proc_macros",
265
+ ]
266
+
267
+ [[package]]
268
+ name = "const_format_proc_macros"
269
+ version = "0.2.34"
270
+ source = "registry+https://github.com/rust-lang/crates.io-index"
271
+ checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744"
272
+ dependencies = [
273
+ "proc-macro2",
274
+ "quote",
275
+ "unicode-xid",
276
+ ]
277
+
278
+ [[package]]
279
+ name = "const_str_slice_concat"
280
+ version = "0.1.0"
281
+ source = "registry+https://github.com/rust-lang/crates.io-index"
282
+ checksum = "f67855af358fcb20fac58f9d714c94e2b228fe5694c1c9b4ead4a366343eda1b"
283
+
284
+ [[package]]
285
+ name = "convert_case"
286
+ version = "0.6.0"
287
+ source = "registry+https://github.com/rust-lang/crates.io-index"
288
+ checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
289
+ dependencies = [
290
+ "unicode-segmentation",
291
+ ]
292
+
293
+ [[package]]
294
+ name = "convert_case"
295
+ version = "0.11.0"
296
+ source = "registry+https://github.com/rust-lang/crates.io-index"
297
+ checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49"
298
+ dependencies = [
299
+ "unicode-segmentation",
300
+ ]
301
+
302
+ [[package]]
303
+ name = "convert_case_extras"
304
+ version = "0.2.0"
305
+ source = "registry+https://github.com/rust-lang/crates.io-index"
306
+ checksum = "589c70f0faf8aa9d17787557d5eae854d7755cac50f5c3d12c81d3d57661cebb"
307
+ dependencies = [
308
+ "convert_case 0.11.0",
309
+ ]
310
+
311
+ [[package]]
312
+ name = "cpufeatures"
313
+ version = "0.2.17"
314
+ source = "registry+https://github.com/rust-lang/crates.io-index"
315
+ checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
316
+ dependencies = [
317
+ "libc",
318
+ ]
319
+
320
+ [[package]]
321
+ name = "crossbeam-utils"
322
+ version = "0.8.21"
323
+ source = "registry+https://github.com/rust-lang/crates.io-index"
324
+ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
325
+
326
+ [[package]]
327
+ name = "crypto-common"
328
+ version = "0.1.7"
329
+ source = "registry+https://github.com/rust-lang/crates.io-index"
330
+ checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
331
+ dependencies = [
332
+ "generic-array",
333
+ "typenum",
334
+ ]
335
+
336
+ [[package]]
337
+ name = "data-encoding"
338
+ version = "2.10.0"
339
+ source = "registry+https://github.com/rust-lang/crates.io-index"
340
+ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
341
+
342
+ [[package]]
343
+ name = "derive-where"
344
+ version = "1.6.1"
345
+ source = "registry+https://github.com/rust-lang/crates.io-index"
346
+ checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534"
347
+ dependencies = [
348
+ "proc-macro2",
349
+ "quote",
350
+ "syn",
351
+ ]
352
+
353
+ [[package]]
354
+ name = "digest"
355
+ version = "0.10.7"
356
+ source = "registry+https://github.com/rust-lang/crates.io-index"
357
+ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
358
+ dependencies = [
359
+ "block-buffer",
360
+ "crypto-common",
361
+ ]
362
+
363
+ [[package]]
364
+ name = "displaydoc"
365
+ version = "0.2.5"
366
+ source = "registry+https://github.com/rust-lang/crates.io-index"
367
+ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
368
+ dependencies = [
369
+ "proc-macro2",
370
+ "quote",
371
+ "syn",
372
+ ]
373
+
374
+ [[package]]
375
+ name = "drain_filter_polyfill"
376
+ version = "0.1.3"
377
+ source = "registry+https://github.com/rust-lang/crates.io-index"
378
+ checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408"
379
+
380
+ [[package]]
381
+ name = "either"
382
+ version = "1.15.0"
383
+ source = "registry+https://github.com/rust-lang/crates.io-index"
384
+ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
385
+
386
+ [[package]]
387
+ name = "either_of"
388
+ version = "0.1.8"
389
+ source = "registry+https://github.com/rust-lang/crates.io-index"
390
+ checksum = "14f7f86eef3a7e4b9c2107583dbbbe3d9535c4b800796faf1774b82ba22033da"
391
+ dependencies = [
392
+ "paste",
393
+ "pin-project-lite",
394
+ ]
395
+
396
+ [[package]]
397
+ name = "encoding_rs"
398
+ version = "0.8.35"
399
+ source = "registry+https://github.com/rust-lang/crates.io-index"
400
+ checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
401
+ dependencies = [
402
+ "cfg-if",
403
+ ]
404
+
405
+ [[package]]
406
+ name = "equivalent"
407
+ version = "1.0.2"
408
+ source = "registry+https://github.com/rust-lang/crates.io-index"
409
+ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
410
+
411
+ [[package]]
412
+ name = "erased"
413
+ version = "0.1.2"
414
+ source = "registry+https://github.com/rust-lang/crates.io-index"
415
+ checksum = "a1731451909bde27714eacba19c2566362a7f35224f52b153d3f42cf60f72472"
416
+
417
+ [[package]]
418
+ name = "event-listener"
419
+ version = "5.4.1"
420
+ source = "registry+https://github.com/rust-lang/crates.io-index"
421
+ checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
422
+ dependencies = [
423
+ "concurrent-queue",
424
+ "parking",
425
+ "pin-project-lite",
426
+ ]
427
+
428
+ [[package]]
429
+ name = "event-listener-strategy"
430
+ version = "0.5.4"
431
+ source = "registry+https://github.com/rust-lang/crates.io-index"
432
+ checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
433
+ dependencies = [
434
+ "event-listener",
435
+ "pin-project-lite",
436
+ ]
437
+
438
+ [[package]]
439
+ name = "foldhash"
440
+ version = "0.1.5"
441
+ source = "registry+https://github.com/rust-lang/crates.io-index"
442
+ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
443
+
444
+ [[package]]
445
+ name = "form_urlencoded"
446
+ version = "1.2.2"
447
+ source = "registry+https://github.com/rust-lang/crates.io-index"
448
+ checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
449
+ dependencies = [
450
+ "percent-encoding",
451
+ ]
452
+
453
+ [[package]]
454
+ name = "futures"
455
+ version = "0.3.32"
456
+ source = "registry+https://github.com/rust-lang/crates.io-index"
457
+ checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
458
+ dependencies = [
459
+ "futures-channel",
460
+ "futures-core",
461
+ "futures-executor",
462
+ "futures-io",
463
+ "futures-sink",
464
+ "futures-task",
465
+ "futures-util",
466
+ ]
467
+
468
+ [[package]]
469
+ name = "futures-channel"
470
+ version = "0.3.32"
471
+ source = "registry+https://github.com/rust-lang/crates.io-index"
472
+ checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
473
+ dependencies = [
474
+ "futures-core",
475
+ "futures-sink",
476
+ ]
477
+
478
+ [[package]]
479
+ name = "futures-core"
480
+ version = "0.3.32"
481
+ source = "registry+https://github.com/rust-lang/crates.io-index"
482
+ checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
483
+
484
+ [[package]]
485
+ name = "futures-executor"
486
+ version = "0.3.32"
487
+ source = "registry+https://github.com/rust-lang/crates.io-index"
488
+ checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
489
+ dependencies = [
490
+ "futures-core",
491
+ "futures-task",
492
+ "futures-util",
493
+ ]
494
+
495
+ [[package]]
496
+ name = "futures-io"
497
+ version = "0.3.32"
498
+ source = "registry+https://github.com/rust-lang/crates.io-index"
499
+ checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
500
+
501
+ [[package]]
502
+ name = "futures-macro"
503
+ version = "0.3.32"
504
+ source = "registry+https://github.com/rust-lang/crates.io-index"
505
+ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
506
+ dependencies = [
507
+ "proc-macro2",
508
+ "quote",
509
+ "syn",
510
+ ]
511
+
512
+ [[package]]
513
+ name = "futures-sink"
514
+ version = "0.3.32"
515
+ source = "registry+https://github.com/rust-lang/crates.io-index"
516
+ checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
517
+
518
+ [[package]]
519
+ name = "futures-task"
520
+ version = "0.3.32"
521
+ source = "registry+https://github.com/rust-lang/crates.io-index"
522
+ checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
523
+
524
+ [[package]]
525
+ name = "futures-util"
526
+ version = "0.3.32"
527
+ source = "registry+https://github.com/rust-lang/crates.io-index"
528
+ checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
529
+ dependencies = [
530
+ "futures-channel",
531
+ "futures-core",
532
+ "futures-io",
533
+ "futures-macro",
534
+ "futures-sink",
535
+ "futures-task",
536
+ "memchr",
537
+ "pin-project-lite",
538
+ "slab",
539
+ ]
540
+
541
+ [[package]]
542
+ name = "generic-array"
543
+ version = "0.14.7"
544
+ source = "registry+https://github.com/rust-lang/crates.io-index"
545
+ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
546
+ dependencies = [
547
+ "typenum",
548
+ "version_check",
549
+ ]
550
+
551
+ [[package]]
552
+ name = "getrandom"
553
+ version = "0.3.4"
554
+ source = "registry+https://github.com/rust-lang/crates.io-index"
555
+ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
556
+ dependencies = [
557
+ "cfg-if",
558
+ "libc",
559
+ "r-efi 5.3.0",
560
+ "wasip2",
561
+ ]
562
+
563
+ [[package]]
564
+ name = "getrandom"
565
+ version = "0.4.2"
566
+ source = "registry+https://github.com/rust-lang/crates.io-index"
567
+ checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
568
+ dependencies = [
569
+ "cfg-if",
570
+ "js-sys",
571
+ "libc",
572
+ "r-efi 6.0.0",
573
+ "wasip2",
574
+ "wasip3",
575
+ "wasm-bindgen",
576
+ ]
577
+
578
+ [[package]]
579
+ name = "gloo-net"
580
+ version = "0.6.0"
581
+ source = "registry+https://github.com/rust-lang/crates.io-index"
582
+ checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580"
583
+ dependencies = [
584
+ "futures-channel",
585
+ "futures-core",
586
+ "futures-sink",
587
+ "gloo-utils",
588
+ "http",
589
+ "js-sys",
590
+ "pin-project",
591
+ "serde",
592
+ "serde_json",
593
+ "thiserror 1.0.69",
594
+ "wasm-bindgen",
595
+ "wasm-bindgen-futures",
596
+ "web-sys",
597
+ ]
598
+
599
+ [[package]]
600
+ name = "gloo-utils"
601
+ version = "0.2.0"
602
+ source = "registry+https://github.com/rust-lang/crates.io-index"
603
+ checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
604
+ dependencies = [
605
+ "js-sys",
606
+ "serde",
607
+ "serde_json",
608
+ "wasm-bindgen",
609
+ "web-sys",
610
+ ]
611
+
612
+ [[package]]
613
+ name = "guardian"
614
+ version = "1.3.0"
615
+ source = "registry+https://github.com/rust-lang/crates.io-index"
616
+ checksum = "17e2ac29387b1aa07a1e448f7bb4f35b500787971e965b02842b900afa5c8f6f"
617
+
618
+ [[package]]
619
+ name = "hashbrown"
620
+ version = "0.15.5"
621
+ source = "registry+https://github.com/rust-lang/crates.io-index"
622
+ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
623
+ dependencies = [
624
+ "foldhash",
625
+ ]
626
+
627
+ [[package]]
628
+ name = "hashbrown"
629
+ version = "0.17.0"
630
+ source = "registry+https://github.com/rust-lang/crates.io-index"
631
+ checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
632
+
633
+ [[package]]
634
+ name = "heck"
635
+ version = "0.5.0"
636
+ source = "registry+https://github.com/rust-lang/crates.io-index"
637
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
638
+
639
+ [[package]]
640
+ name = "html-escape"
641
+ version = "0.2.13"
642
+ source = "registry+https://github.com/rust-lang/crates.io-index"
643
+ checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476"
644
+ dependencies = [
645
+ "utf8-width",
646
+ ]
647
+
648
+ [[package]]
649
+ name = "http"
650
+ version = "1.4.0"
651
+ source = "registry+https://github.com/rust-lang/crates.io-index"
652
+ checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
653
+ dependencies = [
654
+ "bytes",
655
+ "itoa",
656
+ ]
657
+
658
+ [[package]]
659
+ name = "http-body"
660
+ version = "1.0.1"
661
+ source = "registry+https://github.com/rust-lang/crates.io-index"
662
+ checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
663
+ dependencies = [
664
+ "bytes",
665
+ "http",
666
+ ]
667
+
668
+ [[package]]
669
+ name = "http-body-util"
670
+ version = "0.1.3"
671
+ source = "registry+https://github.com/rust-lang/crates.io-index"
672
+ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
673
+ dependencies = [
674
+ "bytes",
675
+ "futures-core",
676
+ "http",
677
+ "http-body",
678
+ "pin-project-lite",
679
+ ]
680
+
681
+ [[package]]
682
+ name = "http-range-header"
683
+ version = "0.4.2"
684
+ source = "registry+https://github.com/rust-lang/crates.io-index"
685
+ checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c"
686
+
687
+ [[package]]
688
+ name = "httparse"
689
+ version = "1.10.1"
690
+ source = "registry+https://github.com/rust-lang/crates.io-index"
691
+ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
692
+
693
+ [[package]]
694
+ name = "httpdate"
695
+ version = "1.0.3"
696
+ source = "registry+https://github.com/rust-lang/crates.io-index"
697
+ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
698
+
699
+ [[package]]
700
+ name = "hydration_context"
701
+ version = "0.3.0"
702
+ source = "registry+https://github.com/rust-lang/crates.io-index"
703
+ checksum = "e8714ae4adeaa846d838f380fbd72f049197de629948f91bf045329e0cf0a283"
704
+ dependencies = [
705
+ "futures",
706
+ "js-sys",
707
+ "once_cell",
708
+ "or_poisoned",
709
+ "pin-project-lite",
710
+ "serde",
711
+ "throw_error",
712
+ "wasm-bindgen",
713
+ ]
714
+
715
+ [[package]]
716
+ name = "hyper"
717
+ version = "1.9.0"
718
+ source = "registry+https://github.com/rust-lang/crates.io-index"
719
+ checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
720
+ dependencies = [
721
+ "atomic-waker",
722
+ "bytes",
723
+ "futures-channel",
724
+ "futures-core",
725
+ "http",
726
+ "http-body",
727
+ "httparse",
728
+ "httpdate",
729
+ "itoa",
730
+ "pin-project-lite",
731
+ "smallvec",
732
+ "tokio",
733
+ ]
734
+
735
+ [[package]]
736
+ name = "hyper-util"
737
+ version = "0.1.20"
738
+ source = "registry+https://github.com/rust-lang/crates.io-index"
739
+ checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
740
+ dependencies = [
741
+ "bytes",
742
+ "http",
743
+ "http-body",
744
+ "hyper",
745
+ "pin-project-lite",
746
+ "tokio",
747
+ "tower-service",
748
+ ]
749
+
750
+ [[package]]
751
+ name = "icu_collections"
752
+ version = "2.2.0"
753
+ source = "registry+https://github.com/rust-lang/crates.io-index"
754
+ checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
755
+ dependencies = [
756
+ "displaydoc",
757
+ "potential_utf",
758
+ "utf8_iter",
759
+ "yoke",
760
+ "zerofrom",
761
+ "zerovec",
762
+ ]
763
+
764
+ [[package]]
765
+ name = "icu_locale_core"
766
+ version = "2.2.0"
767
+ source = "registry+https://github.com/rust-lang/crates.io-index"
768
+ checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
769
+ dependencies = [
770
+ "displaydoc",
771
+ "litemap",
772
+ "tinystr",
773
+ "writeable",
774
+ "zerovec",
775
+ ]
776
+
777
+ [[package]]
778
+ name = "icu_normalizer"
779
+ version = "2.2.0"
780
+ source = "registry+https://github.com/rust-lang/crates.io-index"
781
+ checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
782
+ dependencies = [
783
+ "icu_collections",
784
+ "icu_normalizer_data",
785
+ "icu_properties",
786
+ "icu_provider",
787
+ "smallvec",
788
+ "zerovec",
789
+ ]
790
+
791
+ [[package]]
792
+ name = "icu_normalizer_data"
793
+ version = "2.2.0"
794
+ source = "registry+https://github.com/rust-lang/crates.io-index"
795
+ checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
796
+
797
+ [[package]]
798
+ name = "icu_properties"
799
+ version = "2.2.0"
800
+ source = "registry+https://github.com/rust-lang/crates.io-index"
801
+ checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
802
+ dependencies = [
803
+ "icu_collections",
804
+ "icu_locale_core",
805
+ "icu_properties_data",
806
+ "icu_provider",
807
+ "zerotrie",
808
+ "zerovec",
809
+ ]
810
+
811
+ [[package]]
812
+ name = "icu_properties_data"
813
+ version = "2.2.0"
814
+ source = "registry+https://github.com/rust-lang/crates.io-index"
815
+ checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
816
+
817
+ [[package]]
818
+ name = "icu_provider"
819
+ version = "2.2.0"
820
+ source = "registry+https://github.com/rust-lang/crates.io-index"
821
+ checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
822
+ dependencies = [
823
+ "displaydoc",
824
+ "icu_locale_core",
825
+ "writeable",
826
+ "yoke",
827
+ "zerofrom",
828
+ "zerotrie",
829
+ "zerovec",
830
+ ]
831
+
832
+ [[package]]
833
+ name = "id-arena"
834
+ version = "2.3.0"
835
+ source = "registry+https://github.com/rust-lang/crates.io-index"
836
+ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
837
+
838
+ [[package]]
839
+ name = "idna"
840
+ version = "1.1.0"
841
+ source = "registry+https://github.com/rust-lang/crates.io-index"
842
+ checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
843
+ dependencies = [
844
+ "idna_adapter",
845
+ "smallvec",
846
+ "utf8_iter",
847
+ ]
848
+
849
+ [[package]]
850
+ name = "idna_adapter"
851
+ version = "1.2.1"
852
+ source = "registry+https://github.com/rust-lang/crates.io-index"
853
+ checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
854
+ dependencies = [
855
+ "icu_normalizer",
856
+ "icu_properties",
857
+ ]
858
+
859
+ [[package]]
860
+ name = "indexmap"
861
+ version = "2.14.0"
862
+ source = "registry+https://github.com/rust-lang/crates.io-index"
863
+ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
864
+ dependencies = [
865
+ "equivalent",
866
+ "hashbrown 0.17.0",
867
+ "serde",
868
+ "serde_core",
869
+ ]
870
+
871
+ [[package]]
872
+ name = "interpolator"
873
+ version = "0.5.0"
874
+ source = "registry+https://github.com/rust-lang/crates.io-index"
875
+ checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8"
876
+
877
+ [[package]]
878
+ name = "inventory"
879
+ version = "0.3.24"
880
+ source = "registry+https://github.com/rust-lang/crates.io-index"
881
+ checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b"
882
+ dependencies = [
883
+ "rustversion",
884
+ ]
885
+
886
+ [[package]]
887
+ name = "itertools"
888
+ version = "0.14.0"
889
+ source = "registry+https://github.com/rust-lang/crates.io-index"
890
+ checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
891
+ dependencies = [
892
+ "either",
893
+ ]
894
+
895
+ [[package]]
896
+ name = "itoa"
897
+ version = "1.0.18"
898
+ source = "registry+https://github.com/rust-lang/crates.io-index"
899
+ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
900
+
901
+ [[package]]
902
+ name = "js-sys"
903
+ version = "0.3.95"
904
+ source = "registry+https://github.com/rust-lang/crates.io-index"
905
+ checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca"
906
+ dependencies = [
907
+ "cfg-if",
908
+ "futures-util",
909
+ "once_cell",
910
+ "wasm-bindgen",
911
+ ]
912
+
913
+ [[package]]
914
+ name = "leb128fmt"
915
+ version = "0.1.0"
916
+ source = "registry+https://github.com/rust-lang/crates.io-index"
917
+ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
918
+
919
+ [[package]]
920
+ name = "leptos"
921
+ version = "0.8.17"
922
+ source = "registry+https://github.com/rust-lang/crates.io-index"
923
+ checksum = "4b540ac2868724738f0f5d00f00ec4640e587223774219c1baddc46bad46fb8e"
924
+ dependencies = [
925
+ "any_spawner",
926
+ "base64",
927
+ "cfg-if",
928
+ "either_of",
929
+ "futures",
930
+ "getrandom 0.4.2",
931
+ "hydration_context",
932
+ "leptos_config",
933
+ "leptos_dom",
934
+ "leptos_hot_reload",
935
+ "leptos_macro",
936
+ "leptos_server",
937
+ "oco_ref",
938
+ "or_poisoned",
939
+ "paste",
940
+ "rand",
941
+ "reactive_graph",
942
+ "rustc-hash",
943
+ "rustc_version",
944
+ "send_wrapper",
945
+ "serde",
946
+ "serde_json",
947
+ "serde_qs",
948
+ "server_fn",
949
+ "slotmap",
950
+ "tachys",
951
+ "thiserror 2.0.18",
952
+ "throw_error",
953
+ "typed-builder",
954
+ "typed-builder-macro",
955
+ "wasm-bindgen",
956
+ "wasm-bindgen-futures",
957
+ "wasm_split_helpers",
958
+ "web-sys",
959
+ ]
960
+
961
+ [[package]]
962
+ name = "leptos_axum"
963
+ version = "0.8.8"
964
+ source = "registry+https://github.com/rust-lang/crates.io-index"
965
+ checksum = "196de3f5cde6a4c4cd254bb16dc6abd2efbf46cc3ae1b6c7da0731f77b4bdf61"
966
+ dependencies = [
967
+ "any_spawner",
968
+ "axum",
969
+ "futures",
970
+ "hydration_context",
971
+ "leptos",
972
+ "leptos_integration_utils",
973
+ "leptos_macro",
974
+ "leptos_meta",
975
+ "leptos_router",
976
+ "or_poisoned",
977
+ "server_fn",
978
+ "tachys",
979
+ "tokio",
980
+ "tower",
981
+ "tower-http",
982
+ ]
983
+
984
+ [[package]]
985
+ name = "leptos_config"
986
+ version = "0.8.9"
987
+ source = "registry+https://github.com/rust-lang/crates.io-index"
988
+ checksum = "19a2ac32008dda0d657f2147cc33336f4e743e091597db10f7a99d668e92a46d"
989
+ dependencies = [
990
+ "config",
991
+ "regex",
992
+ "serde",
993
+ "thiserror 2.0.18",
994
+ "typed-builder",
995
+ ]
996
+
997
+ [[package]]
998
+ name = "leptos_dom"
999
+ version = "0.8.8"
1000
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1001
+ checksum = "35742e9ed8f8aaf9e549b454c68a7ac0992536e06856365639b111f72ab07884"
1002
+ dependencies = [
1003
+ "js-sys",
1004
+ "or_poisoned",
1005
+ "reactive_graph",
1006
+ "send_wrapper",
1007
+ "tachys",
1008
+ "wasm-bindgen",
1009
+ "web-sys",
1010
+ ]
1011
+
1012
+ [[package]]
1013
+ name = "leptos_hot_reload"
1014
+ version = "0.8.6"
1015
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1016
+ checksum = "9d2a0f220c8a5ef3c51199dfb9cdd702bc0eb80d52fbe70c7890adfaaae8a4b1"
1017
+ dependencies = [
1018
+ "anyhow",
1019
+ "camino",
1020
+ "indexmap",
1021
+ "or_poisoned",
1022
+ "proc-macro2",
1023
+ "quote",
1024
+ "rstml",
1025
+ "serde",
1026
+ "syn",
1027
+ "walkdir",
1028
+ ]
1029
+
1030
+ [[package]]
1031
+ name = "leptos_integration_utils"
1032
+ version = "0.8.8"
1033
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1034
+ checksum = "c097f89cd9aa606297672f56fa5bdda09f01609a9f4eefaccdbb5ab5afea4279"
1035
+ dependencies = [
1036
+ "futures",
1037
+ "hydration_context",
1038
+ "leptos",
1039
+ "leptos_config",
1040
+ "leptos_meta",
1041
+ "leptos_router",
1042
+ "reactive_graph",
1043
+ ]
1044
+
1045
+ [[package]]
1046
+ name = "leptos_macro"
1047
+ version = "0.8.15"
1048
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1049
+ checksum = "712325a77f1d050bf2897061ccaf2b075930aab36954980d658f04452686c474"
1050
+ dependencies = [
1051
+ "attribute-derive",
1052
+ "cfg-if",
1053
+ "convert_case 0.11.0",
1054
+ "convert_case_extras",
1055
+ "html-escape",
1056
+ "itertools",
1057
+ "leptos_hot_reload",
1058
+ "prettyplease",
1059
+ "proc-macro-error2",
1060
+ "proc-macro2",
1061
+ "quote",
1062
+ "rstml",
1063
+ "rustc_version",
1064
+ "server_fn_macro",
1065
+ "syn",
1066
+ "uuid",
1067
+ ]
1068
+
1069
+ [[package]]
1070
+ name = "leptos_meta"
1071
+ version = "0.8.6"
1072
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1073
+ checksum = "6c3efe657b4c55ed2e078922786ffe20acfb71767c3dd913767b09a35c75c890"
1074
+ dependencies = [
1075
+ "futures",
1076
+ "indexmap",
1077
+ "leptos",
1078
+ "or_poisoned",
1079
+ "send_wrapper",
1080
+ "wasm-bindgen",
1081
+ "web-sys",
1082
+ ]
1083
+
1084
+ [[package]]
1085
+ name = "leptos_router"
1086
+ version = "0.8.13"
1087
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1088
+ checksum = "c15158449162e099e2273442f7fd9b924f5cefd935d52af5755ec62aa819fa52"
1089
+ dependencies = [
1090
+ "any_spawner",
1091
+ "either_of",
1092
+ "futures",
1093
+ "gloo-net",
1094
+ "js-sys",
1095
+ "leptos",
1096
+ "leptos_router_macro",
1097
+ "or_poisoned",
1098
+ "percent-encoding",
1099
+ "reactive_graph",
1100
+ "rustc_version",
1101
+ "send_wrapper",
1102
+ "tachys",
1103
+ "thiserror 2.0.18",
1104
+ "url",
1105
+ "wasm-bindgen",
1106
+ "web-sys",
1107
+ ]
1108
+
1109
+ [[package]]
1110
+ name = "leptos_router_macro"
1111
+ version = "0.8.6"
1112
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1113
+ checksum = "409c0bd99f986c3cfa1a4db2443c835bc602ded1a12784e22ecb28c3ed5a2ae2"
1114
+ dependencies = [
1115
+ "proc-macro-error2",
1116
+ "proc-macro2",
1117
+ "quote",
1118
+ "syn",
1119
+ ]
1120
+
1121
+ [[package]]
1122
+ name = "leptos_server"
1123
+ version = "0.8.7"
1124
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1125
+ checksum = "da974775c5ccbb6bd64be7f53f75e8321542e28f21563a416574dbe4d5447eae"
1126
+ dependencies = [
1127
+ "any_spawner",
1128
+ "base64",
1129
+ "codee",
1130
+ "futures",
1131
+ "hydration_context",
1132
+ "or_poisoned",
1133
+ "reactive_graph",
1134
+ "send_wrapper",
1135
+ "serde",
1136
+ "serde_json",
1137
+ "server_fn",
1138
+ "tachys",
1139
+ ]
1140
+
1141
+ [[package]]
1142
+ name = "libc"
1143
+ version = "0.2.184"
1144
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1145
+ checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
1146
+
1147
+ [[package]]
1148
+ name = "litemap"
1149
+ version = "0.8.2"
1150
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1151
+ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
1152
+
1153
+ [[package]]
1154
+ name = "log"
1155
+ version = "0.4.29"
1156
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1157
+ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
1158
+
1159
+ [[package]]
1160
+ name = "manyhow"
1161
+ version = "0.11.4"
1162
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1163
+ checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587"
1164
+ dependencies = [
1165
+ "manyhow-macros",
1166
+ "proc-macro2",
1167
+ "quote",
1168
+ "syn",
1169
+ ]
1170
+
1171
+ [[package]]
1172
+ name = "manyhow-macros"
1173
+ version = "0.11.4"
1174
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1175
+ checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495"
1176
+ dependencies = [
1177
+ "proc-macro-utils",
1178
+ "proc-macro2",
1179
+ "quote",
1180
+ ]
1181
+
1182
+ [[package]]
1183
+ name = "matchit"
1184
+ version = "0.8.4"
1185
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1186
+ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
1187
+
1188
+ [[package]]
1189
+ name = "memchr"
1190
+ version = "2.8.0"
1191
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1192
+ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
1193
+
1194
+ [[package]]
1195
+ name = "mime"
1196
+ version = "0.3.17"
1197
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1198
+ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
1199
+
1200
+ [[package]]
1201
+ name = "mime_guess"
1202
+ version = "2.0.5"
1203
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1204
+ checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
1205
+ dependencies = [
1206
+ "mime",
1207
+ "unicase",
1208
+ ]
1209
+
1210
+ [[package]]
1211
+ name = "mio"
1212
+ version = "1.2.0"
1213
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1214
+ checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
1215
+ dependencies = [
1216
+ "libc",
1217
+ "wasi",
1218
+ "windows-sys",
1219
+ ]
1220
+
1221
+ [[package]]
1222
+ name = "multer"
1223
+ version = "3.1.0"
1224
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1225
+ checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b"
1226
+ dependencies = [
1227
+ "bytes",
1228
+ "encoding_rs",
1229
+ "futures-util",
1230
+ "http",
1231
+ "httparse",
1232
+ "memchr",
1233
+ "mime",
1234
+ "spin",
1235
+ "version_check",
1236
+ ]
1237
+
1238
+ [[package]]
1239
+ name = "next_tuple"
1240
+ version = "0.1.0"
1241
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1242
+ checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28"
1243
+
1244
+ [[package]]
1245
+ name = "oco_ref"
1246
+ version = "0.2.1"
1247
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1248
+ checksum = "ed0423ff9973dea4d6bd075934fdda86ebb8c05bdf9d6b0507067d4a1226371d"
1249
+ dependencies = [
1250
+ "serde",
1251
+ "thiserror 2.0.18",
1252
+ ]
1253
+
1254
+ [[package]]
1255
+ name = "once_cell"
1256
+ version = "1.21.4"
1257
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1258
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
1259
+
1260
+ [[package]]
1261
+ name = "or_poisoned"
1262
+ version = "0.1.0"
1263
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1264
+ checksum = "8c04f5d74368e4d0dfe06c45c8627c81bd7c317d52762d118fb9b3076f6420fd"
1265
+
1266
+ [[package]]
1267
+ name = "parking"
1268
+ version = "2.2.1"
1269
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1270
+ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
1271
+
1272
+ [[package]]
1273
+ name = "paste"
1274
+ version = "1.0.15"
1275
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1276
+ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
1277
+
1278
+ [[package]]
1279
+ name = "pathdiff"
1280
+ version = "0.2.3"
1281
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1282
+ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
1283
+
1284
+ [[package]]
1285
+ name = "percent-encoding"
1286
+ version = "2.3.2"
1287
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1288
+ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
1289
+
1290
+ [[package]]
1291
+ name = "pin-project"
1292
+ version = "1.1.11"
1293
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1294
+ checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517"
1295
+ dependencies = [
1296
+ "pin-project-internal",
1297
+ ]
1298
+
1299
+ [[package]]
1300
+ name = "pin-project-internal"
1301
+ version = "1.1.11"
1302
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1303
+ checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6"
1304
+ dependencies = [
1305
+ "proc-macro2",
1306
+ "quote",
1307
+ "syn",
1308
+ ]
1309
+
1310
+ [[package]]
1311
+ name = "pin-project-lite"
1312
+ version = "0.2.17"
1313
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1314
+ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
1315
+
1316
+ [[package]]
1317
+ name = "potential_utf"
1318
+ version = "0.1.5"
1319
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1320
+ checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
1321
+ dependencies = [
1322
+ "zerovec",
1323
+ ]
1324
+
1325
+ [[package]]
1326
+ name = "ppv-lite86"
1327
+ version = "0.2.21"
1328
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1329
+ checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
1330
+ dependencies = [
1331
+ "zerocopy",
1332
+ ]
1333
+
1334
+ [[package]]
1335
+ name = "prettyplease"
1336
+ version = "0.2.37"
1337
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1338
+ checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
1339
+ dependencies = [
1340
+ "proc-macro2",
1341
+ "syn",
1342
+ ]
1343
+
1344
+ [[package]]
1345
+ name = "princess"
1346
+ version = "0.1.0"
1347
+ dependencies = [
1348
+ "axum",
1349
+ "console_error_panic_hook",
1350
+ "leptos",
1351
+ "leptos_axum",
1352
+ "leptos_meta",
1353
+ "leptos_router",
1354
+ "serde",
1355
+ "serde_json",
1356
+ "tokio",
1357
+ "tower",
1358
+ "tower-http",
1359
+ "wasm-bindgen",
1360
+ ]
1361
+
1362
+ [[package]]
1363
+ name = "proc-macro-error-attr2"
1364
+ version = "2.0.0"
1365
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1366
+ checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
1367
+ dependencies = [
1368
+ "proc-macro2",
1369
+ "quote",
1370
+ ]
1371
+
1372
+ [[package]]
1373
+ name = "proc-macro-error2"
1374
+ version = "2.0.1"
1375
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1376
+ checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
1377
+ dependencies = [
1378
+ "proc-macro-error-attr2",
1379
+ "proc-macro2",
1380
+ "quote",
1381
+ "syn",
1382
+ ]
1383
+
1384
+ [[package]]
1385
+ name = "proc-macro-utils"
1386
+ version = "0.10.0"
1387
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1388
+ checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071"
1389
+ dependencies = [
1390
+ "proc-macro2",
1391
+ "quote",
1392
+ "smallvec",
1393
+ ]
1394
+
1395
+ [[package]]
1396
+ name = "proc-macro2"
1397
+ version = "1.0.106"
1398
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1399
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
1400
+ dependencies = [
1401
+ "unicode-ident",
1402
+ ]
1403
+
1404
+ [[package]]
1405
+ name = "proc-macro2-diagnostics"
1406
+ version = "0.10.1"
1407
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1408
+ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
1409
+ dependencies = [
1410
+ "proc-macro2",
1411
+ "quote",
1412
+ "syn",
1413
+ "version_check",
1414
+ "yansi",
1415
+ ]
1416
+
1417
+ [[package]]
1418
+ name = "quote"
1419
+ version = "1.0.45"
1420
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1421
+ checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
1422
+ dependencies = [
1423
+ "proc-macro2",
1424
+ ]
1425
+
1426
+ [[package]]
1427
+ name = "quote-use"
1428
+ version = "0.8.4"
1429
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1430
+ checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e"
1431
+ dependencies = [
1432
+ "quote",
1433
+ "quote-use-macros",
1434
+ ]
1435
+
1436
+ [[package]]
1437
+ name = "quote-use-macros"
1438
+ version = "0.8.4"
1439
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1440
+ checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35"
1441
+ dependencies = [
1442
+ "proc-macro-utils",
1443
+ "proc-macro2",
1444
+ "quote",
1445
+ "syn",
1446
+ ]
1447
+
1448
+ [[package]]
1449
+ name = "r-efi"
1450
+ version = "5.3.0"
1451
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1452
+ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
1453
+
1454
+ [[package]]
1455
+ name = "r-efi"
1456
+ version = "6.0.0"
1457
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1458
+ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
1459
+
1460
+ [[package]]
1461
+ name = "rand"
1462
+ version = "0.9.2"
1463
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1464
+ checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
1465
+ dependencies = [
1466
+ "rand_chacha",
1467
+ "rand_core",
1468
+ ]
1469
+
1470
+ [[package]]
1471
+ name = "rand_chacha"
1472
+ version = "0.9.0"
1473
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1474
+ checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
1475
+ dependencies = [
1476
+ "ppv-lite86",
1477
+ "rand_core",
1478
+ ]
1479
+
1480
+ [[package]]
1481
+ name = "rand_core"
1482
+ version = "0.9.5"
1483
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1484
+ checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
1485
+ dependencies = [
1486
+ "getrandom 0.3.4",
1487
+ ]
1488
+
1489
+ [[package]]
1490
+ name = "reactive_graph"
1491
+ version = "0.2.13"
1492
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1493
+ checksum = "35774620b3da884a07341e9e36612e1509b1eb0553ef3bb76f1547dd1b797417"
1494
+ dependencies = [
1495
+ "any_spawner",
1496
+ "async-lock",
1497
+ "futures",
1498
+ "guardian",
1499
+ "hydration_context",
1500
+ "indexmap",
1501
+ "or_poisoned",
1502
+ "paste",
1503
+ "pin-project-lite",
1504
+ "rustc-hash",
1505
+ "rustc_version",
1506
+ "send_wrapper",
1507
+ "serde",
1508
+ "slotmap",
1509
+ "thiserror 2.0.18",
1510
+ "web-sys",
1511
+ ]
1512
+
1513
+ [[package]]
1514
+ name = "reactive_stores"
1515
+ version = "0.4.2"
1516
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1517
+ checksum = "3e114642d342893571ff40b4e1da8ccdea907be44c649041eb7d8413b3fd95e8"
1518
+ dependencies = [
1519
+ "guardian",
1520
+ "indexmap",
1521
+ "itertools",
1522
+ "or_poisoned",
1523
+ "paste",
1524
+ "reactive_graph",
1525
+ "reactive_stores_macro",
1526
+ "rustc-hash",
1527
+ "send_wrapper",
1528
+ ]
1529
+
1530
+ [[package]]
1531
+ name = "reactive_stores_macro"
1532
+ version = "0.4.1"
1533
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1534
+ checksum = "5b024812c47a6867b6cb32767a46182203f94e59eb88c69b032fd9caffa304ce"
1535
+ dependencies = [
1536
+ "convert_case 0.11.0",
1537
+ "proc-macro-error2",
1538
+ "proc-macro2",
1539
+ "quote",
1540
+ "syn",
1541
+ ]
1542
+
1543
+ [[package]]
1544
+ name = "regex"
1545
+ version = "1.12.3"
1546
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1547
+ checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
1548
+ dependencies = [
1549
+ "aho-corasick",
1550
+ "memchr",
1551
+ "regex-automata",
1552
+ "regex-syntax",
1553
+ ]
1554
+
1555
+ [[package]]
1556
+ name = "regex-automata"
1557
+ version = "0.4.14"
1558
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1559
+ checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
1560
+ dependencies = [
1561
+ "aho-corasick",
1562
+ "memchr",
1563
+ "regex-syntax",
1564
+ ]
1565
+
1566
+ [[package]]
1567
+ name = "regex-syntax"
1568
+ version = "0.8.10"
1569
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1570
+ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
1571
+
1572
+ [[package]]
1573
+ name = "rstml"
1574
+ version = "0.12.1"
1575
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1576
+ checksum = "61cf4616de7499fc5164570d40ca4e1b24d231c6833a88bff0fe00725080fd56"
1577
+ dependencies = [
1578
+ "derive-where",
1579
+ "proc-macro2",
1580
+ "proc-macro2-diagnostics",
1581
+ "quote",
1582
+ "syn",
1583
+ "syn_derive",
1584
+ "thiserror 2.0.18",
1585
+ ]
1586
+
1587
+ [[package]]
1588
+ name = "rustc-hash"
1589
+ version = "2.1.2"
1590
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1591
+ checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
1592
+
1593
+ [[package]]
1594
+ name = "rustc_version"
1595
+ version = "0.4.1"
1596
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1597
+ checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
1598
+ dependencies = [
1599
+ "semver",
1600
+ ]
1601
+
1602
+ [[package]]
1603
+ name = "rustversion"
1604
+ version = "1.0.22"
1605
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1606
+ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
1607
+
1608
+ [[package]]
1609
+ name = "ryu"
1610
+ version = "1.0.23"
1611
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1612
+ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
1613
+
1614
+ [[package]]
1615
+ name = "same-file"
1616
+ version = "1.0.6"
1617
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1618
+ checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1619
+ dependencies = [
1620
+ "winapi-util",
1621
+ ]
1622
+
1623
+ [[package]]
1624
+ name = "semver"
1625
+ version = "1.0.28"
1626
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1627
+ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
1628
+
1629
+ [[package]]
1630
+ name = "send_wrapper"
1631
+ version = "0.6.0"
1632
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1633
+ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
1634
+ dependencies = [
1635
+ "futures-core",
1636
+ ]
1637
+
1638
+ [[package]]
1639
+ name = "serde"
1640
+ version = "1.0.228"
1641
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1642
+ checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
1643
+ dependencies = [
1644
+ "serde_core",
1645
+ "serde_derive",
1646
+ ]
1647
+
1648
+ [[package]]
1649
+ name = "serde_core"
1650
+ version = "1.0.228"
1651
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1652
+ checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
1653
+ dependencies = [
1654
+ "serde_derive",
1655
+ ]
1656
+
1657
+ [[package]]
1658
+ name = "serde_derive"
1659
+ version = "1.0.228"
1660
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1661
+ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
1662
+ dependencies = [
1663
+ "proc-macro2",
1664
+ "quote",
1665
+ "syn",
1666
+ ]
1667
+
1668
+ [[package]]
1669
+ name = "serde_json"
1670
+ version = "1.0.149"
1671
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1672
+ checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
1673
+ dependencies = [
1674
+ "itoa",
1675
+ "memchr",
1676
+ "serde",
1677
+ "serde_core",
1678
+ "zmij",
1679
+ ]
1680
+
1681
+ [[package]]
1682
+ name = "serde_path_to_error"
1683
+ version = "0.1.20"
1684
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1685
+ checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
1686
+ dependencies = [
1687
+ "itoa",
1688
+ "serde",
1689
+ "serde_core",
1690
+ ]
1691
+
1692
+ [[package]]
1693
+ name = "serde_qs"
1694
+ version = "0.15.0"
1695
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1696
+ checksum = "f3faaf9e727533a19351a43cc5a8de957372163c7d35cc48c90b75cdda13c352"
1697
+ dependencies = [
1698
+ "percent-encoding",
1699
+ "serde",
1700
+ "thiserror 2.0.18",
1701
+ ]
1702
+
1703
+ [[package]]
1704
+ name = "serde_spanned"
1705
+ version = "1.1.1"
1706
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1707
+ checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
1708
+ dependencies = [
1709
+ "serde_core",
1710
+ ]
1711
+
1712
+ [[package]]
1713
+ name = "serde_urlencoded"
1714
+ version = "0.7.1"
1715
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1716
+ checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
1717
+ dependencies = [
1718
+ "form_urlencoded",
1719
+ "itoa",
1720
+ "ryu",
1721
+ "serde",
1722
+ ]
1723
+
1724
+ [[package]]
1725
+ name = "server_fn"
1726
+ version = "0.8.11"
1727
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1728
+ checksum = "7c799cec4e8e210dfb2f203aa97f0e82232c619e385ef4d011b17a58d6397c7b"
1729
+ dependencies = [
1730
+ "axum",
1731
+ "base64",
1732
+ "bytes",
1733
+ "const-str",
1734
+ "const_format",
1735
+ "futures",
1736
+ "gloo-net",
1737
+ "http",
1738
+ "http-body-util",
1739
+ "hyper",
1740
+ "inventory",
1741
+ "js-sys",
1742
+ "or_poisoned",
1743
+ "pin-project-lite",
1744
+ "rustc_version",
1745
+ "rustversion",
1746
+ "send_wrapper",
1747
+ "serde",
1748
+ "serde_json",
1749
+ "serde_qs",
1750
+ "server_fn_macro_default",
1751
+ "thiserror 2.0.18",
1752
+ "throw_error",
1753
+ "tokio",
1754
+ "tower",
1755
+ "tower-layer",
1756
+ "url",
1757
+ "wasm-bindgen",
1758
+ "wasm-bindgen-futures",
1759
+ "wasm-streams",
1760
+ "web-sys",
1761
+ "xxhash-rust",
1762
+ ]
1763
+
1764
+ [[package]]
1765
+ name = "server_fn_macro"
1766
+ version = "0.8.10"
1767
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1768
+ checksum = "1295b54815397d30d986b63f93cfd515fa86d5e528e0bb589ce9d530502f9e0f"
1769
+ dependencies = [
1770
+ "const_format",
1771
+ "convert_case 0.11.0",
1772
+ "proc-macro2",
1773
+ "quote",
1774
+ "rustc_version",
1775
+ "syn",
1776
+ "xxhash-rust",
1777
+ ]
1778
+
1779
+ [[package]]
1780
+ name = "server_fn_macro_default"
1781
+ version = "0.8.5"
1782
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1783
+ checksum = "63eb08f80db903d3c42f64e60ebb3875e0305be502bdc064ec0a0eab42207f00"
1784
+ dependencies = [
1785
+ "server_fn_macro",
1786
+ "syn",
1787
+ ]
1788
+
1789
+ [[package]]
1790
+ name = "sha1"
1791
+ version = "0.10.6"
1792
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1793
+ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
1794
+ dependencies = [
1795
+ "cfg-if",
1796
+ "cpufeatures",
1797
+ "digest",
1798
+ ]
1799
+
1800
+ [[package]]
1801
+ name = "sha2"
1802
+ version = "0.10.9"
1803
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1804
+ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
1805
+ dependencies = [
1806
+ "cfg-if",
1807
+ "cpufeatures",
1808
+ "digest",
1809
+ ]
1810
+
1811
+ [[package]]
1812
+ name = "slab"
1813
+ version = "0.4.12"
1814
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1815
+ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
1816
+
1817
+ [[package]]
1818
+ name = "slotmap"
1819
+ version = "1.1.1"
1820
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1821
+ checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038"
1822
+ dependencies = [
1823
+ "version_check",
1824
+ ]
1825
+
1826
+ [[package]]
1827
+ name = "smallvec"
1828
+ version = "1.15.1"
1829
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1830
+ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
1831
+
1832
+ [[package]]
1833
+ name = "socket2"
1834
+ version = "0.6.3"
1835
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1836
+ checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
1837
+ dependencies = [
1838
+ "libc",
1839
+ "windows-sys",
1840
+ ]
1841
+
1842
+ [[package]]
1843
+ name = "spin"
1844
+ version = "0.9.8"
1845
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1846
+ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
1847
+
1848
+ [[package]]
1849
+ name = "stable_deref_trait"
1850
+ version = "1.2.1"
1851
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1852
+ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
1853
+
1854
+ [[package]]
1855
+ name = "syn"
1856
+ version = "2.0.117"
1857
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1858
+ checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
1859
+ dependencies = [
1860
+ "proc-macro2",
1861
+ "quote",
1862
+ "unicode-ident",
1863
+ ]
1864
+
1865
+ [[package]]
1866
+ name = "syn_derive"
1867
+ version = "0.2.0"
1868
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1869
+ checksum = "cdb066a04799e45f5d582e8fc6ec8e6d6896040d00898eb4e6a835196815b219"
1870
+ dependencies = [
1871
+ "proc-macro-error2",
1872
+ "proc-macro2",
1873
+ "quote",
1874
+ "syn",
1875
+ ]
1876
+
1877
+ [[package]]
1878
+ name = "sync_wrapper"
1879
+ version = "1.0.2"
1880
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1881
+ checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
1882
+
1883
+ [[package]]
1884
+ name = "synstructure"
1885
+ version = "0.13.2"
1886
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1887
+ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
1888
+ dependencies = [
1889
+ "proc-macro2",
1890
+ "quote",
1891
+ "syn",
1892
+ ]
1893
+
1894
+ [[package]]
1895
+ name = "tachys"
1896
+ version = "0.2.14"
1897
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1898
+ checksum = "f768750b0d5514f487772187d4b20c66f56faff4541b1faa5aad4975f5aee085"
1899
+ dependencies = [
1900
+ "any_spawner",
1901
+ "async-trait",
1902
+ "const_str_slice_concat",
1903
+ "drain_filter_polyfill",
1904
+ "either_of",
1905
+ "erased",
1906
+ "futures",
1907
+ "html-escape",
1908
+ "indexmap",
1909
+ "itertools",
1910
+ "js-sys",
1911
+ "next_tuple",
1912
+ "oco_ref",
1913
+ "or_poisoned",
1914
+ "paste",
1915
+ "reactive_graph",
1916
+ "reactive_stores",
1917
+ "rustc-hash",
1918
+ "rustc_version",
1919
+ "send_wrapper",
1920
+ "slotmap",
1921
+ "throw_error",
1922
+ "wasm-bindgen",
1923
+ "web-sys",
1924
+ ]
1925
+
1926
+ [[package]]
1927
+ name = "thiserror"
1928
+ version = "1.0.69"
1929
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1930
+ checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
1931
+ dependencies = [
1932
+ "thiserror-impl 1.0.69",
1933
+ ]
1934
+
1935
+ [[package]]
1936
+ name = "thiserror"
1937
+ version = "2.0.18"
1938
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1939
+ checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
1940
+ dependencies = [
1941
+ "thiserror-impl 2.0.18",
1942
+ ]
1943
+
1944
+ [[package]]
1945
+ name = "thiserror-impl"
1946
+ version = "1.0.69"
1947
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1948
+ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
1949
+ dependencies = [
1950
+ "proc-macro2",
1951
+ "quote",
1952
+ "syn",
1953
+ ]
1954
+
1955
+ [[package]]
1956
+ name = "thiserror-impl"
1957
+ version = "2.0.18"
1958
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1959
+ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
1960
+ dependencies = [
1961
+ "proc-macro2",
1962
+ "quote",
1963
+ "syn",
1964
+ ]
1965
+
1966
+ [[package]]
1967
+ name = "throw_error"
1968
+ version = "0.3.1"
1969
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1970
+ checksum = "dc0ed6038fcbc0795aca7c92963ddda636573b956679204e044492d2b13c8f64"
1971
+ dependencies = [
1972
+ "pin-project-lite",
1973
+ ]
1974
+
1975
+ [[package]]
1976
+ name = "tinystr"
1977
+ version = "0.8.3"
1978
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1979
+ checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
1980
+ dependencies = [
1981
+ "displaydoc",
1982
+ "zerovec",
1983
+ ]
1984
+
1985
+ [[package]]
1986
+ name = "tokio"
1987
+ version = "1.51.1"
1988
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1989
+ checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c"
1990
+ dependencies = [
1991
+ "bytes",
1992
+ "libc",
1993
+ "mio",
1994
+ "pin-project-lite",
1995
+ "socket2",
1996
+ "tokio-macros",
1997
+ "windows-sys",
1998
+ ]
1999
+
2000
+ [[package]]
2001
+ name = "tokio-macros"
2002
+ version = "2.7.0"
2003
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2004
+ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
2005
+ dependencies = [
2006
+ "proc-macro2",
2007
+ "quote",
2008
+ "syn",
2009
+ ]
2010
+
2011
+ [[package]]
2012
+ name = "tokio-tungstenite"
2013
+ version = "0.28.0"
2014
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2015
+ checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857"
2016
+ dependencies = [
2017
+ "futures-util",
2018
+ "log",
2019
+ "tokio",
2020
+ "tungstenite",
2021
+ ]
2022
+
2023
+ [[package]]
2024
+ name = "tokio-util"
2025
+ version = "0.7.18"
2026
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2027
+ checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
2028
+ dependencies = [
2029
+ "bytes",
2030
+ "futures-core",
2031
+ "futures-sink",
2032
+ "pin-project-lite",
2033
+ "tokio",
2034
+ ]
2035
+
2036
+ [[package]]
2037
+ name = "toml"
2038
+ version = "1.1.2+spec-1.1.0"
2039
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2040
+ checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
2041
+ dependencies = [
2042
+ "serde_core",
2043
+ "serde_spanned",
2044
+ "toml_datetime",
2045
+ "toml_parser",
2046
+ "winnow",
2047
+ ]
2048
+
2049
+ [[package]]
2050
+ name = "toml_datetime"
2051
+ version = "1.1.1+spec-1.1.0"
2052
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2053
+ checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
2054
+ dependencies = [
2055
+ "serde_core",
2056
+ ]
2057
+
2058
+ [[package]]
2059
+ name = "toml_parser"
2060
+ version = "1.1.2+spec-1.1.0"
2061
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2062
+ checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
2063
+ dependencies = [
2064
+ "winnow",
2065
+ ]
2066
+
2067
+ [[package]]
2068
+ name = "tower"
2069
+ version = "0.5.3"
2070
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2071
+ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
2072
+ dependencies = [
2073
+ "futures-core",
2074
+ "futures-util",
2075
+ "pin-project-lite",
2076
+ "sync_wrapper",
2077
+ "tokio",
2078
+ "tower-layer",
2079
+ "tower-service",
2080
+ "tracing",
2081
+ ]
2082
+
2083
+ [[package]]
2084
+ name = "tower-http"
2085
+ version = "0.6.8"
2086
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2087
+ checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
2088
+ dependencies = [
2089
+ "bitflags",
2090
+ "bytes",
2091
+ "futures-core",
2092
+ "futures-util",
2093
+ "http",
2094
+ "http-body",
2095
+ "http-body-util",
2096
+ "http-range-header",
2097
+ "httpdate",
2098
+ "mime",
2099
+ "mime_guess",
2100
+ "percent-encoding",
2101
+ "pin-project-lite",
2102
+ "tokio",
2103
+ "tokio-util",
2104
+ "tower-layer",
2105
+ "tower-service",
2106
+ "tracing",
2107
+ ]
2108
+
2109
+ [[package]]
2110
+ name = "tower-layer"
2111
+ version = "0.3.3"
2112
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2113
+ checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
2114
+
2115
+ [[package]]
2116
+ name = "tower-service"
2117
+ version = "0.3.3"
2118
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2119
+ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
2120
+
2121
+ [[package]]
2122
+ name = "tracing"
2123
+ version = "0.1.44"
2124
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2125
+ checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
2126
+ dependencies = [
2127
+ "log",
2128
+ "pin-project-lite",
2129
+ "tracing-core",
2130
+ ]
2131
+
2132
+ [[package]]
2133
+ name = "tracing-core"
2134
+ version = "0.1.36"
2135
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2136
+ checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
2137
+ dependencies = [
2138
+ "once_cell",
2139
+ ]
2140
+
2141
+ [[package]]
2142
+ name = "tungstenite"
2143
+ version = "0.28.0"
2144
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2145
+ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442"
2146
+ dependencies = [
2147
+ "bytes",
2148
+ "data-encoding",
2149
+ "http",
2150
+ "httparse",
2151
+ "log",
2152
+ "rand",
2153
+ "sha1",
2154
+ "thiserror 2.0.18",
2155
+ "utf-8",
2156
+ ]
2157
+
2158
+ [[package]]
2159
+ name = "typed-builder"
2160
+ version = "0.23.2"
2161
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2162
+ checksum = "31aa81521b70f94402501d848ccc0ecaa8f93c8eb6999eb9747e72287757ffda"
2163
+ dependencies = [
2164
+ "typed-builder-macro",
2165
+ ]
2166
+
2167
+ [[package]]
2168
+ name = "typed-builder-macro"
2169
+ version = "0.23.2"
2170
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2171
+ checksum = "076a02dc54dd46795c2e9c8282ed40bcfb1e22747e955de9389a1de28190fb26"
2172
+ dependencies = [
2173
+ "proc-macro2",
2174
+ "quote",
2175
+ "syn",
2176
+ ]
2177
+
2178
+ [[package]]
2179
+ name = "typenum"
2180
+ version = "1.19.0"
2181
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2182
+ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
2183
+
2184
+ [[package]]
2185
+ name = "unicase"
2186
+ version = "2.9.0"
2187
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2188
+ checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
2189
+
2190
+ [[package]]
2191
+ name = "unicode-ident"
2192
+ version = "1.0.24"
2193
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2194
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
2195
+
2196
+ [[package]]
2197
+ name = "unicode-segmentation"
2198
+ version = "1.13.2"
2199
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2200
+ checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
2201
+
2202
+ [[package]]
2203
+ name = "unicode-xid"
2204
+ version = "0.2.6"
2205
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2206
+ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
2207
+
2208
+ [[package]]
2209
+ name = "url"
2210
+ version = "2.5.8"
2211
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2212
+ checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
2213
+ dependencies = [
2214
+ "form_urlencoded",
2215
+ "idna",
2216
+ "percent-encoding",
2217
+ "serde",
2218
+ ]
2219
+
2220
+ [[package]]
2221
+ name = "utf-8"
2222
+ version = "0.7.6"
2223
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2224
+ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
2225
+
2226
+ [[package]]
2227
+ name = "utf8-width"
2228
+ version = "0.1.8"
2229
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2230
+ checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091"
2231
+
2232
+ [[package]]
2233
+ name = "utf8_iter"
2234
+ version = "1.0.4"
2235
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2236
+ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
2237
+
2238
+ [[package]]
2239
+ name = "uuid"
2240
+ version = "1.23.0"
2241
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2242
+ checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9"
2243
+ dependencies = [
2244
+ "getrandom 0.4.2",
2245
+ "js-sys",
2246
+ "wasm-bindgen",
2247
+ ]
2248
+
2249
+ [[package]]
2250
+ name = "version_check"
2251
+ version = "0.9.5"
2252
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2253
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
2254
+
2255
+ [[package]]
2256
+ name = "walkdir"
2257
+ version = "2.5.0"
2258
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2259
+ checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
2260
+ dependencies = [
2261
+ "same-file",
2262
+ "winapi-util",
2263
+ ]
2264
+
2265
+ [[package]]
2266
+ name = "wasi"
2267
+ version = "0.11.1+wasi-snapshot-preview1"
2268
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2269
+ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
2270
+
2271
+ [[package]]
2272
+ name = "wasip2"
2273
+ version = "1.0.2+wasi-0.2.9"
2274
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2275
+ checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
2276
+ dependencies = [
2277
+ "wit-bindgen",
2278
+ ]
2279
+
2280
+ [[package]]
2281
+ name = "wasip3"
2282
+ version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
2283
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2284
+ checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
2285
+ dependencies = [
2286
+ "wit-bindgen",
2287
+ ]
2288
+
2289
+ [[package]]
2290
+ name = "wasm-bindgen"
2291
+ version = "0.2.118"
2292
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2293
+ checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89"
2294
+ dependencies = [
2295
+ "cfg-if",
2296
+ "once_cell",
2297
+ "rustversion",
2298
+ "wasm-bindgen-macro",
2299
+ "wasm-bindgen-shared",
2300
+ ]
2301
+
2302
+ [[package]]
2303
+ name = "wasm-bindgen-futures"
2304
+ version = "0.4.68"
2305
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2306
+ checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8"
2307
+ dependencies = [
2308
+ "js-sys",
2309
+ "wasm-bindgen",
2310
+ ]
2311
+
2312
+ [[package]]
2313
+ name = "wasm-bindgen-macro"
2314
+ version = "0.2.118"
2315
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2316
+ checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed"
2317
+ dependencies = [
2318
+ "quote",
2319
+ "wasm-bindgen-macro-support",
2320
+ ]
2321
+
2322
+ [[package]]
2323
+ name = "wasm-bindgen-macro-support"
2324
+ version = "0.2.118"
2325
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2326
+ checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904"
2327
+ dependencies = [
2328
+ "bumpalo",
2329
+ "proc-macro2",
2330
+ "quote",
2331
+ "syn",
2332
+ "wasm-bindgen-shared",
2333
+ ]
2334
+
2335
+ [[package]]
2336
+ name = "wasm-bindgen-shared"
2337
+ version = "0.2.118"
2338
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2339
+ checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129"
2340
+ dependencies = [
2341
+ "unicode-ident",
2342
+ ]
2343
+
2344
+ [[package]]
2345
+ name = "wasm-encoder"
2346
+ version = "0.244.0"
2347
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2348
+ checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
2349
+ dependencies = [
2350
+ "leb128fmt",
2351
+ "wasmparser",
2352
+ ]
2353
+
2354
+ [[package]]
2355
+ name = "wasm-metadata"
2356
+ version = "0.244.0"
2357
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2358
+ checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
2359
+ dependencies = [
2360
+ "anyhow",
2361
+ "indexmap",
2362
+ "wasm-encoder",
2363
+ "wasmparser",
2364
+ ]
2365
+
2366
+ [[package]]
2367
+ name = "wasm-streams"
2368
+ version = "0.5.0"
2369
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2370
+ checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb"
2371
+ dependencies = [
2372
+ "futures-util",
2373
+ "js-sys",
2374
+ "wasm-bindgen",
2375
+ "wasm-bindgen-futures",
2376
+ "web-sys",
2377
+ ]
2378
+
2379
+ [[package]]
2380
+ name = "wasm_split_helpers"
2381
+ version = "0.2.0"
2382
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2383
+ checksum = "a114b3073258dd5de3d812cdd048cca6842342755e828a14dbf15f843f2d1b84"
2384
+ dependencies = [
2385
+ "async-once-cell",
2386
+ "wasm_split_macros",
2387
+ ]
2388
+
2389
+ [[package]]
2390
+ name = "wasm_split_macros"
2391
+ version = "0.2.0"
2392
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2393
+ checksum = "56481f8ed1a9f9ae97ea7b08a5e2b12e8adf9a7818a6ba952b918e09c7be8bf0"
2394
+ dependencies = [
2395
+ "base16",
2396
+ "quote",
2397
+ "sha2",
2398
+ "syn",
2399
+ ]
2400
+
2401
+ [[package]]
2402
+ name = "wasmparser"
2403
+ version = "0.244.0"
2404
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2405
+ checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
2406
+ dependencies = [
2407
+ "bitflags",
2408
+ "hashbrown 0.15.5",
2409
+ "indexmap",
2410
+ "semver",
2411
+ ]
2412
+
2413
+ [[package]]
2414
+ name = "web-sys"
2415
+ version = "0.3.95"
2416
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2417
+ checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d"
2418
+ dependencies = [
2419
+ "js-sys",
2420
+ "wasm-bindgen",
2421
+ ]
2422
+
2423
+ [[package]]
2424
+ name = "winapi-util"
2425
+ version = "0.1.11"
2426
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2427
+ checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
2428
+ dependencies = [
2429
+ "windows-sys",
2430
+ ]
2431
+
2432
+ [[package]]
2433
+ name = "windows-link"
2434
+ version = "0.2.1"
2435
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2436
+ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
2437
+
2438
+ [[package]]
2439
+ name = "windows-sys"
2440
+ version = "0.61.2"
2441
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2442
+ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
2443
+ dependencies = [
2444
+ "windows-link",
2445
+ ]
2446
+
2447
+ [[package]]
2448
+ name = "winnow"
2449
+ version = "1.0.1"
2450
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2451
+ checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5"
2452
+ dependencies = [
2453
+ "memchr",
2454
+ ]
2455
+
2456
+ [[package]]
2457
+ name = "wit-bindgen"
2458
+ version = "0.51.0"
2459
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2460
+ checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
2461
+ dependencies = [
2462
+ "wit-bindgen-rust-macro",
2463
+ ]
2464
+
2465
+ [[package]]
2466
+ name = "wit-bindgen-core"
2467
+ version = "0.51.0"
2468
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2469
+ checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
2470
+ dependencies = [
2471
+ "anyhow",
2472
+ "heck",
2473
+ "wit-parser",
2474
+ ]
2475
+
2476
+ [[package]]
2477
+ name = "wit-bindgen-rust"
2478
+ version = "0.51.0"
2479
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2480
+ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
2481
+ dependencies = [
2482
+ "anyhow",
2483
+ "heck",
2484
+ "indexmap",
2485
+ "prettyplease",
2486
+ "syn",
2487
+ "wasm-metadata",
2488
+ "wit-bindgen-core",
2489
+ "wit-component",
2490
+ ]
2491
+
2492
+ [[package]]
2493
+ name = "wit-bindgen-rust-macro"
2494
+ version = "0.51.0"
2495
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2496
+ checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
2497
+ dependencies = [
2498
+ "anyhow",
2499
+ "prettyplease",
2500
+ "proc-macro2",
2501
+ "quote",
2502
+ "syn",
2503
+ "wit-bindgen-core",
2504
+ "wit-bindgen-rust",
2505
+ ]
2506
+
2507
+ [[package]]
2508
+ name = "wit-component"
2509
+ version = "0.244.0"
2510
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2511
+ checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
2512
+ dependencies = [
2513
+ "anyhow",
2514
+ "bitflags",
2515
+ "indexmap",
2516
+ "log",
2517
+ "serde",
2518
+ "serde_derive",
2519
+ "serde_json",
2520
+ "wasm-encoder",
2521
+ "wasm-metadata",
2522
+ "wasmparser",
2523
+ "wit-parser",
2524
+ ]
2525
+
2526
+ [[package]]
2527
+ name = "wit-parser"
2528
+ version = "0.244.0"
2529
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2530
+ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
2531
+ dependencies = [
2532
+ "anyhow",
2533
+ "id-arena",
2534
+ "indexmap",
2535
+ "log",
2536
+ "semver",
2537
+ "serde",
2538
+ "serde_derive",
2539
+ "serde_json",
2540
+ "unicode-xid",
2541
+ "wasmparser",
2542
+ ]
2543
+
2544
+ [[package]]
2545
+ name = "writeable"
2546
+ version = "0.6.3"
2547
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2548
+ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
2549
+
2550
+ [[package]]
2551
+ name = "xxhash-rust"
2552
+ version = "0.8.15"
2553
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2554
+ checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
2555
+
2556
+ [[package]]
2557
+ name = "yansi"
2558
+ version = "1.0.1"
2559
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2560
+ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
2561
+
2562
+ [[package]]
2563
+ name = "yoke"
2564
+ version = "0.8.2"
2565
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2566
+ checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
2567
+ dependencies = [
2568
+ "stable_deref_trait",
2569
+ "yoke-derive",
2570
+ "zerofrom",
2571
+ ]
2572
+
2573
+ [[package]]
2574
+ name = "yoke-derive"
2575
+ version = "0.8.2"
2576
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2577
+ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
2578
+ dependencies = [
2579
+ "proc-macro2",
2580
+ "quote",
2581
+ "syn",
2582
+ "synstructure",
2583
+ ]
2584
+
2585
+ [[package]]
2586
+ name = "zerocopy"
2587
+ version = "0.8.48"
2588
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2589
+ checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
2590
+ dependencies = [
2591
+ "zerocopy-derive",
2592
+ ]
2593
+
2594
+ [[package]]
2595
+ name = "zerocopy-derive"
2596
+ version = "0.8.48"
2597
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2598
+ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
2599
+ dependencies = [
2600
+ "proc-macro2",
2601
+ "quote",
2602
+ "syn",
2603
+ ]
2604
+
2605
+ [[package]]
2606
+ name = "zerofrom"
2607
+ version = "0.1.7"
2608
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2609
+ checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
2610
+ dependencies = [
2611
+ "zerofrom-derive",
2612
+ ]
2613
+
2614
+ [[package]]
2615
+ name = "zerofrom-derive"
2616
+ version = "0.1.7"
2617
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2618
+ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
2619
+ dependencies = [
2620
+ "proc-macro2",
2621
+ "quote",
2622
+ "syn",
2623
+ "synstructure",
2624
+ ]
2625
+
2626
+ [[package]]
2627
+ name = "zerotrie"
2628
+ version = "0.2.4"
2629
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2630
+ checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
2631
+ dependencies = [
2632
+ "displaydoc",
2633
+ "yoke",
2634
+ "zerofrom",
2635
+ ]
2636
+
2637
+ [[package]]
2638
+ name = "zerovec"
2639
+ version = "0.11.6"
2640
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2641
+ checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
2642
+ dependencies = [
2643
+ "yoke",
2644
+ "zerofrom",
2645
+ "zerovec-derive",
2646
+ ]
2647
+
2648
+ [[package]]
2649
+ name = "zerovec-derive"
2650
+ version = "0.11.3"
2651
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2652
+ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
2653
+ dependencies = [
2654
+ "proc-macro2",
2655
+ "quote",
2656
+ "syn",
2657
+ ]
2658
+
2659
+ [[package]]
2660
+ name = "zmij"
2661
+ version = "1.0.21"
2662
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2663
+ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
Cargo.toml ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [package]
2
+ name = "princess"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+
6
+ [lib]
7
+ crate-type = ["cdylib", "rlib"]
8
+
9
+ [dependencies]
10
+ leptos = { version = "0.8" }
11
+ leptos_meta = { version = "0.8" }
12
+ leptos_router = { version = "0.8" }
13
+ serde = { version = "1", features = ["derive"] }
14
+ serde_json = "1"
15
+ console_error_panic_hook = { version = "0.1", optional = true }
16
+ wasm-bindgen = { version = "0.2", optional = true }
17
+
18
+ # SSR-only
19
+ leptos_axum = { version = "0.8", optional = true }
20
+ axum = { version = "0.8", optional = true }
21
+ tokio = { version = "1", features = ["rt-multi-thread", "macros"], optional = true }
22
+ tower = { version = "0.5", optional = true }
23
+ tower-http = { version = "0.6", features = ["fs", "cors"], optional = true }
24
+
25
+ [features]
26
+ default = []
27
+ hydrate = [
28
+ "leptos/hydrate",
29
+ "dep:console_error_panic_hook",
30
+ "dep:wasm-bindgen",
31
+ ]
32
+ ssr = [
33
+ "leptos/ssr",
34
+ "leptos_meta/ssr",
35
+ "dep:leptos_axum",
36
+ "dep:axum",
37
+ "dep:tokio",
38
+ "dep:tower",
39
+ "dep:tower-http",
40
+ ]
41
+
42
+ [profile.release]
43
+ opt-level = 3
44
+ lto = true
45
+ codegen-units = 1
46
+
47
+ [profile.dev.package."*"]
48
+ opt-level = 1
49
+
50
+ [package.metadata.leptos]
51
+ output-name = "princess"
52
+ site-root = "target/site"
53
+ site-pkg-dir = "pkg"
54
+ style-file = "style/main.css"
55
+ assets-dir = "public"
56
+ site-addr = "0.0.0.0:3000"
57
+ reload-port = 3001
58
+ bin-features = ["ssr"]
59
+ lib-features = ["hydrate"]
PLAN.md ADDED
@@ -0,0 +1,1169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Princess Dress-Up Game — Project Plan
2
+
3
+ > A full-stack Rust web app where a child photographs hand-drawn princesses and clothes,
4
+ > then dresses them up via smooth drag-and-drop with smart clothes-snapping.
5
+ >
6
+ > Target user: 3-5 year old child on a phone or tablet.
7
+ > Builder: Parent + Claude Code, iterative.
8
+
9
+ ---
10
+
11
+ ## Stack
12
+
13
+ | Layer | Technology | Why |
14
+ |---|---|---|
15
+ | Frontend | Leptos 0.7 (WASM) | Full Rust, fine-grained reactivity |
16
+ | Backend | Axum 0.7 | Same binary, server functions |
17
+ | Segmentation | transformers.js (MODNet) via JS interop | Best browser background removal |
18
+ | Storage | Firebase Storage + Firestore | Free tier, cross-device, persistent |
19
+ | Auth | Firebase Anonymous Auth | Zero friction for a child |
20
+ | Build | cargo-leptos | WASM + SSR in one command |
21
+ | CSS | Hand-written, mobile-first | Full control, no bloat |
22
+ | Font | Baloo 2 (Google Fonts) | Rounded, friendly, legible for kids |
23
+ | Hosting | Fly.io (single binary) | Free tier, simple deploy |
24
+
25
+ ---
26
+
27
+ ## Architecture Overview
28
+
29
+ ```
30
+ Phone/Tablet Browser
31
+ Leptos WASM app (UI, drag/drop, snap logic, canvas)
32
+ transformers.js Web Worker (MODNet segmentation, JS side)
33
+ wasm_bindgen bridge (Rust <-> JS for segmentation calls)
34
+ Leptos Server Functions (no manual REST API)
35
+ |
36
+ v
37
+ Axum Server (same binary as WASM host)
38
+ - Serves WASM + assets
39
+ - Firebase Storage upload (PNG to public URL)
40
+ - Firestore read/write (metadata)
41
+ |
42
+ v
43
+ Firebase
44
+ - Storage: segmented PNGs
45
+ - Firestore: princess + clothing records with anchor metadata
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Core Concepts
51
+
52
+ ### Anchor Points (the key to smart snapping)
53
+
54
+ Every uploaded asset (princess or clothing item) stores anchor points: named
55
+ pixel coordinates that define where clothing attaches to a body, and where a
56
+ clothing item expects to be attached.
57
+
58
+ ```
59
+ Princess anchors: Clothing anchor:
60
+ head_top attach_point (where it snaps to princess)
61
+ head_center
62
+ neck
63
+ left_shoulder
64
+ right_shoulder
65
+ waist
66
+ left_hand
67
+ right_hand
68
+ feet_center
69
+ ```
70
+
71
+ When a child drops clothing onto a princess:
72
+ 1. Find the clothing item's attach_point
73
+ 2. Find the nearest matching anchor on the princess
74
+ 3. Snap the clothing so attach_point aligns to the princess anchor
75
+ 4. Scale clothing to fit the princess proportionally
76
+
77
+ Anchors are set automatically using a lightweight heuristic after segmentation
78
+ (bounding box analysis), then optionally refined by the parent in an anchor
79
+ editor screen before saving.
80
+
81
+ ### Coordinate System
82
+
83
+ All coordinates stored as normalized (0.0-1.0) fractions of the image bounding
84
+ box, so they work regardless of display size.
85
+
86
+ ```
87
+ (0,0) --- (1,0)
88
+ | |
89
+ (0,1) --- (1,1)
90
+ ```
91
+
92
+ ### Drag and Drop on Mobile
93
+
94
+ Mobile drag/drop uses pointer events (not mouse events):
95
+ - pointerdown -> pick up item (scale-up animation)
96
+ - pointermove -> drag with finger
97
+ - pointerup -> detect nearest snap zone -> animate into place
98
+
99
+ Snap zones computed in real time as user drags. A glowing ring shows which
100
+ anchor is "active" before the user lifts their finger.
101
+
102
+ ---
103
+
104
+ ## Firestore Schema
105
+
106
+ ```
107
+ /users/{uid}
108
+ createdAt: Timestamp
109
+
110
+ /users/{uid}/princesses/{id}
111
+ name: String
112
+ imageUrl: String (Firebase Storage transparent PNG)
113
+ thumbnailUrl: String (128x128 thumbnail)
114
+ anchors: {
115
+ head_top: { x: f32, y: f32 }
116
+ head_center: { x: f32, y: f32 }
117
+ neck: { x: f32, y: f32 }
118
+ left_shoulder: { x: f32, y: f32 }
119
+ right_shoulder: { x: f32, y: f32 }
120
+ waist: { x: f32, y: f32 }
121
+ left_hand: { x: f32, y: f32 }
122
+ right_hand: { x: f32, y: f32 }
123
+ feet_center: { x: f32, y: f32 }
124
+ }
125
+ createdAt: Timestamp
126
+
127
+ /users/{uid}/clothes/{id}
128
+ name: String
129
+ imageUrl: String
130
+ thumbnailUrl: String
131
+ category: "crown" | "dress" | "top" | "skirt" | "shoes"
132
+ | "cape" | "wand" | "necklace" | "earrings" | "bag"
133
+ attachPoint: { x: f32, y: f32 } (normalized, on the clothing image)
134
+ targetAnchor: String (which princess anchor to snap to)
135
+ scale: f32 (default scale relative to princess, e.g. 0.4)
136
+ zIndex: i32 (layer order: dress behind crown)
137
+ createdAt: Timestamp
138
+
139
+ /users/{uid}/outfits/{id} (stretch goal)
140
+ princessId: String
141
+ clothes: [{ clothingId, x, y, scale, rotation }]
142
+ screenshotUrl: String
143
+ createdAt: Timestamp
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Anchor Auto-Detection Heuristics
149
+
150
+ After segmentation, the server scans the alpha channel bounding box and applies:
151
+
152
+ ```
153
+ Given: cx=0.5, bbox_top and bbox_bottom from alpha scan
154
+
155
+ head_top: (cx, bbox_top + 0.02)
156
+ head_center: (cx, bbox_top + 0.12)
157
+ neck: (cx, bbox_top + 0.22)
158
+ left_shoulder: (cx - 0.15, bbox_top + 0.25)
159
+ right_shoulder: (cx + 0.15, bbox_top + 0.25)
160
+ waist: (cx, bbox_top + 0.48)
161
+ left_hand: (cx - 0.20, bbox_top + 0.55)
162
+ right_hand: (cx + 0.20, bbox_top + 0.55)
163
+ feet_center: (cx, bbox_bottom - 0.02)
164
+ ```
165
+
166
+ Clothing attach_point and targetAnchor by category:
167
+ ```
168
+ crown -> attach (cx, top+0.05) -> targetAnchor: "head_top"
169
+ dress -> attach (cx, top+0.02) -> targetAnchor: "neck"
170
+ top -> attach (cx, top+0.02) -> targetAnchor: "neck"
171
+ skirt -> attach (cx, top+0.02) -> targetAnchor: "waist"
172
+ shoes -> attach (cx, top+0.02) -> targetAnchor: "feet_center"
173
+ cape -> attach (cx, top+0.05) -> targetAnchor: "neck"
174
+ wand -> attach (left+0.05, cy) -> targetAnchor: "right_hand"
175
+ necklace -> attach (cx, cy) -> targetAnchor: "neck"
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Screen Layout
181
+
182
+ ### Screen 1: Dress-Up (main game)
183
+
184
+ ```
185
+ +-----------------------------+
186
+ | [Princess Name] | <- title, changes with princess
187
+ | |
188
+ | +---------------------+ |
189
+ | | | |
190
+ | | PRINCESS CANVAS | | <- fixed aspect ratio 3:4
191
+ | | (layered images) | |
192
+ | | | |
193
+ | | [snap rings glow | |
194
+ | | during drag] | |
195
+ | +---------------------+ |
196
+ | |
197
+ | [<] Princess Name [>] | <- big arrows to switch princesses
198
+ | |
199
+ | +---------------------+ |
200
+ | | CLOTHING TRAY | | <- horizontal scroll
201
+ | | [dress][crown][shoe]| | <- big tap targets
202
+ | +---------------------+ |
203
+ | |
204
+ | [Add Photo] [Save Look] | <- bottom bar
205
+ +-----------------------------+
206
+ ```
207
+
208
+ Interactions:
209
+ - Clothing tray items: DRAGGABLE onto princess canvas
210
+ - Tapping clothing (no drag): AUTO-SNAPS to default anchor immediately
211
+ - Placed clothing on canvas: DRAGGABLE to reposition
212
+ - Double-tap placed item: REMOVES it (poof animation)
213
+ - Pinch placed item: RESIZE (stretch goal)
214
+
215
+ ### Screen 2: Upload
216
+
217
+ ```
218
+ +-----------------------------+
219
+ | [<- Back] |
220
+ | |
221
+ | What are we adding? |
222
+ | [Princess] [Clothes] | <- big pill toggle
223
+ | |
224
+ | +---------------------+ |
225
+ | | [camera icon] | |
226
+ | | Tap to photograph! | |
227
+ | +---------------------+ |
228
+ | |
229
+ | (if Clothes) Category: |
230
+ | [dress][crown][shoes]... |
231
+ | |
232
+ | Name it: [______________] |
233
+ | |
234
+ | [Magic Time!] | -> segmentation + upload
235
+ +-----------------------------+
236
+ ```
237
+
238
+ ### Screen 3: Anchor Editor (parent-only, after uploading princess)
239
+
240
+ ```
241
+ +-----------------------------+
242
+ | [<- Done] Fix the dots |
243
+ | |
244
+ | +---------------------+ |
245
+ | | [princess image] | |
246
+ | | (red dot) | | <- draggable colored dots
247
+ | | (orange dot) | |
248
+ | | (yellow dot) | |
249
+ | | (blue dot) | |
250
+ | +---------------------+ |
251
+ | |
252
+ | Drag dots to right spots! |
253
+ | |
254
+ | [Save] [Skip] |
255
+ +-----------------------------+
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Drag and Drop Implementation Plan
261
+
262
+ ### Rust-side state (Leptos signals)
263
+
264
+ ```rust
265
+ enum DragKind {
266
+ FromTray(String), // clothing_id
267
+ FromCanvas(String, usize), // clothing_id, placed index
268
+ }
269
+
270
+ struct DragState {
271
+ kind: DragKind,
272
+ start: (f32, f32), // viewport coords where drag started
273
+ current: (f32, f32), // current finger viewport coords
274
+ active_snap: Option<usize>, // index into current snap zones vec
275
+ }
276
+
277
+ struct PlacedClothing {
278
+ clothing_id: String,
279
+ anchor_used: Option<String>, // None = free-placed
280
+ offset: (f32, f32), // fine adjustment from snap point in canvas px
281
+ scale: f32,
282
+ z_index: i32,
283
+ }
284
+
285
+ struct SnapZone {
286
+ anchor_name: String,
287
+ x: f32, // canvas px, recomputed each render
288
+ y: f32,
289
+ radius: f32,
290
+ }
291
+ ```
292
+
293
+ ### Pointer Event Flow
294
+
295
+ ```
296
+ pointerdown on tray item:
297
+ - create DragState { kind: FromTray(id), start: pos, current: pos, active_snap: None }
298
+ - ghost div appears at finger position
299
+ - compute snap zones from princess anchors + current canvas rect
300
+ - call setPointerCapture(pointerId) on the ghost element
301
+
302
+ pointermove (captured on ghost):
303
+ - update DragState.current to new finger pos
304
+ - find nearest snap zone
305
+ - if dist < SNAP_THRESHOLD_PX: ghost locks to zone, set active_snap
306
+ - elif dist < MAGNETIC_START_PX: ghost pulled toward zone (quadratic lerp)
307
+ - else: ghost follows finger exactly
308
+ - update snap ring visibility on canvas
309
+
310
+ pointerup:
311
+ - if active_snap set:
312
+ add PlacedClothing snapped to that anchor zone
313
+ trigger sparkle at snap position
314
+ play sparkle sound
315
+ - elif finger is over canvas rect:
316
+ add PlacedClothing at finger pos, anchor_used = None
317
+ - else:
318
+ animate ghost back to tray origin (bounce curve)
319
+ - clear DragState
320
+
321
+ pointerdown on placed clothing (canvas):
322
+ - remove from placed list
323
+ - create DragState { kind: FromCanvas, ... }
324
+ - same flow as above (allows repositioning + re-snapping)
325
+
326
+ double-tap on placed clothing:
327
+ - remove from placed list
328
+ - play poof animation at that position
329
+
330
+ tap (< DRAG_DEAD_ZONE_PX movement, < 200ms) on tray item:
331
+ - immediately add PlacedClothing at targetAnchor
332
+ - sparkle + sound, no drag UI
333
+ ```
334
+
335
+ ### Magnetic Snap Effect
336
+
337
+ ```
338
+ dist = distance(finger, snap_zone_center)
339
+
340
+ if dist < SNAP_THRESHOLD_PX:
341
+ ghost_pos = snap_zone_center (hard lock)
342
+ show pulsing gold ring on canvas
343
+
344
+ elif dist < MAGNETIC_START_PX:
345
+ t = 1.0 - (dist / MAGNETIC_START_PX)
346
+ ghost_pos = lerp(finger, snap_zone_center, t * t) (quadratic pull)
347
+ show faint gold ring on canvas
348
+
349
+ else:
350
+ ghost_pos = finger
351
+ no ring shown
352
+ ```
353
+
354
+ ---
355
+
356
+ ## Segmentation Pipeline
357
+
358
+ ```
359
+ [Browser] User photographs drawing
360
+ |
361
+ JPEG bytes in Leptos upload component
362
+ |
363
+ wasm_bindgen async call to segmentation_worker.js
364
+ |
365
+ segmentation_worker.js:
366
+ - check navigator.gpu -> device = 'webgpu' or 'wasm' fallback
367
+ - lazy-load MODNet via transformers.js (cached in IndexedDB after first load)
368
+ - run inference -> float32 alpha mask tensor [1,1,H,W]
369
+ - draw original to OffscreenCanvas
370
+ - apply alpha mask per-pixel
371
+ - convertToBlob({ type: 'image/png' })
372
+ - return Uint8Array of PNG bytes
373
+ |
374
+ Back in Rust as Vec<u8> via JsFuture
375
+ |
376
+ Show preview in browser ("Looks good? / Try again")
377
+ |
378
+ [If approved] Leptos server function: upload_asset(uid, name, category, png_b64)
379
+ |
380
+ Axum server:
381
+ 1. image_process::optimize_png() max 1200px, strip EXIF
382
+ 2. image_process::generate_thumbnail() 128x128, contain, PNG
383
+ 3. image_process::auto_anchors() heuristic from alpha bounding box
384
+ 4. firebase::upload_image(png) returns imageUrl
385
+ 5. firebase::upload_image(thumb) returns thumbnailUrl
386
+ 6. firebase::save_record(...) returns doc id
387
+ |
388
+ If princess -> navigate to /anchor-editor/{id}
389
+ If clothing -> navigate to / with success flash
390
+ ```
391
+
392
+ ---
393
+
394
+ ## JS Interop Design
395
+
396
+ ```rust
397
+ // src/interop.rs - wasm32 only
398
+ #[cfg(target_arch = "wasm32")]
399
+ pub mod segmentation {
400
+ use wasm_bindgen::prelude::*;
401
+ use wasm_bindgen_futures::JsFuture;
402
+
403
+ #[wasm_bindgen(module = "/public/segmentation_worker.js")]
404
+ extern "C" {
405
+ #[wasm_bindgen(js_name = segmentImage, catch)]
406
+ fn segment_image_js(jpeg_bytes: &[u8]) -> js_sys::Promise;
407
+ }
408
+
409
+ pub async fn segment_image(jpeg_bytes: Vec<u8>) -> Result<Vec<u8>, JsValue> {
410
+ let promise = segment_image_js(&jpeg_bytes);
411
+ let result = JsFuture::from(promise).await?;
412
+ let arr = js_sys::Uint8Array::from(result);
413
+ Ok(arr.to_vec())
414
+ }
415
+ }
416
+ ```
417
+
418
+ ```javascript
419
+ // public/segmentation_worker.js - plain ES module, no bundler needed
420
+ import { AutoModel, AutoProcessor, env, RawImage }
421
+ from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3/dist/transformers.min.js';
422
+
423
+ env.allowLocalModels = false;
424
+ let modelCache = null;
425
+
426
+ async function loadModel() {
427
+ if (modelCache) return modelCache;
428
+ const device = navigator.gpu ? 'webgpu' : 'wasm';
429
+ const [model, processor] = await Promise.all([
430
+ AutoModel.from_pretrained('Xenova/modnet', { device }),
431
+ AutoProcessor.from_pretrained('Xenova/modnet'),
432
+ ]);
433
+ modelCache = { model, processor };
434
+ return modelCache;
435
+ }
436
+
437
+ export async function segmentImage(jpegBytes) {
438
+ const { model, processor } = await loadModel();
439
+ const blob = new Blob([jpegBytes], { type: 'image/jpeg' });
440
+ const image = await RawImage.fromURL(URL.createObjectURL(blob));
441
+ const inputs = await processor(image);
442
+ const { output } = await model(inputs);
443
+
444
+ const mask = output.data;
445
+ const [,, maskH, maskW] = output.dims;
446
+
447
+ const imageBitmap = await createImageBitmap(blob);
448
+ const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height);
449
+ const ctx = canvas.getContext('2d');
450
+ ctx.drawImage(imageBitmap, 0, 0);
451
+
452
+ const imgData = ctx.getImageData(0, 0, imageBitmap.width, imageBitmap.height);
453
+ const scaleX = imageBitmap.width / maskW;
454
+ const scaleY = imageBitmap.height / maskH;
455
+ for (let y = 0; y < imageBitmap.height; y++) {
456
+ for (let x = 0; x < imageBitmap.width; x++) {
457
+ const mx = Math.min(Math.floor(x / scaleX), maskW - 1);
458
+ const my = Math.min(Math.floor(y / scaleY), maskH - 1);
459
+ imgData.data[(y * imageBitmap.width + x) * 4 + 3] =
460
+ Math.round(mask[my * maskW + mx] * 255);
461
+ }
462
+ }
463
+ ctx.putImageData(imgData, 0, 0);
464
+
465
+ const outBlob = await canvas.convertToBlob({ type: 'image/png' });
466
+ return new Uint8Array(await outBlob.arrayBuffer());
467
+ }
468
+ ```
469
+
470
+ ---
471
+
472
+ ## Visual Design
473
+
474
+ ### Aesthetic: Enchanted Storybook
475
+ Warm parchment backgrounds, ink-like borders, watercolor-wash panels.
476
+ Nothing generic or digital. Every element feels hand-illustrated.
477
+
478
+ ### Color Palette
479
+ ```css
480
+ :root {
481
+ --parchment: #fdf6e3; /* app background */
482
+ --panel: #fff8f0; /* card backgrounds */
483
+ --ink: #2d1b4e; /* text, borders */
484
+ --rose: #e8738a; /* primary action */
485
+ --rose-light: #f9c0cb; /* hover / tint */
486
+ --gold: #f0b429; /* snap rings, accents, active */
487
+ --gold-light: #fde68a;
488
+ --lavender: #c3aed6; /* secondary elements */
489
+ --lavender-dk: #7c5cbf;
490
+ --mint: #a8d8a8; /* success */
491
+ --shadow: rgba(45, 27, 78, 0.12);
492
+ --shadow-lifted: rgba(45, 27, 78, 0.25); /* dragging state */
493
+ }
494
+ ```
495
+
496
+ ### Typography
497
+ ```css
498
+ --font: 'Baloo 2', cursive;
499
+ /* weights: 400 body / 700 labels / 800 titles */
500
+ ```
501
+
502
+ ### Animation Curves
503
+ ```css
504
+ --spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* snap overshoot */
505
+ --bounce: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* back to tray */
506
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* smooth settle */
507
+ ```
508
+
509
+ ### Interaction Feedback
510
+
511
+ | Event | Visual | Sound |
512
+ |--------------------|-------------------------------------|--------------|
513
+ | Pick up clothing | 1.2x scale, bigger shadow, tilt | - |
514
+ | Near snap zone | gold ring pulses on anchor point | - |
515
+ | Snap | spring-overshoot to position | snap.mp3 |
516
+ | Snap landed | 8-star sparkle burst at snap point | sparkle.mp3 |
517
+ | Bounce back | returns to tray with bounce curve | - |
518
+ | Double-tap remove | poof: scale to 0 + fade | - |
519
+ | Princess switch | slide left or right with spring | - |
520
+ | Upload success | crown spins -> check -> green flash | sparkle.mp3 |
521
+
522
+ ### Keyframes (all in style/animations.css)
523
+ ```
524
+ sparkle-burst 8 stars fly outward + fade, 600ms
525
+ snap-ring-pulse gold ring scale + opacity, repeating
526
+ bounce-back item returns to tray with overshoot
527
+ crown-spin 360 degrees continuous, for loading
528
+ poof scale to 0 + fade, for remove
529
+ slide-in-right princess switcher forward direction
530
+ slide-in-left princess switcher backward direction
531
+ float-pickup item scale-up + shadow on grab
532
+ success-flash green overlay flash on upload complete
533
+ ```
534
+
535
+ ---
536
+
537
+ ## File Structure
538
+
539
+ ```
540
+ princess-game/
541
+ CLAUDE.md <- THIS FILE, source of truth + task board
542
+ Cargo.toml
543
+ .env
544
+ .env.example
545
+ .gitignore
546
+
547
+ src/
548
+ main.rs <- Axum server entry (ssr feature only)
549
+ lib.rs <- WASM hydrate entry + module declarations
550
+ app.rs <- Root Leptos component + router (3 routes)
551
+ models.rs <- All shared data types
552
+ interop.rs <- wasm_bindgen JS bridge (wasm32 only)
553
+
554
+ components/
555
+ mod.rs
556
+ dress_up/
557
+ mod.rs <- DressUpScreen: top-level state + layout
558
+ princess_canvas.rs <- Image layers + snap zone rings
559
+ clothing_tray.rs <- Horizontal tray + category filter tabs
560
+ drag_ghost.rs <- Floating div via Portal, GPU-composited
561
+ snap_engine.rs <- Snap zone math + magnetic logic (pure fns)
562
+ upload/
563
+ mod.rs <- UploadScreen orchestrator
564
+ camera_capture.rs <- File input + FileReader + preview
565
+ segmentation.rs <- State machine + JS interop call
566
+ category_picker.rs <- Emoji category grid
567
+ anchor_editor/
568
+ mod.rs <- AnchorEditorScreen
569
+ draggable_dot.rs <- One colored draggable anchor dot
570
+ shared/
571
+ mod.rs
572
+ big_button.rs <- Reusable large touch button
573
+ sparkle.rs <- 8-star burst overlay component
574
+ loading_crown.rs <- Spinning crown indicator
575
+
576
+ server/ <- All behind #[cfg(feature = "ssr")]
577
+ mod.rs
578
+ firebase.rs <- Firestore + Storage REST calls
579
+ image_process.rs <- optimize, thumbnail, auto_anchors
580
+ auth.rs <- Anonymous auth token verification
581
+
582
+ style/
583
+ main.css <- Tokens, reset, layout, typography
584
+ dress_up.css <- Canvas, placed items, snap rings
585
+ clothing_tray.css <- Tray scroll, item cards, tabs
586
+ upload.css <- Camera zone, progress, picker
587
+ animations.css <- All @keyframes
588
+
589
+ public/
590
+ manifest.json <- PWA manifest
591
+ segmentation_worker.js <- transformers.js MODNet (ES module)
592
+ icons/
593
+ icon-192.png
594
+ icon-512.png
595
+ sounds/
596
+ snap.mp3
597
+ sparkle.mp3
598
+
599
+ Dockerfile
600
+ ```
601
+
602
+ ---
603
+
604
+ ## Cargo.toml
605
+
606
+ ```toml
607
+ [package]
608
+ name = "princess_game"
609
+ version = "0.1.0"
610
+ edition = "2021"
611
+
612
+ [lib]
613
+ crate-type = ["cdylib", "rlib"]
614
+
615
+ [[bin]]
616
+ name = "princess_game"
617
+ path = "src/main.rs"
618
+
619
+ [features]
620
+ default = []
621
+ hydrate = ["leptos/hydrate"]
622
+ ssr = [
623
+ "leptos/ssr", "leptos_axum", "leptos_meta/ssr", "leptos_router/ssr",
624
+ "dep:axum", "dep:tokio", "dep:tower", "dep:tower-http",
625
+ "dep:reqwest", "dep:image", "dep:base64", "dep:dotenvy",
626
+ "dep:jsonwebtoken", "dep:chrono", "dep:urlencoding", "dep:uuid",
627
+ ]
628
+
629
+ [dependencies]
630
+ leptos = { version = "0.7" }
631
+ leptos_meta = { version = "0.7" }
632
+ leptos_router = { version = "0.7" }
633
+ serde = { version = "1", features = ["derive"] }
634
+ serde_json = "1"
635
+ wasm-bindgen = "0.2"
636
+ wasm-bindgen-futures = "0.4"
637
+ js-sys = "0.3"
638
+ web-sys = { version = "0.3", features = [
639
+ "Window", "Document", "Element", "HtmlElement", "HtmlInputElement",
640
+ "PointerEvent", "File", "FileList", "FileReader", "Blob", "Url",
641
+ "OffscreenCanvas", "ImageBitmap", "HtmlAudioElement",
642
+ "Navigator", "Gpu", "DomRect",
643
+ ] }
644
+
645
+ leptos_axum = { version = "0.7", optional = true }
646
+ axum = { version = "0.7", features = ["multipart"], optional = true }
647
+ tokio = { version = "1", features = ["full"], optional = true }
648
+ tower = { version = "0.4", optional = true }
649
+ tower-http = { version = "0.5", features = ["fs", "cors"], optional = true }
650
+ reqwest = { version = "0.12", features = ["json"], optional = true }
651
+ image = { version = "0.25", features = ["png", "jpeg"], optional = true }
652
+ base64 = { version = "0.22", optional = true }
653
+ dotenvy = { version = "0.15", optional = true }
654
+ jsonwebtoken = { version = "9", optional = true }
655
+ chrono = { version = "0.4", optional = true }
656
+ urlencoding = { version = "2", optional = true }
657
+ uuid = { version = "1", features = ["v4"], optional = true }
658
+
659
+ [profile.release]
660
+ opt-level = 3
661
+ lto = true
662
+ codegen-units = 1
663
+
664
+ [profile.dev.package."*"]
665
+ opt-level = 1
666
+
667
+ [package.metadata.leptos]
668
+ output-name = "princess_game"
669
+ site-root = "target/site"
670
+ site-pkg-dir = "pkg"
671
+ style-file = "style/main.css"
672
+ assets-dir = "public"
673
+ site-addr = "127.0.0.1:3000"
674
+ reload-port = 3001
675
+ bin-features = ["ssr"]
676
+ lib-features = ["hydrate"]
677
+ ```
678
+
679
+ ---
680
+
681
+ ## Environment Variables
682
+
683
+ ```bash
684
+ FIREBASE_PROJECT_ID=princess-game-xxx
685
+ FIREBASE_STORAGE_BUCKET=princess-game-xxx.appspot.com
686
+ FIREBASE_API_KEY=AIza...
687
+ FIREBASE_SERVICE_ACCOUNT=eyJ... # base64-encoded service account JSON
688
+ LEPTOS_OUTPUT_NAME=princess_game
689
+ LEPTOS_SITE_ADDR=0.0.0.0:3000
690
+ ```
691
+
692
+ ---
693
+
694
+ ## Tuning Constants
695
+
696
+ These live in src/components/dress_up/snap_engine.rs. Adjust after playtesting:
697
+
698
+ ```rust
699
+ pub const SNAP_THRESHOLD_PX: f32 = 80.0; // distance to hard-lock to snap point
700
+ pub const MAGNETIC_START_PX: f32 = 160.0; // distance to start magnetic pull
701
+ pub const DOUBLE_TAP_MS: u32 = 300; // max ms between taps = double-tap
702
+ pub const DRAG_DEAD_ZONE_PX: f32 = 10.0; // movement before drag starts vs tap
703
+ ```
704
+
705
+ Z-index layer order by category:
706
+ ```
707
+ shoes=1, dress=2, top=3, skirt=3, cape=4, necklace=5, crown=6, wand=7
708
+ ```
709
+
710
+ ---
711
+
712
+ ## Known Hard Parts
713
+
714
+ ### 1. setPointerCapture on mobile
715
+ Must call element.set_pointer_capture(pointer_id) on pointerdown on the ghost
716
+ element (or a full-screen invisible overlay). Without this, fast finger movement
717
+ loses pointermove events when the finger slides off the ghost element bounds.
718
+
719
+ ### 2. Image rect vs container rect for snap zones
720
+ The princess img uses object-fit:contain, so letterbox space exists inside the
721
+ container. Snap zone pixel positions must use the RENDERED IMAGE RECT, not the
722
+ container rect. Use a NodeRef on the img element and call getBoundingClientRect()
723
+ on every pointermove. Recompute on window resize too.
724
+
725
+ ### 3. transformers.js on iOS Safari
726
+ WebGPU is behind a flag on iOS Safari. Always check navigator.gpu before
727
+ requesting WebGPU. The 'wasm' device fallback works but is ~5x slower.
728
+ Show a "Processing... this may take a moment" message when WebGPU is unavailable.
729
+
730
+ ### 4. wasm_bindgen async with JS Promises
731
+ segment_image_js() returns js_sys::Promise. Wrap with JsFuture::from(promise).await
732
+ inside spawn_local in the upload component. This is browser-side only. The server
733
+ function only receives the final already-segmented PNG bytes.
734
+
735
+ ### 5. Pointer coordinate spaces
736
+ pointer_event.client_x/y() is in viewport coords.
737
+ Canvas rect from getBoundingClientRect() is also in viewport coords.
738
+ Canvas-relative: canvas_x = client_x - rect.left. All snap math in canvas-relative px.
739
+
740
+ ### 6. Double-tap detection
741
+ Track last_tap_time: Option<f64> from performance.now(). On pointerup, if
742
+ (now - last_tap_time) < DOUBLE_TAP_MS and movement < DRAG_DEAD_ZONE_PX = double-tap.
743
+ Add touch-action: manipulation in CSS to suppress browser zoom on double-tap.
744
+
745
+ ### 7. Ghost div escaping overflow:hidden
746
+ The drag ghost must be a child of body, not inside the canvas container (which
747
+ has overflow:hidden). Use a Leptos Portal to render it at the body level.
748
+
749
+ ---
750
+
751
+ ## Task Board
752
+
753
+ Workflow for each task:
754
+ 1. Read CLAUDE.md before starting
755
+ 2. Move task to IN PROGRESS (update this file)
756
+ 3. Implement it
757
+ 4. Run "cargo leptos check" - fix ALL errors before proceeding
758
+ 5. Move to DONE with a one-line note about what was tricky
759
+ 6. Commit: "feat: {TASK-ID} short description"
760
+
761
+ ---
762
+
763
+ ### BLOCKED
764
+
765
+
766
+ ---
767
+
768
+ ### TODO
769
+
770
+ #### PHASE 0 - Foundation
771
+
772
+ - [ ] P0-01 Scaffold cargo-leptos project
773
+ Install cargo-leptos and wasm32 target. Scaffold project using Cargo.toml
774
+ from this file. Verify "cargo leptos watch" serves at localhost:3000.
775
+ Commit: "chore: scaffold"
776
+
777
+ - [ ] P0-02 Firebase project setup (done in browser console, not in code)
778
+ Create Firebase project. Enable Firestore, Storage, Anonymous Auth.
779
+ Set security rules (user-scoped: /users/{uid}/... readable/writable only by
780
+ that uid). Generate service account JSON, base64-encode it, add to .env.
781
+ Copy Firebase web config values to .env.
782
+
783
+ - [ ] P0-03 src/models.rs - all shared data types
784
+ Anchor { x: f32, y: f32 }
785
+ Princess { id, name, image_url, thumbnail_url, anchors: HashMap<String,Anchor> }
786
+ Clothing { id, name, category: Category, image_url, thumbnail_url,
787
+ attach_point: Anchor, target_anchor: String, scale: f32, z_index: i32 }
788
+ PlacedClothing { clothing_id, anchor_used: Option<String>, offset: (f32,f32),
789
+ scale: f32, z_index: i32 }
790
+ SnapZone { anchor_name: String, x: f32, y: f32, radius: f32 }
791
+ DragKind { FromTray(String), FromCanvas(String, usize) }
792
+ DragState { kind: DragKind, start: (f32,f32), current: (f32,f32),
793
+ active_snap: Option<usize> }
794
+ Category enum with all variants + target_anchor() and default_z_index() methods
795
+ All types: #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
796
+
797
+ - [ ] P0-04 src/server/image_process.rs
798
+ optimize_png(bytes: Vec<u8>) -> Result<Vec<u8>>
799
+ Load with image crate, convert RGBA8, resize max 1200px longest side (Lanczos3)
800
+ Re-encode as PNG
801
+ generate_thumbnail(bytes: Vec<u8>) -> Result<Vec<u8>>
802
+ Resize to 128x128 contain (transparent letterbox), PNG
803
+ auto_anchors(png_bytes: &[u8]) -> Result<HashMap<String, Anchor>>
804
+ Load RGBA, scan alpha > 10 for bounding box
805
+ Apply heuristics from "Anchor Auto-Detection Heuristics" section
806
+ Return normalized coords (0.0-1.0)
807
+ Write a unit test: run on a test PNG, assert anchor coords are in valid ranges
808
+
809
+ - [ ] P0-05 src/server/firebase.rs
810
+ Service account OAuth2 token (JWT with jsonwebtoken crate, exchange at
811
+ oauth2.googleapis.com/token). Cache token in tokio::sync::RwLock with expiry.
812
+ upload_image(bytes: &[u8], path: &str) -> Result<String> (returns public URL)
813
+ save_princess(uid, name, image_url, thumb_url, anchors) -> Result<String>
814
+ save_clothing(uid, name, category, image_url, thumb_url, attach_point,
815
+ target_anchor, scale) -> Result<String>
816
+ list_princesses(uid) -> Result<Vec<Princess>>
817
+ list_clothes(uid) -> Result<Vec<Clothing>>
818
+ update_anchors(uid, princess_id, anchors) -> Result<()>
819
+ Test each function against real Firebase before wiring to server functions.
820
+
821
+ - [ ] P0-06 src/server/auth.rs
822
+ Firebase Anonymous Auth flow:
823
+ Client JS calls firebase.auth().signInAnonymously() via JS interop on load
824
+ Client passes uid + ID token with each server function call
825
+ Server: verify_id_token(token: &str) -> Result<String> (returns uid)
826
+ Call https://identitytoolkit.googleapis.com/v1/accounts:lookup?key={API_KEY}
827
+ with the token. Return uid from the response.
828
+ For v1: can skip server-side verification and just trust uid from client,
829
+ adding full verification in a later pass.
830
+
831
+ - [ ] P0-07 public/segmentation_worker.js
832
+ ES module as shown in "JS Interop Design" section.
833
+ Test standalone: create test_seg.html, drop a JPEG, verify transparent PNG output.
834
+ Verify WebGPU path on Chrome desktop.
835
+ Verify WASM fallback on Safari or Firefox.
836
+
837
+ - [ ] P0-08 src/interop.rs
838
+ wasm_bindgen extern block for segmentImage (as shown in JS Interop Design section)
839
+ pub async fn segment_image(jpeg_bytes: Vec<u8>) -> Result<Vec<u8>, JsValue>
840
+ pub fn init_audio() - creates Audio elements for snap.mp3 and sparkle.mp3
841
+ pub fn play_snap() - resets currentTime to 0, calls play()
842
+ pub fn play_sparkle() - same for sparkle sound
843
+ Only compiled for target_arch = "wasm32"
844
+
845
+
846
+ #### PHASE 1 - Upload Flow
847
+
848
+ - [ ] P1-01 src/components/upload/camera_capture.rs
849
+ Hidden input[type=file, accept="image/*", capture="environment"]
850
+ Large styled label covers the upper half of screen (tap anywhere = open camera)
851
+ After capture: show photo preview in the zone using object URL
852
+ Read bytes via FileReader.readAsArrayBuffer -> Vec<u8> in a Leptos RwSignal
853
+ Show image dimensions + file size in small text below (useful during dev)
854
+
855
+ - [ ] P1-02 src/components/upload/category_picker.rs
856
+ Props: selected: RwSignal<Category>
857
+ Big emoji buttons in 3-column grid
858
+ Each: emoji (2.5rem) + label text + gold border when selected + bounce on tap
859
+ Only shown when upload_type == Clothing
860
+
861
+ - [ ] P1-03 src/components/upload/segmentation.rs
862
+ State machine: enum SegState { Idle, Processing, Preview(Vec<u8>), Error(String) }
863
+ Idle: show "Magic Time!" button (disabled until photo + name filled in)
864
+ Processing: spinning crown + "Removing the background!" text
865
+ Preview:
866
+ Convert Vec<u8> to object URL, show in img element
867
+ "Looks good!" button -> triggers upload server function
868
+ "Try again" button -> back to Idle
869
+ Error: friendly child message + "Try again" button
870
+ On Magic Time click: spawn_local(async { interop::segment_image(jpeg_bytes).await })
871
+
872
+ - [ ] P1-04 UploadScreen (src/components/upload/mod.rs)
873
+ Type toggle: [Princess] [Clothes] pill buttons at top
874
+ Compose: camera_capture + (if Clothes: category_picker) + name input + segmentation
875
+ Server function: upload_asset(uid, name, category_str, png_b64) -> Result<String>
876
+ Decode base64 -> bytes
877
+ optimize_png + generate_thumbnail + auto_anchors
878
+ firebase save_princess or save_clothing
879
+ Return new document ID
880
+ On success:
881
+ If Princess -> navigate to /anchor-editor/{id}
882
+ If Clothing -> navigate to / with a success flash signal
883
+
884
+ - [ ] P1-05 AnchorEditorScreen (src/components/anchor_editor/mod.rs)
885
+ Route: /anchor-editor/:id
886
+ Load princess by ID from Firestore via server function
887
+ Show princess img filling the screen, position: relative
888
+ Overlay 4 draggable dots:
889
+ head_top (red circle, label "Head top")
890
+ neck (orange, label "Neck")
891
+ waist (yellow, label "Waist")
892
+ feet_center (blue, label "Feet")
893
+ Each dot: 36px circle, position absolute, draggable via pointer events
894
+ Clamp drag to image bounds
895
+ Show label on long-press (300ms hold)
896
+ "Save" -> server function update_anchors -> navigate to /
897
+ "Skip" -> navigate to / using auto-detected anchors as-is
898
+ Instruction text: "Drag the dots to the right spots!"
899
+
900
+
901
+ #### PHASE 2 - Dress-Up Core
902
+
903
+ - [ ] P2-01 src/components/dress_up/snap_engine.rs (pure functions, no Leptos)
904
+ struct Rect { x: f32, y: f32, width: f32, height: f32 }
905
+ const SNAP_THRESHOLD_PX: f32 = 80.0
906
+ const MAGNETIC_START_PX: f32 = 160.0
907
+
908
+ fn compute_snap_zones(princess: &Princess, img_rect: Rect) -> Vec<SnapZone>
909
+ For each anchor in princess.anchors:
910
+ px_x = img_rect.x + anchor.x * img_rect.width
911
+ px_y = img_rect.y + anchor.y * img_rect.height
912
+ radius = SNAP_THRESHOLD_PX
913
+
914
+ fn find_nearest_zone(zones: &[SnapZone], finger: (f32,f32)) -> Option<usize>
915
+ Returns index of zone with min dist where dist < SNAP_THRESHOLD_PX
916
+
917
+ fn magnetic_position(finger: (f32,f32), zone: &SnapZone) -> (f32,f32)
918
+ Quadratic lerp: t = 1 - clamp(dist/MAGNETIC_START_PX, 0,1); lerp(finger,zone,t*t)
919
+
920
+ fn placed_top_left(zone: &SnapZone, clothing: &Clothing, rendered_w: f32) -> (f32,f32)
921
+ rendered_w = princess_img_width * clothing.scale
922
+ rendered_h = same ratio from clothing image aspect ratio
923
+ attach_px = (attach_point.x * rendered_w, attach_point.y * rendered_h)
924
+ top_left = (zone.x - attach_px.x, zone.y - attach_px.y)
925
+
926
+ fn dist(a: (f32,f32), b: (f32,f32)) -> f32
927
+ fn lerp_pt(a: (f32,f32), b: (f32,f32), t: f32) -> (f32,f32)
928
+ Write unit tests for every function.
929
+
930
+ - [ ] P2-02 src/components/dress_up/drag_ghost.rs
931
+ Rendered via leptos Portal into document.body
932
+ Only rendered when drag_state signal is Some
933
+ CSS: position:fixed; pointer-events:none; z-index:9999; will-change:transform
934
+ Position set via inline style transform:translate({x}px,{y}px) on every pointermove
935
+ Shows clothing thumbnail image at 1.2x scale
936
+ When active_snap is Some: add gold box-shadow + scale to 1.25x
937
+ The ghost element's NodeRef is used for setPointerCapture in DressUpScreen
938
+
939
+ - [ ] P2-03 src/components/dress_up/princess_canvas.rs
940
+ Props:
941
+ princess: Signal<Princess>
942
+ placed: ReadSignal<Vec<PlacedClothing>>
943
+ clothes_map: Signal<HashMap<String,Clothing>>
944
+ drag_state: ReadSignal<Option<DragState>>
945
+ on_placed_drag_start: Callback<(String, usize)>
946
+ on_canvas_pointer_up: Callback<(f32,f32)>
947
+ on_remove: Callback<usize>
948
+ img_ref: NodeRef<html::Img> <- for getBoundingClientRect()
949
+
950
+ Outer container div: position:relative; aspect-ratio:3/4; overflow:hidden
951
+ Princess img: position:absolute; inset:0; width:100%; height:100%; object-fit:contain
952
+ NodeRef on the img (not the container) for rect computation
953
+
954
+ For each PlacedClothing sorted by z_index:
955
+ position:absolute img at computed top-left
956
+ pointerdown -> on_placed_drag_start(clothing_id, idx)
957
+ Double-tap detection -> on_remove(idx) + add CSS class "poof"
958
+
959
+ Snap zone rings (one div per anchor):
960
+ position:absolute at anchor pixel position
961
+ width:48px; height:48px; border-radius:50%
962
+ border:3px solid var(--gold); opacity:0 normally
963
+ opacity:1 + animation:snap-ring-pulse when this is the active_snap zone
964
+
965
+ pointerup on canvas container: on_canvas_pointer_up(client_x, client_y)
966
+
967
+ - [ ] P2-04 src/components/dress_up/clothing_tray.rs
968
+ Props:
969
+ clothes: ReadSignal<Vec<Clothing>>
970
+ placed_ids: ReadSignal<HashSet<String>>
971
+ on_drag_start: Callback<String>
972
+ on_tap: Callback<String>
973
+ filter: RwSignal<Option<Category>>
974
+
975
+ Category filter tabs above tray: "All" + one tab per category present in clothes
976
+ Tray div: display:flex; overflow-x:auto; gap:12px; scroll-snap-type:x mandatory
977
+ Each item card (min 90px wide, min 120px tall, scroll-snap-align:start):
978
+ Thumbnail img 64x64
979
+ Name label below
980
+ Checkmark badge overlay if id in placed_ids
981
+ On pointerdown: start a 150ms timer
982
+ On pointermove beyond DRAG_DEAD_ZONE_PX before timer fires: on_drag_start(id)
983
+ On pointerup within dead zone and timer not yet fired: on_tap(id)
984
+ Scale 0.95 on pointerdown, release on up/cancel
985
+
986
+ - [ ] P2-05 DressUpScreen (src/components/dress_up/mod.rs)
987
+ Signals:
988
+ princesses: Resource<Vec<Princess>>
989
+ clothes: Resource<Vec<Clothing>>
990
+ current_idx: RwSignal<usize>
991
+ placed: RwSignal<Vec<PlacedClothing>>
992
+ drag_state: RwSignal<Option<DragState>>
993
+ canvas_rect: RwSignal<Option<Rect>>
994
+ sparkle_pos: RwSignal<Option<(f32,f32)>>
995
+ filter: RwSignal<Option<Category>>
996
+ img_ref: NodeRef<html::Img>
997
+
998
+ On mount:
999
+ Load princesses and clothes via server functions
1000
+ Set canvas_rect from img_ref.get_bounding_client_rect()
1001
+ Add window resize listener to update canvas_rect
1002
+ Call interop::init_audio() on first pointerdown (satisfies autoplay policy)
1003
+
1004
+ snap_zones: Memo derived from current princess anchors + canvas_rect
1005
+ Recomputes whenever either changes
1006
+
1007
+ Global window pointermove handler:
1008
+ Update drag_state.current
1009
+ Recompute ghost visual position (magnetic formula)
1010
+
1011
+ Global window pointerup handler:
1012
+ If drag_state is Some:
1013
+ Get current canvas_rect
1014
+ Find nearest snap zone to drag_state.current
1015
+ If snapped:
1016
+ Compute PlacedClothing top-left via snap_engine::placed_top_left
1017
+ Add to placed signal
1018
+ Set sparkle_pos to snap zone center
1019
+ Call interop::play_sparkle()
1020
+ Elif pointer is inside canvas_rect:
1021
+ Add PlacedClothing at pointer position, anchor_used = None
1022
+ Else:
1023
+ Set drag_state to "bouncing" state -> CSS bounce-back animation
1024
+ Clear drag_state after placement
1025
+
1026
+ on_tray_tap(clothing_id):
1027
+ Find clothing in clothes resource
1028
+ Find target anchor in current princess anchors
1029
+ Compute PlacedClothing position at that anchor
1030
+ Add to placed, set sparkle_pos, play_sparkle()
1031
+
1032
+ on_placed_drag_start(clothing_id, idx):
1033
+ Remove placed[idx] from placed vec
1034
+ Create DragState { kind: FromCanvas, ... }
1035
+
1036
+ Princess switcher:
1037
+ Left/right buttons, clamp or wrap current_idx
1038
+ Add slide animation class on switch
1039
+ Clear placed vec on princess switch
1040
+
1041
+ Layout: title, canvas, switcher arrows, clothing tray, bottom bar
1042
+ Bottom bar: [Add Photo] -> /upload link, [Save Look] placeholder button
1043
+
1044
+
1045
+ #### PHASE 3 - Polish and Delight
1046
+
1047
+ - [ ] P3-01 src/components/shared/sparkle.rs
1048
+ Props: pos: ReadSignal<Option<(f32,f32)>>
1049
+ When Some: render 8 span.sparkle-star elements positioned around the point
1050
+ Each star: random angle (45deg increments), moves outward, fades, 600ms
1051
+ Stars: gold and rose colored star emojis or inline SVG
1052
+ After 700ms: clear pos signal via set_timeout
1053
+
1054
+ - [ ] P3-02 All style files
1055
+ style/main.css: CSS tokens, box-sizing reset, body/app-shell, Google Fonts import
1056
+ style/dress_up.css: canvas, placed items, snap rings, switcher, title
1057
+ style/clothing_tray.css: tray container, item cards, category tabs, checkmark badge
1058
+ style/upload.css: camera zone, preview, states, category picker, name input, submit
1059
+ style/animations.css: all @keyframes listed in the Keyframes section above
1060
+ Global rules on all interactive elements:
1061
+ touch-action: manipulation (prevents double-tap zoom)
1062
+ -webkit-tap-highlight-color: transparent
1063
+ user-select: none
1064
+
1065
+ - [ ] P3-03 src/components/shared/loading_crown.rs
1066
+ A centered div with a crown emoji in a circle
1067
+ animation: crown-spin 1s linear infinite
1068
+ Optional text prop shown below the crown
1069
+
1070
+ - [ ] P3-04 Sound system in src/interop.rs
1071
+ init_audio(): create HTMLAudioElement for each sound file, preload
1072
+ Must be called on first user pointerdown to satisfy browser autoplay policy
1073
+ play_snap(): audio.set_current_time(0.0); audio.play().ok()
1074
+ play_sparkle(): same
1075
+
1076
+ - [ ] P3-05 Empty states and error states
1077
+ No princesses: friendly illustration + "Draw a princess and add a photo!"
1078
+ No clothes: "Draw some clothes for your princess!"
1079
+ Upload error: "Oops! Let's try again"
1080
+ Network error: "No internet right now. Come back soon!"
1081
+ Never a dead end: every error has a retry or navigate-away action
1082
+
1083
+ - [ ] P3-06 PWA manifest and icons
1084
+ public/manifest.json with name, short_name, icons, theme_color (#f0b429),
1085
+ background_color (#fdf6e3), display: standalone, orientation: portrait
1086
+ Generate crown SVG icon, export 192x192 and 512x512 PNGs
1087
+ Add <link rel="manifest"> and <meta name="theme-color"> to app.rs head
1088
+
1089
+ - [ ] P3-07 Responsive layout + real device testing
1090
+ Test on: iPhone SE (375px), iPhone 15 (390px), iPad (768px)
1091
+ Canvas must be fully visible without scrolling on all above
1092
+ Tray reachable with thumb at bottom of screen
1093
+ All tap targets minimum 48x48px
1094
+ env(safe-area-inset-*) applied to bottom-bar padding on notched phones
1095
+ Verify segmentation works on phone camera JPEG (may differ from desktop PNG)
1096
+
1097
+
1098
+ #### PHASE 4 - Deployment
1099
+
1100
+ - [ ] P4-01 Dockerfile (multi-stage build)
1101
+ Stage 1 (builder): FROM rust:1.77
1102
+ cargo install cargo-leptos
1103
+ rustup target add wasm32-unknown-unknown
1104
+ COPY . .
1105
+ RUN cargo leptos build --release
1106
+ Stage 2 (runtime): FROM debian:bookworm-slim
1107
+ COPY binary and target/site/
1108
+ Set LEPTOS_SITE_ROOT, expose 3000, CMD the binary
1109
+
1110
+ - [ ] P4-02 Fly.io deploy
1111
+ fly launch in project root (generates fly.toml)
1112
+ fly secrets set for all env vars
1113
+ fly deploy
1114
+ Smoke test on real phone: load app, photograph a drawing, dress it up, save works
1115
+
1116
+
1117
+ #### STRETCH GOALS
1118
+
1119
+ - [ ] SG-01 Pinch-to-resize placed clothing
1120
+ Track two pointerdown events. On pointermove, compute distance ratio vs start.
1121
+ Update PlacedClothing.scale. Clamp 0.3 to 2.0.
1122
+
1123
+ - [ ] SG-02 Two-finger rotation
1124
+ Track angle between two pointers. Add rotation: f32 to PlacedClothing.
1125
+ Apply transform: translate() rotate({r}rad) scale({s}).
1126
+
1127
+ - [ ] SG-03 Save Look screenshot
1128
+ Composite all layers on OffscreenCanvas. convertToBlob.
1129
+ Upload to Firebase Storage. Show in a gallery screen.
1130
+
1131
+ - [ ] SG-04 Sticker mode
1132
+ Free-drop decorations (stars, hearts, flowers) with no snapping.
1133
+
1134
+
1135
+ ---
1136
+
1137
+ ### IN PROGRESS
1138
+
1139
+ (move one task here at a time)
1140
+
1141
+
1142
+ ---
1143
+
1144
+ ### DONE
1145
+
1146
+ (completed tasks with one-line notes go here)
1147
+
1148
+
1149
+ ---
1150
+
1151
+ ## Code Rules (Claude Code must follow these)
1152
+
1153
+ 1. No unwrap() or expect() in production code paths. Use ? and anyhow::Result.
1154
+ 2. SSR-only code always behind #[cfg(feature = "ssr")]
1155
+ 3. WASM-only code always behind #[cfg(target_arch = "wasm32")]
1156
+ 4. Pointer events only - no mouse-only event handlers (breaks mobile)
1157
+ 5. All stored coordinates normalized 0.0-1.0, convert to px at render time only
1158
+ 6. Child-friendly error messages in UI - never raw error strings
1159
+ 7. Server logging with tracing::error! not println!
1160
+ 8. All interactive elements: touch-action: manipulation in CSS
1161
+
1162
+ ## Invariants Never to Break
1163
+
1164
+ 1. PlacedClothing.anchor_used is None for free-placed items, never assume snapped
1165
+ 2. Snap zones always recomputed from live canvas rect, never cached across renders
1166
+ 3. Drag ghost always rendered via Portal into body, never inside canvas container
1167
+ 4. setPointerCapture called on ghost element on pointerdown, not on tray item
1168
+ 5. Firebase service account credentials only ever on the server side
1169
+ 6. Segmentation runs client-side (WASM), server only receives final PNG bytes
src/app.rs ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ use leptos::prelude::*;
2
+ use leptos_meta::*;
3
+
4
+ pub fn shell(options: LeptosOptions) -> impl IntoView {
5
+ view! {
6
+ <!DOCTYPE html>
7
+ <html lang="en">
8
+ <head>
9
+ <meta charset="utf-8"/>
10
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
11
+ <AutoReload options=options.clone()/>
12
+ <HydrationScripts options/>
13
+ <MetaTags/>
14
+ </head>
15
+ <body>
16
+ <App/>
17
+ </body>
18
+ </html>
19
+ }
20
+ }
21
+
22
+ #[component]
23
+ pub fn App() -> impl IntoView {
24
+ provide_meta_context();
25
+
26
+ view! {
27
+ <Stylesheet id="leptos" href="/pkg/princess.css"/>
28
+ <Title text="Princess Dress-Up"/>
29
+ <HomePage/>
30
+ }
31
+ }
32
+
33
+ #[component]
34
+ fn HomePage() -> impl IntoView {
35
+ let (count, set_count) = signal(0);
36
+
37
+ view! {
38
+ <div class="app">
39
+ <h1>"Princess Dress-Up"</h1>
40
+ <p>"Welcome to the magical dress-up game!"</p>
41
+ <button on:click=move |_| set_count.set(count.get() + 1)>
42
+ "Magic taps: " {count}
43
+ </button>
44
+ </div>
45
+ }
46
+ }
src/lib.rs ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ pub mod app;
2
+
3
+ #[cfg(feature = "hydrate")]
4
+ #[wasm_bindgen::prelude::wasm_bindgen]
5
+ pub fn hydrate() {
6
+ console_error_panic_hook::set_once();
7
+ leptos::mount::hydrate_body(app::App);
8
+ }
src/main.rs ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #[cfg(feature = "ssr")]
2
+ #[tokio::main]
3
+ async fn main() {
4
+ use axum::Router;
5
+ use leptos::prelude::*;
6
+ use leptos_axum::{generate_route_list, LeptosRoutes};
7
+ use princess::app::shell;
8
+
9
+ let conf = get_configuration(None).unwrap();
10
+ let leptos_options = conf.leptos_options;
11
+ let addr = leptos_options.site_addr;
12
+ let routes = generate_route_list(princess::app::App);
13
+
14
+ let app = Router::new()
15
+ .leptos_routes(&leptos_options, routes, {
16
+ let leptos_options = leptos_options.clone();
17
+ move || shell(leptos_options.clone())
18
+ })
19
+ .fallback(leptos_axum::file_and_error_handler(shell))
20
+ .with_state(leptos_options);
21
+
22
+ let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
23
+ println!("listening on http://{}", &addr);
24
+ axum::serve(listener, app.into_make_service())
25
+ .await
26
+ .unwrap();
27
+ }
28
+
29
+ #[cfg(not(feature = "ssr"))]
30
+ fn main() {}
style/main.css ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Baloo+2:wght@400;700;800&display=swap');
2
+
3
+ :root {
4
+ --parchment: #fdf6e3;
5
+ --panel: #fff8f0;
6
+ --ink: #2d1b4e;
7
+ --rose: #e8738a;
8
+ --rose-light: #f9c0cb;
9
+ --gold: #f0b429;
10
+ --gold-light: #fde68a;
11
+ --lavender: #c3aed6;
12
+ --lavender-dk: #7c5cbf;
13
+ --mint: #a8d8a8;
14
+ --shadow: rgba(45, 27, 78, 0.12);
15
+ --shadow-lifted: rgba(45, 27, 78, 0.25);
16
+ --font: 'Baloo 2', cursive;
17
+ --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
18
+ --bounce: cubic-bezier(0.68, -0.55, 0.27, 1.55);
19
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
20
+ }
21
+
22
+ *, *::before, *::after {
23
+ box-sizing: border-box;
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+
28
+ html, body {
29
+ height: 100%;
30
+ font-family: var(--font);
31
+ background: var(--parchment);
32
+ color: var(--ink);
33
+ -webkit-font-smoothing: antialiased;
34
+ touch-action: manipulation;
35
+ user-select: none;
36
+ -webkit-user-select: none;
37
+ -webkit-tap-highlight-color: transparent;
38
+ overflow: hidden;
39
+ }
40
+
41
+ .app {
42
+ display: flex;
43
+ flex-direction: column;
44
+ align-items: center;
45
+ justify-content: center;
46
+ height: 100vh;
47
+ padding: 2rem;
48
+ text-align: center;
49
+ gap: 1.5rem;
50
+ }
51
+
52
+ h1 {
53
+ font-size: 2.5rem;
54
+ font-weight: 800;
55
+ color: var(--lavender-dk);
56
+ }
57
+
58
+ p {
59
+ font-size: 1.2rem;
60
+ color: var(--ink);
61
+ }
62
+
63
+ button {
64
+ font-family: var(--font);
65
+ font-size: 1.3rem;
66
+ font-weight: 700;
67
+ padding: 1rem 2rem;
68
+ border: 3px solid var(--ink);
69
+ border-radius: 2rem;
70
+ background: var(--rose);
71
+ color: white;
72
+ cursor: pointer;
73
+ transition: transform 0.15s var(--spring), box-shadow 0.15s ease;
74
+ box-shadow: 0 4px 0 var(--ink);
75
+ touch-action: manipulation;
76
+ }
77
+
78
+ button:active {
79
+ transform: translateY(2px);
80
+ box-shadow: 0 2px 0 var(--ink);
81
+ }