···104104105105Highlights:
106106107107+- experimental WASM support
107108- better value type deserialization helpers
108109- service auth implementation
109110- XrpcRequest derive Macros
110111- more builders in generated api to make constructing things easier (lmk if compile time is awful)
111112- `AgentSessionExt` trait with a host of convenience methods for working with records and preferences
112113- Improvements to the `Collection` trait, code generation, and addition of the `VecUpdate` trait to enable that
113113-- A bunch of examples, both in the docs and in the repository
114114-- More lexicons in the generated API bindings.
115114116115## Development
117116118118-This repo uses [Flakes](https://nixos.asia/en/flakes) from the get-go.
117117+This repo uses [Flakes](https://nixos.asia/en/flakes)
119118120119```bash
121120# Dev shell
···129128```
130129131130There's also a [`justfile`](https://just.systems/) for Makefile-esque commands to be run inside of the devShell, and you can generally `cargo ...` or `just ...` whatever just fine if you don't want to use Nix and have the prerequisites installed.
131131+132132+133133+## Experimental WASM Support
134134+135135+Core crates (`jacquard-common`, `jacquard-api`, `jacquard-identity`, `jacquard-oauth`) compile for `wasm32-unknown-unknown`. Traits use [`trait-variant`](https://docs.rs/trait-variant) to conditionally exclude `Send` bounds on WASM targets. DNS-based handle resolution is gated behind the `dns` feature and unavailable on WASM (HTTPS well-known and PDS resolution still work).
136136+137137+Test WASM compilation:
138138+```bash
139139+just check-wasm
140140+# or: cargo build --target wasm32-unknown-unknown -p jacquard-common --no-default-features
141141+```
132142133143[](./LICENSE)
···119119 }
120120121121 /// Construct a TID from a timestamp (in microseconds) and clock ID
122122- pub fn from_time(timestamp: usize, clkid: u32) -> Self {
122122+ pub fn from_time(timestamp: u64, clkid: u32) -> Self {
123123 let str = smol_str::format_smolstr!(
124124 "{0}{1:2>2}",
125125 s32_encode(timestamp as u64),
···129129 }
130130131131 /// Extract the timestamp component (microseconds since UNIX epoch)
132132- pub fn timestamp(&self) -> usize {
132132+ pub fn timestamp(&self) -> u64 {
133133 s32decode(self.0[0..11].to_owned())
134134 }
135135···194194}
195195196196/// Decode a base32-sortable string into a usize
197197-pub fn s32decode(s: String) -> usize {
197197+pub fn s32decode(s: String) -> u64 {
198198 let mut i: usize = 0;
199199 for c in s.chars() {
200200 i = i * 32 + S32_CHAR.chars().position(|x| x == c).unwrap();
201201 }
202202- i
202202+ i as u64
203203}
204204205205impl FromStr for Tid {
···289289/// Based on adenosine/adenosine/src/identifiers.rs
290290/// TODO: clean up and normalize stuff between this and the stuff pulled from atrium
291291pub struct Ticker {
292292- last_timestamp: usize,
292292+ last_timestamp: u64,
293293 clock_id: u32,
294294}
295295···311311 let now = SystemTime::now()
312312 .duration_since(SystemTime::UNIX_EPOCH)
313313 .expect("timestamp in micros since UNIX epoch")
314314- .as_micros() as usize;
314314+ .as_micros() as u64;
315315 // mask to 53 bits
316316 let now = now & 0x001FFFFFFFFFFFFF;
317317 if now > self.last_timestamp {
+16-2
crates/jacquard-common/src/xrpc.rs
···226226impl<T: HttpClient> XrpcExt for T {}
227227228228/// Stateful XRPC call trait
229229+#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(Send))]
229230pub trait XrpcClient: HttpClient {
230231 /// Get the base URI for the client.
231232 fn base_uri(&self) -> Url;
···234235 fn opts(&self) -> impl Future<Output = CallOptions<'_>> {
235236 async { CallOptions::default() }
236237 }
238238+237239 /// Send an XRPC request and parse the response
240240+ #[cfg(not(target_arch = "wasm32"))]
238241 fn send<R>(
239242 &self,
240243 request: R,
241241- ) -> impl Future<Output = XrpcResult<Response<<R as XrpcRequest>::Response>>> + Send
244244+ ) -> impl Future<Output = XrpcResult<Response<<R as XrpcRequest>::Response>>>
245245+ where
246246+ R: XrpcRequest + Send + Sync,
247247+ <R as XrpcRequest>::Response: Send + Sync,
248248+ Self: Sync;
249249+250250+ /// Send an XRPC request and parse the response
251251+ #[cfg(target_arch = "wasm32")]
252252+ fn send<R>(
253253+ &self,
254254+ request: R,
255255+ ) -> impl Future<Output = XrpcResult<Response<<R as XrpcRequest>::Response>>>
242256 where
243257 R: XrpcRequest + Send + Sync,
244258 <R as XrpcRequest>::Response: Send + Sync;
···308322 #[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(self, request), fields(nsid = R::NSID)))]
309323 pub async fn send<R>(self, request: &R) -> XrpcResult<Response<<R as XrpcRequest>::Response>>
310324 where
311311- R: XrpcRequest + Send + Sync,
325325+ R: XrpcRequest,
312326 <R as XrpcRequest>::Response: Send + Sync,
313327 {
314328 let http_request = build_http_request(&self.base, request, &self.opts)
···55pre-commit-all:
66 pre-commit run --all-files
7788+# Check that jacquard-common compiles for wasm32
99+check-wasm:
1010+ cargo build --target wasm32-unknown-unknown -p jacquard-common --no-default-features
1111+812# Run 'cargo run' on the project
913run *ARGS:
1014 cargo run {{ARGS}}