From b7b7b37f1a13408a4491647e289f4d725614762a Mon Sep 17 00:00:00 2001 From: egol Date: Mon, 9 Jun 2025 17:03:55 -0700 Subject: [PATCH 01/71] basic hosting of frontend and websocket communication --- bundle-hello-world/Cargo.toml | 14 + bundle-hello-world/src/main.rs | 101 ++ bundle-hello-world/target/.rustc_info.json | 1 + bundle-hello-world/target/CACHEDIR.TAG | 3 + integ-tests/python/uv.lock | 966 +++++++++--------- .../src/baml_wasm_web/EventListener.tsx | 35 +- 6 files changed, 636 insertions(+), 484 deletions(-) create mode 100644 bundle-hello-world/Cargo.toml create mode 100644 bundle-hello-world/src/main.rs create mode 100644 bundle-hello-world/target/.rustc_info.json create mode 100644 bundle-hello-world/target/CACHEDIR.TAG diff --git a/bundle-hello-world/Cargo.toml b/bundle-hello-world/Cargo.toml new file mode 100644 index 0000000000..59e71968d7 --- /dev/null +++ b/bundle-hello-world/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "bundle-hello-world" +version = "0.1.0" +edition = "2024" + +[dependencies] +tokio = { version = "1", features = ["full"] } +warp = "0.3" +include_dir = "0.7" +mime_guess = "2.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio-stream = { version = "0.1", features = ["sync"] } +futures-util = "0.3" diff --git a/bundle-hello-world/src/main.rs b/bundle-hello-world/src/main.rs new file mode 100644 index 0000000000..5a5689fe84 --- /dev/null +++ b/bundle-hello-world/src/main.rs @@ -0,0 +1,101 @@ +// src/main.rs +use futures_util::{SinkExt, StreamExt}; +use include_dir::{Dir, include_dir}; +use mime_guess::from_path; +use serde::Serialize; +use std::{convert::Infallible, ops::Range}; +use tokio::sync::broadcast; +use warp::{ + Filter, + http::Response, + ws::{Message, WebSocket}, +}; + +/// Embed at compile time everything in dist/ +static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); + +#[derive(Serialize)] +struct Hello { + message: &'static str, +} + +/// Handle a new WebSocket client: forward every broadcasted String as a text frame. +async fn client_connection(ws: WebSocket, mut rx: broadcast::Receiver) { + let (mut tx, mut _rx) = ws.split(); + // Spawn a task that listens on the broadcast channel... + tokio::spawn(async move { + while let Ok(json_msg) = rx.recv().await { + if tx.send(Message::text(json_msg)).await.is_err() { + // client disconnected + break; + } + } + }); + // (Optionally) you can also read from `_rx` if clients send you messages. +} + +#[tokio::main] +async fn main() { + // 1) Create a broadcast channel for JSON‐payloads + let (tx, _rx) = broadcast::channel::(16); + + // 2) Simple API route + let api = warp::path!("api" / "hello").map(|| { + warp::reply::json(&Hello { + message: "Hello from Rust!", + }) + }); + + // 3) Static‐file SPA handler + let spa = + warp::path::full() + .and(warp::get()) + .and_then(|full: warp::path::FullPath| async move { + let path = full.as_str().trim_start_matches('/'); + let file = if path.is_empty() { "index.html" } else { path }; + match STATIC_DIR.get_file(file) { + Some(f) => { + let body = f.contents(); + let mime = from_path(file).first_or_octet_stream(); + Ok::<_, Infallible>( + Response::builder() + .header("content-type", mime.as_ref()) + .body(body.to_vec()), + ) + } + None => Ok(Response::builder().status(404).body(b"Not Found".to_vec())), + } + }); + + // 4) WebSocket route at /ws + let tx_ws = tx.clone(); + let ws_route = warp::path("ws") + .and(warp::ws()) + .map(move |ws: warp::ws::Ws| { + let rx = tx_ws.subscribe(); + ws.on_upgrade(move |socket| client_connection(socket, rx)) + }); + + // 5) Combine all routes + let routes = ws_route.or(api).or(spa).with(warp::log("bundle-server")); + + // 6) Example: after 5 seconds, broadcast a demo message + let demo_tx = tx.clone(); + tokio::spawn(async move { + for _i in 0..100 { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + let payload = serde_json::json!({ + "command": "add_project", + "content": { + "root_path": "/foo/bar", + "files": { "main.baml": "class Receipt {}" } + } + }); + let _ = demo_tx.send(payload.to_string()); + } + }); + + // 7) Launch the server + println!("Listening on http://localhost:3030 …"); + warp::serve(routes).run(([127, 0, 0, 1], 3030)).await; +} diff --git a/bundle-hello-world/target/.rustc_info.json b/bundle-hello-world/target/.rustc_info.json new file mode 100644 index 0000000000..cf06391425 --- /dev/null +++ b/bundle-hello-world/target/.rustc_info.json @@ -0,0 +1 @@ +{"rustc_fingerprint":15275327620044501057,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.87.0 (17067e9ac 2025-05-09)\nbinary: rustc\ncommit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359\ncommit-date: 2025-05-09\nhost: aarch64-apple-darwin\nrelease: 1.87.0\nLLVM version: 20.1.1\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/egor/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""}},"successes":{}} \ No newline at end of file diff --git a/bundle-hello-world/target/CACHEDIR.TAG b/bundle-hello-world/target/CACHEDIR.TAG new file mode 100644 index 0000000000..20d7c319cd --- /dev/null +++ b/bundle-hello-world/target/CACHEDIR.TAG @@ -0,0 +1,3 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by cargo. +# For information about cache directory tags see https://bford.info/cachedir/ diff --git a/integ-tests/python/uv.lock b/integ-tests/python/uv.lock index 489ec479ad..8d4a743433 100644 --- a/integ-tests/python/uv.lock +++ b/integ-tests/python/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 2 requires-python = ">=3.9, <4" resolution-markers = [ "python_full_version < '3.10'", @@ -9,9 +10,9 @@ resolution-markers = [ name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] [[package]] @@ -27,9 +28,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/e3/a88c8494ce4d1a88252b9e053607e885f9b14d0a32273d47b727cbee4228/anthropic-0.49.0.tar.gz", hash = "sha256:c09e885b0f674b9119b4f296d8508907f6cff0009bc20d5cf6b35936c40b4398", size = 210016 } +sdist = { url = "https://files.pythonhosted.org/packages/86/e3/a88c8494ce4d1a88252b9e053607e885f9b14d0a32273d47b727cbee4228/anthropic-0.49.0.tar.gz", hash = "sha256:c09e885b0f674b9119b4f296d8508907f6cff0009bc20d5cf6b35936c40b4398", size = 210016, upload-time = "2025-02-28T19:35:47.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/74/5d90ad14d55fbe3f9c474fdcb6e34b4bed99e3be8efac98734a5ddce88c1/anthropic-0.49.0-py3-none-any.whl", hash = "sha256:bbc17ad4e7094988d2fa86b87753ded8dce12498f4b85fe5810f208f454a8375", size = 243368 }, + { url = "https://files.pythonhosted.org/packages/76/74/5d90ad14d55fbe3f9c474fdcb6e34b4bed99e3be8efac98734a5ddce88c1/anthropic-0.49.0-py3-none-any.whl", hash = "sha256:bbc17ad4e7094988d2fa86b87753ded8dce12498f4b85fe5810f208f454a8375", size = 243368, upload-time = "2025-02-28T19:35:44.963Z" }, ] [[package]] @@ -42,24 +43,24 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 } +sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 }, + { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, ] [[package]] name = "assertpy" version = "1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4f/39/720b5d4463612a40a166d00999cbb715fce3edaf08a9a7588ba5985699ec/assertpy-1.1.tar.gz", hash = "sha256:acc64329934ad71a3221de185517a43af33e373bb44dc05b5a9b174394ef4833", size = 25421 } +sdist = { url = "https://files.pythonhosted.org/packages/4f/39/720b5d4463612a40a166d00999cbb715fce3edaf08a9a7588ba5985699ec/assertpy-1.1.tar.gz", hash = "sha256:acc64329934ad71a3221de185517a43af33e373bb44dc05b5a9b174394ef4833", size = 25421, upload-time = "2020-07-19T14:39:02.462Z" } [[package]] name = "blinker" version = "1.8.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/57/a6a1721eff09598fb01f3c7cda070c1b6a0f12d63c83236edf79a440abcc/blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83", size = 23161 } +sdist = { url = "https://files.pythonhosted.org/packages/1e/57/a6a1721eff09598fb01f3c7cda070c1b6a0f12d63c83236edf79a440abcc/blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83", size = 23161, upload-time = "2024-05-06T17:04:10.101Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01", size = 9456 }, + { url = "https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01", size = 9456, upload-time = "2024-05-06T17:04:08.444Z" }, ] [[package]] @@ -71,9 +72,9 @@ dependencies = [ { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/82/8c/2ca661db6c9e591d9dc46149b43a91385283c852436ccba62e199643e196/boto3-1.37.37.tar.gz", hash = "sha256:752d31105a45e3e01c8c68471db14ae439990b75a35e72b591ca528e2575b28f", size = 111666 } +sdist = { url = "https://files.pythonhosted.org/packages/82/8c/2ca661db6c9e591d9dc46149b43a91385283c852436ccba62e199643e196/boto3-1.37.37.tar.gz", hash = "sha256:752d31105a45e3e01c8c68471db14ae439990b75a35e72b591ca528e2575b28f", size = 111666, upload-time = "2025-04-18T19:21:46.741Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/5f/032d93e74949222ffbfbc3270f29a3ee423fe648de8a31c49cce0cbb0a09/boto3-1.37.37-py3-none-any.whl", hash = "sha256:d125cb11e22817f7a2581bade4bf7b75247b401888890239ceb5d3e902ccaf38", size = 139917 }, + { url = "https://files.pythonhosted.org/packages/e4/5f/032d93e74949222ffbfbc3270f29a3ee423fe648de8a31c49cce0cbb0a09/boto3-1.37.37-py3-none-any.whl", hash = "sha256:d125cb11e22817f7a2581bade4bf7b75247b401888890239ceb5d3e902ccaf38", size = 139917, upload-time = "2025-04-18T19:21:43.769Z" }, ] [[package]] @@ -86,111 +87,111 @@ dependencies = [ { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "urllib3", version = "2.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/d0/70969515e3ae8ff0fcccf22827d5d131bc7b8729331127415cf8f2861d63/botocore-1.37.37.tar.gz", hash = "sha256:3eadde6fed95c4cb469cc39d1c3558528b7fa76d23e7e16d4bddc77250431a64", size = 13828530 } +sdist = { url = "https://files.pythonhosted.org/packages/96/d0/70969515e3ae8ff0fcccf22827d5d131bc7b8729331127415cf8f2861d63/botocore-1.37.37.tar.gz", hash = "sha256:3eadde6fed95c4cb469cc39d1c3558528b7fa76d23e7e16d4bddc77250431a64", size = 13828530, upload-time = "2025-04-18T19:21:32.145Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/17/602915b29cb695e1e66f65e33b1026f1534e49975d99ea4e32e58d963542/botocore-1.37.37-py3-none-any.whl", hash = "sha256:eb730ff978f47c02f0c8ed07bccdc0db6d8fa098ed32ac31bee1da0e9be480d1", size = 13495584 }, + { url = "https://files.pythonhosted.org/packages/fe/17/602915b29cb695e1e66f65e33b1026f1534e49975d99ea4e32e58d963542/botocore-1.37.37-py3-none-any.whl", hash = "sha256:eb730ff978f47c02f0c8ed07bccdc0db6d8fa098ed32ac31bee1da0e9be480d1", size = 13495584, upload-time = "2025-04-18T19:21:26.45Z" }, ] [[package]] name = "cachetools" version = "5.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380 } +sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080 }, + { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, ] [[package]] name = "certifi" version = "2024.8.30" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } +sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507, upload-time = "2024-08-30T01:55:04.365Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, + { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321, upload-time = "2024-08-30T01:55:02.591Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620, upload-time = "2024-10-09T07:40:20.413Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/8b/825cc84cf13a28bfbcba7c416ec22bf85a9584971be15b21dd8300c65b7f/charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", size = 196363 }, - { url = "https://files.pythonhosted.org/packages/23/81/d7eef6a99e42c77f444fdd7bc894b0ceca6c3a95c51239e74a722039521c/charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", size = 125639 }, - { url = "https://files.pythonhosted.org/packages/21/67/b4564d81f48042f520c948abac7079356e94b30cb8ffb22e747532cf469d/charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", size = 120451 }, - { url = "https://files.pythonhosted.org/packages/c2/72/12a7f0943dd71fb5b4e7b55c41327ac0a1663046a868ee4d0d8e9c369b85/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", size = 140041 }, - { url = "https://files.pythonhosted.org/packages/67/56/fa28c2c3e31217c4c52158537a2cf5d98a6c1e89d31faf476c89391cd16b/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", size = 150333 }, - { url = "https://files.pythonhosted.org/packages/f9/d2/466a9be1f32d89eb1554cf84073a5ed9262047acee1ab39cbaefc19635d2/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", size = 142921 }, - { url = "https://files.pythonhosted.org/packages/f8/01/344ec40cf5d85c1da3c1f57566c59e0c9b56bcc5566c08804a95a6cc8257/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", size = 144785 }, - { url = "https://files.pythonhosted.org/packages/73/8b/2102692cb6d7e9f03b9a33a710e0164cadfce312872e3efc7cfe22ed26b4/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", size = 146631 }, - { url = "https://files.pythonhosted.org/packages/d8/96/cc2c1b5d994119ce9f088a9a0c3ebd489d360a2eb058e2c8049f27092847/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", size = 140867 }, - { url = "https://files.pythonhosted.org/packages/c9/27/cde291783715b8ec30a61c810d0120411844bc4c23b50189b81188b273db/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", size = 149273 }, - { url = "https://files.pythonhosted.org/packages/3a/a4/8633b0fc1a2d1834d5393dafecce4a1cc56727bfd82b4dc18fc92f0d3cc3/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", size = 152437 }, - { url = "https://files.pythonhosted.org/packages/64/ea/69af161062166b5975ccbb0961fd2384853190c70786f288684490913bf5/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", size = 150087 }, - { url = "https://files.pythonhosted.org/packages/3b/fd/e60a9d9fd967f4ad5a92810138192f825d77b4fa2a557990fd575a47695b/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", size = 145142 }, - { url = "https://files.pythonhosted.org/packages/6d/02/8cb0988a1e49ac9ce2eed1e07b77ff118f2923e9ebd0ede41ba85f2dcb04/charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", size = 94701 }, - { url = "https://files.pythonhosted.org/packages/d6/20/f1d4670a8a723c46be695dff449d86d6092916f9e99c53051954ee33a1bc/charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", size = 102191 }, - { url = "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", size = 193339 }, - { url = "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", size = 124366 }, - { url = "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", size = 118874 }, - { url = "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", size = 138243 }, - { url = "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", size = 148676 }, - { url = "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", size = 141289 }, - { url = "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", size = 142585 }, - { url = "https://files.pythonhosted.org/packages/3b/a0/a68980ab8a1f45a36d9745d35049c1af57d27255eff8c907e3add84cf68f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", size = 144408 }, - { url = "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", size = 139076 }, - { url = "https://files.pythonhosted.org/packages/fb/9d/9c13753a5a6e0db4a0a6edb1cef7aee39859177b64e1a1e748a6e3ba62c2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", size = 146874 }, - { url = "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", size = 150871 }, - { url = "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", size = 148546 }, - { url = "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", size = 143048 }, - { url = "https://files.pythonhosted.org/packages/01/f8/38842422988b795220eb8038745d27a675ce066e2ada79516c118f291f07/charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", size = 94389 }, - { url = "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", size = 101752 }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, - { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, - { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, - { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, - { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, - { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, - { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, - { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, - { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, - { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, - { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, - { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, - { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, - { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, - { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, - { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, - { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, - { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, - { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, - { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, - { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, - { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, - { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, - { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, - { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, - { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, - { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, - { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, - { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, - { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, - { url = "https://files.pythonhosted.org/packages/54/2f/28659eee7f5d003e0f5a3b572765bf76d6e0fe6601ab1f1b1dd4cba7e4f1/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", size = 196326 }, - { url = "https://files.pythonhosted.org/packages/d1/18/92869d5c0057baa973a3ee2af71573be7b084b3c3d428fe6463ce71167f8/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", size = 125614 }, - { url = "https://files.pythonhosted.org/packages/d6/27/327904c5a54a7796bb9f36810ec4173d2df5d88b401d2b95ef53111d214e/charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", size = 120450 }, - { url = "https://files.pythonhosted.org/packages/a4/23/65af317914a0308495133b2d654cf67b11bbd6ca16637c4e8a38f80a5a69/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", size = 140135 }, - { url = "https://files.pythonhosted.org/packages/f2/41/6190102ad521a8aa888519bb014a74251ac4586cde9b38e790901684f9ab/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", size = 150413 }, - { url = "https://files.pythonhosted.org/packages/7b/ab/f47b0159a69eab9bd915591106859f49670c75f9a19082505ff16f50efc0/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", size = 142992 }, - { url = "https://files.pythonhosted.org/packages/28/89/60f51ad71f63aaaa7e51a2a2ad37919985a341a1d267070f212cdf6c2d22/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", size = 144871 }, - { url = "https://files.pythonhosted.org/packages/0c/48/0050550275fea585a6e24460b42465020b53375017d8596c96be57bfabca/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", size = 146756 }, - { url = "https://files.pythonhosted.org/packages/dc/b5/47f8ee91455946f745e6c9ddbb0f8f50314d2416dd922b213e7d5551ad09/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", size = 141034 }, - { url = "https://files.pythonhosted.org/packages/84/79/5c731059ebab43e80bf61fa51666b9b18167974b82004f18c76378ed31a3/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", size = 149434 }, - { url = "https://files.pythonhosted.org/packages/ca/f3/0719cd09fc4dc42066f239cb3c48ced17fc3316afca3e2a30a4756fe49ab/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", size = 152443 }, - { url = "https://files.pythonhosted.org/packages/f7/0e/c6357297f1157c8e8227ff337e93fd0a90e498e3d6ab96b2782204ecae48/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", size = 150294 }, - { url = "https://files.pythonhosted.org/packages/54/9a/acfa96dc4ea8c928040b15822b59d0863d6e1757fba8bd7de3dc4f761c13/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", size = 145314 }, - { url = "https://files.pythonhosted.org/packages/73/1c/b10a63032eaebb8d7bcb8544f12f063f41f5f463778ac61da15d9985e8b6/charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", size = 94724 }, - { url = "https://files.pythonhosted.org/packages/c5/77/3a78bf28bfaa0863f9cfef278dbeadf55efe064eafff8c7c424ae3c4c1bf/charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", size = 102159 }, - { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, + { url = "https://files.pythonhosted.org/packages/69/8b/825cc84cf13a28bfbcba7c416ec22bf85a9584971be15b21dd8300c65b7f/charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", size = 196363, upload-time = "2024-10-09T07:38:02.622Z" }, + { url = "https://files.pythonhosted.org/packages/23/81/d7eef6a99e42c77f444fdd7bc894b0ceca6c3a95c51239e74a722039521c/charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", size = 125639, upload-time = "2024-10-09T07:38:04.044Z" }, + { url = "https://files.pythonhosted.org/packages/21/67/b4564d81f48042f520c948abac7079356e94b30cb8ffb22e747532cf469d/charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", size = 120451, upload-time = "2024-10-09T07:38:04.997Z" }, + { url = "https://files.pythonhosted.org/packages/c2/72/12a7f0943dd71fb5b4e7b55c41327ac0a1663046a868ee4d0d8e9c369b85/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", size = 140041, upload-time = "2024-10-09T07:38:06.676Z" }, + { url = "https://files.pythonhosted.org/packages/67/56/fa28c2c3e31217c4c52158537a2cf5d98a6c1e89d31faf476c89391cd16b/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", size = 150333, upload-time = "2024-10-09T07:38:08.626Z" }, + { url = "https://files.pythonhosted.org/packages/f9/d2/466a9be1f32d89eb1554cf84073a5ed9262047acee1ab39cbaefc19635d2/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", size = 142921, upload-time = "2024-10-09T07:38:10.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/01/344ec40cf5d85c1da3c1f57566c59e0c9b56bcc5566c08804a95a6cc8257/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", size = 144785, upload-time = "2024-10-09T07:38:12.019Z" }, + { url = "https://files.pythonhosted.org/packages/73/8b/2102692cb6d7e9f03b9a33a710e0164cadfce312872e3efc7cfe22ed26b4/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", size = 146631, upload-time = "2024-10-09T07:38:13.701Z" }, + { url = "https://files.pythonhosted.org/packages/d8/96/cc2c1b5d994119ce9f088a9a0c3ebd489d360a2eb058e2c8049f27092847/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", size = 140867, upload-time = "2024-10-09T07:38:15.403Z" }, + { url = "https://files.pythonhosted.org/packages/c9/27/cde291783715b8ec30a61c810d0120411844bc4c23b50189b81188b273db/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", size = 149273, upload-time = "2024-10-09T07:38:16.433Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a4/8633b0fc1a2d1834d5393dafecce4a1cc56727bfd82b4dc18fc92f0d3cc3/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", size = 152437, upload-time = "2024-10-09T07:38:18.013Z" }, + { url = "https://files.pythonhosted.org/packages/64/ea/69af161062166b5975ccbb0961fd2384853190c70786f288684490913bf5/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", size = 150087, upload-time = "2024-10-09T07:38:19.089Z" }, + { url = "https://files.pythonhosted.org/packages/3b/fd/e60a9d9fd967f4ad5a92810138192f825d77b4fa2a557990fd575a47695b/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", size = 145142, upload-time = "2024-10-09T07:38:20.78Z" }, + { url = "https://files.pythonhosted.org/packages/6d/02/8cb0988a1e49ac9ce2eed1e07b77ff118f2923e9ebd0ede41ba85f2dcb04/charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", size = 94701, upload-time = "2024-10-09T07:38:21.851Z" }, + { url = "https://files.pythonhosted.org/packages/d6/20/f1d4670a8a723c46be695dff449d86d6092916f9e99c53051954ee33a1bc/charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", size = 102191, upload-time = "2024-10-09T07:38:23.467Z" }, + { url = "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", size = 193339, upload-time = "2024-10-09T07:38:24.527Z" }, + { url = "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", size = 124366, upload-time = "2024-10-09T07:38:26.488Z" }, + { url = "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", size = 118874, upload-time = "2024-10-09T07:38:28.115Z" }, + { url = "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", size = 138243, upload-time = "2024-10-09T07:38:29.822Z" }, + { url = "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", size = 148676, upload-time = "2024-10-09T07:38:30.869Z" }, + { url = "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", size = 141289, upload-time = "2024-10-09T07:38:32.557Z" }, + { url = "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", size = 142585, upload-time = "2024-10-09T07:38:33.649Z" }, + { url = "https://files.pythonhosted.org/packages/3b/a0/a68980ab8a1f45a36d9745d35049c1af57d27255eff8c907e3add84cf68f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", size = 144408, upload-time = "2024-10-09T07:38:34.687Z" }, + { url = "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", size = 139076, upload-time = "2024-10-09T07:38:36.417Z" }, + { url = "https://files.pythonhosted.org/packages/fb/9d/9c13753a5a6e0db4a0a6edb1cef7aee39859177b64e1a1e748a6e3ba62c2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", size = 146874, upload-time = "2024-10-09T07:38:37.59Z" }, + { url = "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", size = 150871, upload-time = "2024-10-09T07:38:38.666Z" }, + { url = "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", size = 148546, upload-time = "2024-10-09T07:38:40.459Z" }, + { url = "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", size = 143048, upload-time = "2024-10-09T07:38:42.178Z" }, + { url = "https://files.pythonhosted.org/packages/01/f8/38842422988b795220eb8038745d27a675ce066e2ada79516c118f291f07/charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", size = 94389, upload-time = "2024-10-09T07:38:43.339Z" }, + { url = "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", size = 101752, upload-time = "2024-10-09T07:38:44.276Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445, upload-time = "2024-10-09T07:38:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275, upload-time = "2024-10-09T07:38:46.449Z" }, + { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020, upload-time = "2024-10-09T07:38:48.88Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128, upload-time = "2024-10-09T07:38:49.86Z" }, + { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277, upload-time = "2024-10-09T07:38:52.306Z" }, + { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174, upload-time = "2024-10-09T07:38:53.458Z" }, + { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838, upload-time = "2024-10-09T07:38:54.691Z" }, + { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149, upload-time = "2024-10-09T07:38:55.737Z" }, + { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043, upload-time = "2024-10-09T07:38:57.44Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229, upload-time = "2024-10-09T07:38:58.782Z" }, + { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556, upload-time = "2024-10-09T07:39:00.467Z" }, + { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772, upload-time = "2024-10-09T07:39:01.5Z" }, + { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800, upload-time = "2024-10-09T07:39:02.491Z" }, + { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836, upload-time = "2024-10-09T07:39:04.607Z" }, + { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187, upload-time = "2024-10-09T07:39:06.247Z" }, + { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617, upload-time = "2024-10-09T07:39:07.317Z" }, + { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310, upload-time = "2024-10-09T07:39:08.353Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126, upload-time = "2024-10-09T07:39:09.327Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342, upload-time = "2024-10-09T07:39:10.322Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383, upload-time = "2024-10-09T07:39:12.042Z" }, + { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214, upload-time = "2024-10-09T07:39:13.059Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104, upload-time = "2024-10-09T07:39:14.815Z" }, + { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255, upload-time = "2024-10-09T07:39:15.868Z" }, + { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251, upload-time = "2024-10-09T07:39:16.995Z" }, + { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474, upload-time = "2024-10-09T07:39:18.021Z" }, + { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849, upload-time = "2024-10-09T07:39:19.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781, upload-time = "2024-10-09T07:39:20.397Z" }, + { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970, upload-time = "2024-10-09T07:39:21.452Z" }, + { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973, upload-time = "2024-10-09T07:39:22.509Z" }, + { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308, upload-time = "2024-10-09T07:39:23.524Z" }, + { url = "https://files.pythonhosted.org/packages/54/2f/28659eee7f5d003e0f5a3b572765bf76d6e0fe6601ab1f1b1dd4cba7e4f1/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", size = 196326, upload-time = "2024-10-09T07:39:59.619Z" }, + { url = "https://files.pythonhosted.org/packages/d1/18/92869d5c0057baa973a3ee2af71573be7b084b3c3d428fe6463ce71167f8/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", size = 125614, upload-time = "2024-10-09T07:40:00.776Z" }, + { url = "https://files.pythonhosted.org/packages/d6/27/327904c5a54a7796bb9f36810ec4173d2df5d88b401d2b95ef53111d214e/charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", size = 120450, upload-time = "2024-10-09T07:40:02.621Z" }, + { url = "https://files.pythonhosted.org/packages/a4/23/65af317914a0308495133b2d654cf67b11bbd6ca16637c4e8a38f80a5a69/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", size = 140135, upload-time = "2024-10-09T07:40:05.719Z" }, + { url = "https://files.pythonhosted.org/packages/f2/41/6190102ad521a8aa888519bb014a74251ac4586cde9b38e790901684f9ab/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", size = 150413, upload-time = "2024-10-09T07:40:06.777Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ab/f47b0159a69eab9bd915591106859f49670c75f9a19082505ff16f50efc0/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", size = 142992, upload-time = "2024-10-09T07:40:07.921Z" }, + { url = "https://files.pythonhosted.org/packages/28/89/60f51ad71f63aaaa7e51a2a2ad37919985a341a1d267070f212cdf6c2d22/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", size = 144871, upload-time = "2024-10-09T07:40:09.035Z" }, + { url = "https://files.pythonhosted.org/packages/0c/48/0050550275fea585a6e24460b42465020b53375017d8596c96be57bfabca/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", size = 146756, upload-time = "2024-10-09T07:40:10.186Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b5/47f8ee91455946f745e6c9ddbb0f8f50314d2416dd922b213e7d5551ad09/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", size = 141034, upload-time = "2024-10-09T07:40:11.386Z" }, + { url = "https://files.pythonhosted.org/packages/84/79/5c731059ebab43e80bf61fa51666b9b18167974b82004f18c76378ed31a3/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", size = 149434, upload-time = "2024-10-09T07:40:12.513Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f3/0719cd09fc4dc42066f239cb3c48ced17fc3316afca3e2a30a4756fe49ab/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", size = 152443, upload-time = "2024-10-09T07:40:13.655Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0e/c6357297f1157c8e8227ff337e93fd0a90e498e3d6ab96b2782204ecae48/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", size = 150294, upload-time = "2024-10-09T07:40:14.883Z" }, + { url = "https://files.pythonhosted.org/packages/54/9a/acfa96dc4ea8c928040b15822b59d0863d6e1757fba8bd7de3dc4f761c13/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", size = 145314, upload-time = "2024-10-09T07:40:16.043Z" }, + { url = "https://files.pythonhosted.org/packages/73/1c/b10a63032eaebb8d7bcb8544f12f063f41f5f463778ac61da15d9985e8b6/charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", size = 94724, upload-time = "2024-10-09T07:40:17.199Z" }, + { url = "https://files.pythonhosted.org/packages/c5/77/3a78bf28bfaa0863f9cfef278dbeadf55efe064eafff8c7c424ae3c4c1bf/charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", size = 102159, upload-time = "2024-10-09T07:40:18.264Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446, upload-time = "2024-10-09T07:40:19.383Z" }, ] [[package]] @@ -198,38 +199,38 @@ name = "click" version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] name = "distro" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] [[package]] name = "exceptiongroup" version = "1.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883, upload-time = "2024-07-12T22:26:00.161Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, + { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453, upload-time = "2024-07-12T22:25:58.476Z" }, ] [[package]] @@ -244,9 +245,9 @@ dependencies = [ { name = "jinja2" }, { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/e1/d104c83026f8d35dfd2c261df7d64738341067526406b40190bc063e829a/flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842", size = 676315 } +sdist = { url = "https://files.pythonhosted.org/packages/41/e1/d104c83026f8d35dfd2c261df7d64738341067526406b40190bc063e829a/flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842", size = 676315, upload-time = "2024-04-07T19:26:11.035Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3", size = 101735 }, + { url = "https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3", size = 101735, upload-time = "2024-04-07T19:26:08.569Z" }, ] [[package]] @@ -256,9 +257,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "flask" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/21/0160aa217c4df74e44a04919213f9c8af7e68551c10267b055f1e09d421c/Flask-HTTPAuth-4.8.0.tar.gz", hash = "sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a", size = 230314 } +sdist = { url = "https://files.pythonhosted.org/packages/22/21/0160aa217c4df74e44a04919213f9c8af7e68551c10267b055f1e09d421c/Flask-HTTPAuth-4.8.0.tar.gz", hash = "sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a", size = 230314, upload-time = "2023-04-27T09:25:57.48Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/c4/e64ace124b927cd1f29270050ee0e0ef5faad75a512c5c8d733961dda9ca/Flask_HTTPAuth-4.8.0-py3-none-any.whl", hash = "sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0", size = 6958 }, + { url = "https://files.pythonhosted.org/packages/83/c4/e64ace124b927cd1f29270050ee0e0ef5faad75a512c5c8d733961dda9ca/Flask_HTTPAuth-4.8.0-py3-none-any.whl", hash = "sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0", size = 6958, upload-time = "2023-04-27T09:25:55.803Z" }, ] [[package]] @@ -270,9 +271,9 @@ dependencies = [ { name = "pyasn1-modules" }, { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/eb/d504ba1daf190af6b204a9d4714d457462b486043744901a6eeea711f913/google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4", size = 270866 } +sdist = { url = "https://files.pythonhosted.org/packages/c6/eb/d504ba1daf190af6b204a9d4714d457462b486043744901a6eeea711f913/google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4", size = 270866, upload-time = "2025-01-23T01:05:29.119Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/47/603554949a37bca5b7f894d51896a9c534b9eab808e2520a748e081669d0/google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a", size = 210770 }, + { url = "https://files.pythonhosted.org/packages/9d/47/603554949a37bca5b7f894d51896a9c534b9eab808e2520a748e081669d0/google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a", size = 210770, upload-time = "2025-01-23T01:05:26.572Z" }, ] [[package]] @@ -288,18 +289,18 @@ dependencies = [ { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/23/21/6f164fcb13293f520e016171be92611126d6bd2e9ceb246b32451c4ef51b/google_genai-1.5.0.tar.gz", hash = "sha256:83fcfc4956ad32ecea1fda37d8f3f7cbadbdeebd2310f2a55bc7564a2f1d459f", size = 135903 } +sdist = { url = "https://files.pythonhosted.org/packages/23/21/6f164fcb13293f520e016171be92611126d6bd2e9ceb246b32451c4ef51b/google_genai-1.5.0.tar.gz", hash = "sha256:83fcfc4956ad32ecea1fda37d8f3f7cbadbdeebd2310f2a55bc7564a2f1d459f", size = 135903, upload-time = "2025-03-07T00:34:53.186Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/2a/a55da0c959326a7cf3c13398fc93c8e2af624b054ef3fa85b4cb6d0e2c96/google_genai-1.5.0-py3-none-any.whl", hash = "sha256:0ad433836a402957a967ccd57cbab7768325d28966a8556771974ae1c018be59", size = 142404 }, + { url = "https://files.pythonhosted.org/packages/ec/2a/a55da0c959326a7cf3c13398fc93c8e2af624b054ef3fa85b4cb6d0e2c96/google_genai-1.5.0-py3-none-any.whl", hash = "sha256:0ad433836a402957a967ccd57cbab7768325d28966a8556771974ae1c018be59", size = 142404, upload-time = "2025-03-07T00:34:51.157Z" }, ] [[package]] name = "h11" version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } +sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418, upload-time = "2022-09-25T15:40:01.519Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, + { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259, upload-time = "2022-09-25T15:39:59.68Z" }, ] [[package]] @@ -310,9 +311,9 @@ dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } +sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196, upload-time = "2024-11-15T12:30:47.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, + { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551, upload-time = "2024-11-15T12:30:45.782Z" }, ] [[package]] @@ -325,18 +326,18 @@ dependencies = [ { name = "httpcore" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] [[package]] name = "idna" version = "3.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, ] [[package]] @@ -346,27 +347,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp", marker = "python_full_version < '3.10'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304 } +sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304, upload-time = "2024-09-11T14:56:08.937Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514 }, + { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514, upload-time = "2024-09-11T14:56:07.019Z" }, ] [[package]] name = "iniconfig" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646, upload-time = "2023-01-07T11:08:11.254Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892, upload-time = "2023-01-07T11:08:09.864Z" }, ] [[package]] name = "itsdangerous" version = "2.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410 } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234 }, + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, ] [[package]] @@ -376,137 +377,137 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 } +sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674, upload-time = "2024-12-21T18:30:22.828Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, + { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596, upload-time = "2024-12-21T18:30:19.133Z" }, ] [[package]] name = "jiter" version = "0.8.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/70/90bc7bd3932e651486861df5c8ffea4ca7c77d28e8532ddefe2abc561a53/jiter-0.8.2.tar.gz", hash = "sha256:cd73d3e740666d0e639f678adb176fad25c1bcbdae88d8d7b857e1783bb4212d", size = 163007 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/70/90bc7bd3932e651486861df5c8ffea4ca7c77d28e8532ddefe2abc561a53/jiter-0.8.2.tar.gz", hash = "sha256:cd73d3e740666d0e639f678adb176fad25c1bcbdae88d8d7b857e1783bb4212d", size = 163007, upload-time = "2024-12-09T18:11:08.649Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/f3/8c11e0e87bd5934c414f9b1cfae3cbfd4a938d4669d57cb427e1c4d11a7f/jiter-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b", size = 303381 }, - { url = "https://files.pythonhosted.org/packages/ea/28/4cd3f0bcbf40e946bc6a62a82c951afc386a25673d3d8d5ee461f1559bbe/jiter-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393", size = 311718 }, - { url = "https://files.pythonhosted.org/packages/0d/17/57acab00507e60bd954eaec0837d9d7b119b4117ff49b8a62f2b646f32ed/jiter-0.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c826a221851a8dc028eb6d7d6429ba03184fa3c7e83ae01cd6d3bd1d4bd17d", size = 335465 }, - { url = "https://files.pythonhosted.org/packages/74/b9/1a3ddd2bc95ae17c815b021521020f40c60b32137730126bada962ef32b4/jiter-0.8.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d35c864c2dff13dfd79fb070fc4fc6235d7b9b359efe340e1261deb21b9fcb66", size = 355570 }, - { url = "https://files.pythonhosted.org/packages/78/69/6d29e2296a934199a7d0dde673ecccf98c9c8db44caf0248b3f2b65483cb/jiter-0.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f557c55bc2b7676e74d39d19bcb8775ca295c7a028246175d6a8b431e70835e5", size = 381383 }, - { url = "https://files.pythonhosted.org/packages/22/d7/fbc4c3fb1bf65f9be22a32759b539f88e897aeb13fe84ab0266e4423487a/jiter-0.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:580ccf358539153db147e40751a0b41688a5ceb275e6f3e93d91c9467f42b2e3", size = 390454 }, - { url = "https://files.pythonhosted.org/packages/4d/a0/3993cda2e267fe679b45d0bcc2cef0b4504b0aa810659cdae9737d6bace9/jiter-0.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af102d3372e917cffce49b521e4c32c497515119dc7bd8a75665e90a718bbf08", size = 345039 }, - { url = "https://files.pythonhosted.org/packages/b9/ef/69c18562b4c09ce88fab5df1dcaf643f6b1a8b970b65216e7221169b81c4/jiter-0.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cadcc978f82397d515bb2683fc0d50103acff2a180552654bb92d6045dec2c49", size = 376200 }, - { url = "https://files.pythonhosted.org/packages/4d/17/0b5a8de46a6ab4d836f70934036278b49b8530c292b29dde3483326d4555/jiter-0.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba5bdf56969cad2019d4e8ffd3f879b5fdc792624129741d3d83fc832fef8c7d", size = 511158 }, - { url = "https://files.pythonhosted.org/packages/6c/b2/c401a0a2554b36c9e6d6e4876b43790d75139cf3936f0222e675cbc23451/jiter-0.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3b94a33a241bee9e34b8481cdcaa3d5c2116f575e0226e421bed3f7a6ea71cff", size = 503956 }, - { url = "https://files.pythonhosted.org/packages/d4/02/a0291ed7d72c0ac130f172354ee3cf0b2556b69584de391463a8ee534f40/jiter-0.8.2-cp310-cp310-win32.whl", hash = "sha256:6e5337bf454abddd91bd048ce0dca5134056fc99ca0205258766db35d0a2ea43", size = 202846 }, - { url = "https://files.pythonhosted.org/packages/ad/20/8c988831ae4bf437e29f1671e198fc99ba8fe49f2895f23789acad1d1811/jiter-0.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:4a9220497ca0cb1fe94e3f334f65b9b5102a0b8147646118f020d8ce1de70105", size = 204414 }, - { url = "https://files.pythonhosted.org/packages/cb/b0/c1a7caa7f9dc5f1f6cfa08722867790fe2d3645d6e7170ca280e6e52d163/jiter-0.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2dd61c5afc88a4fda7d8b2cf03ae5947c6ac7516d32b7a15bf4b49569a5c076b", size = 303666 }, - { url = "https://files.pythonhosted.org/packages/f5/97/0468bc9eeae43079aaa5feb9267964e496bf13133d469cfdc135498f8dd0/jiter-0.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a6c710d657c8d1d2adbbb5c0b0c6bfcec28fd35bd6b5f016395f9ac43e878a15", size = 311934 }, - { url = "https://files.pythonhosted.org/packages/e5/69/64058e18263d9a5f1e10f90c436853616d5f047d997c37c7b2df11b085ec/jiter-0.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9584de0cd306072635fe4b89742bf26feae858a0683b399ad0c2509011b9dc0", size = 335506 }, - { url = "https://files.pythonhosted.org/packages/9d/14/b747f9a77b8c0542141d77ca1e2a7523e854754af2c339ac89a8b66527d6/jiter-0.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a90a923338531b7970abb063cfc087eebae6ef8ec8139762007188f6bc69a9f", size = 355849 }, - { url = "https://files.pythonhosted.org/packages/53/e2/98a08161db7cc9d0e39bc385415890928ff09709034982f48eccfca40733/jiter-0.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21974d246ed0181558087cd9f76e84e8321091ebfb3a93d4c341479a736f099", size = 381700 }, - { url = "https://files.pythonhosted.org/packages/7a/38/1674672954d35bce3b1c9af99d5849f9256ac8f5b672e020ac7821581206/jiter-0.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32475a42b2ea7b344069dc1e81445cfc00b9d0e3ca837f0523072432332e9f74", size = 389710 }, - { url = "https://files.pythonhosted.org/packages/f8/9b/92f9da9a9e107d019bcf883cd9125fa1690079f323f5a9d5c6986eeec3c0/jiter-0.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9931fd36ee513c26b5bf08c940b0ac875de175341cbdd4fa3be109f0492586", size = 345553 }, - { url = "https://files.pythonhosted.org/packages/44/a6/6d030003394e9659cd0d7136bbeabd82e869849ceccddc34d40abbbbb269/jiter-0.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0820f4a3a59ddced7fce696d86a096d5cc48d32a4183483a17671a61edfddc", size = 376388 }, - { url = "https://files.pythonhosted.org/packages/ad/8d/87b09e648e4aca5f9af89e3ab3cfb93db2d1e633b2f2931ede8dabd9b19a/jiter-0.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ffc86ae5e3e6a93765d49d1ab47b6075a9c978a2b3b80f0f32628f39caa0c88", size = 511226 }, - { url = "https://files.pythonhosted.org/packages/77/95/8008ebe4cdc82eac1c97864a8042ca7e383ed67e0ec17bfd03797045c727/jiter-0.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5127dc1abd809431172bc3fbe8168d6b90556a30bb10acd5ded41c3cfd6f43b6", size = 504134 }, - { url = "https://files.pythonhosted.org/packages/26/0d/3056a74de13e8b2562e4d526de6dac2f65d91ace63a8234deb9284a1d24d/jiter-0.8.2-cp311-cp311-win32.whl", hash = "sha256:66227a2c7b575720c1871c8800d3a0122bb8ee94edb43a5685aa9aceb2782d44", size = 203103 }, - { url = "https://files.pythonhosted.org/packages/4e/1e/7f96b798f356e531ffc0f53dd2f37185fac60fae4d6c612bbbd4639b90aa/jiter-0.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:cde031d8413842a1e7501e9129b8e676e62a657f8ec8166e18a70d94d4682855", size = 206717 }, - { url = "https://files.pythonhosted.org/packages/a1/17/c8747af8ea4e045f57d6cfd6fc180752cab9bc3de0e8a0c9ca4e8af333b1/jiter-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e6ec2be506e7d6f9527dae9ff4b7f54e68ea44a0ef6b098256ddf895218a2f8f", size = 302027 }, - { url = "https://files.pythonhosted.org/packages/3c/c1/6da849640cd35a41e91085723b76acc818d4b7d92b0b6e5111736ce1dd10/jiter-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76e324da7b5da060287c54f2fabd3db5f76468006c811831f051942bf68c9d44", size = 310326 }, - { url = "https://files.pythonhosted.org/packages/06/99/a2bf660d8ccffee9ad7ed46b4f860d2108a148d0ea36043fd16f4dc37e94/jiter-0.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:180a8aea058f7535d1c84183c0362c710f4750bef66630c05f40c93c2b152a0f", size = 334242 }, - { url = "https://files.pythonhosted.org/packages/a7/5f/cea1c17864828731f11427b9d1ab7f24764dbd9aaf4648a7f851164d2718/jiter-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025337859077b41548bdcbabe38698bcd93cfe10b06ff66617a48ff92c9aec60", size = 356654 }, - { url = "https://files.pythonhosted.org/packages/e9/13/62774b7e5e7f5d5043efe1d0f94ead66e6d0f894ae010adb56b3f788de71/jiter-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecff0dc14f409599bbcafa7e470c00b80f17abc14d1405d38ab02e4b42e55b57", size = 379967 }, - { url = "https://files.pythonhosted.org/packages/ec/fb/096b34c553bb0bd3f2289d5013dcad6074948b8d55212aa13a10d44c5326/jiter-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffd9fee7d0775ebaba131f7ca2e2d83839a62ad65e8e02fe2bd8fc975cedeb9e", size = 389252 }, - { url = "https://files.pythonhosted.org/packages/17/61/beea645c0bf398ced8b199e377b61eb999d8e46e053bb285c91c3d3eaab0/jiter-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14601dcac4889e0a1c75ccf6a0e4baf70dbc75041e51bcf8d0e9274519df6887", size = 345490 }, - { url = "https://files.pythonhosted.org/packages/d5/df/834aa17ad5dcc3cf0118821da0a0cf1589ea7db9832589278553640366bc/jiter-0.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92249669925bc1c54fcd2ec73f70f2c1d6a817928480ee1c65af5f6b81cdf12d", size = 376991 }, - { url = "https://files.pythonhosted.org/packages/67/80/87d140399d382fb4ea5b3d56e7ecaa4efdca17cd7411ff904c1517855314/jiter-0.8.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e725edd0929fa79f8349ab4ec7f81c714df51dc4e991539a578e5018fa4a7152", size = 510822 }, - { url = "https://files.pythonhosted.org/packages/5c/37/3394bb47bac1ad2cb0465601f86828a0518d07828a650722e55268cdb7e6/jiter-0.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bf55846c7b7a680eebaf9c3c48d630e1bf51bdf76c68a5f654b8524335b0ad29", size = 503730 }, - { url = "https://files.pythonhosted.org/packages/f9/e2/253fc1fa59103bb4e3aa0665d6ceb1818df1cd7bf3eb492c4dad229b1cd4/jiter-0.8.2-cp312-cp312-win32.whl", hash = "sha256:7efe4853ecd3d6110301665a5178b9856be7e2a9485f49d91aa4d737ad2ae49e", size = 203375 }, - { url = "https://files.pythonhosted.org/packages/41/69/6d4bbe66b3b3b4507e47aa1dd5d075919ad242b4b1115b3f80eecd443687/jiter-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:83c0efd80b29695058d0fd2fa8a556490dbce9804eac3e281f373bbc99045f6c", size = 204740 }, - { url = "https://files.pythonhosted.org/packages/6c/b0/bfa1f6f2c956b948802ef5a021281978bf53b7a6ca54bb126fd88a5d014e/jiter-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ca1f08b8e43dc3bd0594c992fb1fd2f7ce87f7bf0d44358198d6da8034afdf84", size = 301190 }, - { url = "https://files.pythonhosted.org/packages/a4/8f/396ddb4e292b5ea57e45ade5dc48229556b9044bad29a3b4b2dddeaedd52/jiter-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5672a86d55416ccd214c778efccf3266b84f87b89063b582167d803246354be4", size = 309334 }, - { url = "https://files.pythonhosted.org/packages/7f/68/805978f2f446fa6362ba0cc2e4489b945695940656edd844e110a61c98f8/jiter-0.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58dc9bc9767a1101f4e5e22db1b652161a225874d66f0e5cb8e2c7d1c438b587", size = 333918 }, - { url = "https://files.pythonhosted.org/packages/b3/99/0f71f7be667c33403fa9706e5b50583ae5106d96fab997fa7e2f38ee8347/jiter-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b2998606d6dadbb5ccda959a33d6a5e853252d921fec1792fc902351bb4e2c", size = 356057 }, - { url = "https://files.pythonhosted.org/packages/8d/50/a82796e421a22b699ee4d2ce527e5bcb29471a2351cbdc931819d941a167/jiter-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab9a87f3784eb0e098f84a32670cfe4a79cb6512fd8f42ae3d0709f06405d18", size = 379790 }, - { url = "https://files.pythonhosted.org/packages/3c/31/10fb012b00f6d83342ca9e2c9618869ab449f1aa78c8f1b2193a6b49647c/jiter-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79aec8172b9e3c6d05fd4b219d5de1ac616bd8da934107325a6c0d0e866a21b6", size = 388285 }, - { url = "https://files.pythonhosted.org/packages/c8/81/f15ebf7de57be488aa22944bf4274962aca8092e4f7817f92ffa50d3ee46/jiter-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:711e408732d4e9a0208008e5892c2966b485c783cd2d9a681f3eb147cf36c7ef", size = 344764 }, - { url = "https://files.pythonhosted.org/packages/b3/e8/0cae550d72b48829ba653eb348cdc25f3f06f8a62363723702ec18e7be9c/jiter-0.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:653cf462db4e8c41995e33d865965e79641ef45369d8a11f54cd30888b7e6ff1", size = 376620 }, - { url = "https://files.pythonhosted.org/packages/b8/50/e5478ff9d82534a944c03b63bc217c5f37019d4a34d288db0f079b13c10b/jiter-0.8.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:9c63eaef32b7bebac8ebebf4dabebdbc6769a09c127294db6babee38e9f405b9", size = 510402 }, - { url = "https://files.pythonhosted.org/packages/8e/1e/3de48bbebbc8f7025bd454cedc8c62378c0e32dd483dece5f4a814a5cb55/jiter-0.8.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:eb21aaa9a200d0a80dacc7a81038d2e476ffe473ffdd9c91eb745d623561de05", size = 503018 }, - { url = "https://files.pythonhosted.org/packages/d5/cd/d5a5501d72a11fe3e5fd65c78c884e5164eefe80077680533919be22d3a3/jiter-0.8.2-cp313-cp313-win32.whl", hash = "sha256:789361ed945d8d42850f919342a8665d2dc79e7e44ca1c97cc786966a21f627a", size = 203190 }, - { url = "https://files.pythonhosted.org/packages/51/bf/e5ca301245ba951447e3ad677a02a64a8845b185de2603dabd83e1e4b9c6/jiter-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ab7f43235d71e03b941c1630f4b6e3055d46b6cb8728a17663eaac9d8e83a865", size = 203551 }, - { url = "https://files.pythonhosted.org/packages/2f/3c/71a491952c37b87d127790dd7a0b1ebea0514c6b6ad30085b16bbe00aee6/jiter-0.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b426f72cd77da3fec300ed3bc990895e2dd6b49e3bfe6c438592a3ba660e41ca", size = 308347 }, - { url = "https://files.pythonhosted.org/packages/a0/4c/c02408042e6a7605ec063daed138e07b982fdb98467deaaf1c90950cf2c6/jiter-0.8.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2dd880785088ff2ad21ffee205e58a8c1ddabc63612444ae41e5e4b321b39c0", size = 342875 }, - { url = "https://files.pythonhosted.org/packages/91/61/c80ef80ed8a0a21158e289ef70dac01e351d929a1c30cb0f49be60772547/jiter-0.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:3ac9f578c46f22405ff7f8b1f5848fb753cc4b8377fbec8470a7dc3997ca7566", size = 202374 }, - { url = "https://files.pythonhosted.org/packages/c9/b2/ed7fbabd21c3cf556d6ea849cee35c74f13a509e668baad8323091e2867e/jiter-0.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e41e75344acef3fc59ba4765df29f107f309ca9e8eace5baacabd9217e52a5ee", size = 304502 }, - { url = "https://files.pythonhosted.org/packages/75/6e/1386857ac9165c1e9c71031566e7884d8a4f63724ce29ad1ace5bfe1351c/jiter-0.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f22b16b35d5c1df9dfd58843ab2cd25e6bf15191f5a236bed177afade507bfc", size = 300982 }, - { url = "https://files.pythonhosted.org/packages/56/4c/b413977c20bbb359b4d6c91d04f7f36fc525af0b7778119815477fc97242/jiter-0.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7200b8f7619d36aa51c803fd52020a2dfbea36ffec1b5e22cab11fd34d95a6d", size = 335344 }, - { url = "https://files.pythonhosted.org/packages/b0/59/51b080519938192edd33b4e8d48adb7e9bf9e0d699ec8b91119b9269fc75/jiter-0.8.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70bf4c43652cc294040dbb62256c83c8718370c8b93dd93d934b9a7bf6c4f53c", size = 356298 }, - { url = "https://files.pythonhosted.org/packages/72/bb/828db5ea406916d7b2232be31393f782b0f71bcb0b128750c4a028157565/jiter-0.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9d471356dc16f84ed48768b8ee79f29514295c7295cb41e1133ec0b2b8d637d", size = 381703 }, - { url = "https://files.pythonhosted.org/packages/c0/88/45d33a8728733e161e9783c54d8ecca0fc4c1aa74b1cebea1d97917eddc3/jiter-0.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:859e8eb3507894093d01929e12e267f83b1d5f6221099d3ec976f0c995cb6bd9", size = 391281 }, - { url = "https://files.pythonhosted.org/packages/45/3e/142712e0f45c28ad8a678dc8732a78294ce5a36fc694141f772bb827a8f2/jiter-0.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa58399c01db555346647a907b4ef6d4f584b123943be6ed5588c3f2359c9f4", size = 345553 }, - { url = "https://files.pythonhosted.org/packages/36/42/9b463b59fd22687b6da1afcad6c9adc870464a808208651de73f1dbeda09/jiter-0.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8f2d5ed877f089862f4c7aacf3a542627c1496f972a34d0474ce85ee7d939c27", size = 377063 }, - { url = "https://files.pythonhosted.org/packages/83/b3/44b1f5cd2e4eb15757eec341b25399da4c90515bb881ef6636b50a8c08a5/jiter-0.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:03c9df035d4f8d647f8c210ddc2ae0728387275340668fb30d2421e17d9a0841", size = 512543 }, - { url = "https://files.pythonhosted.org/packages/46/4e/c695c803aa2b668c057b2dea1cdd7a884d1a819ce610cec0be9666210bfd/jiter-0.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8bd2a824d08d8977bb2794ea2682f898ad3d8837932e3a74937e93d62ecbb637", size = 505141 }, - { url = "https://files.pythonhosted.org/packages/8e/51/e805b837db056f872db0b7a7a3610b7d764392be696dbe47afa0bea05bf2/jiter-0.8.2-cp39-cp39-win32.whl", hash = "sha256:ca29b6371ebc40e496995c94b988a101b9fbbed48a51190a4461fcb0a68b4a36", size = 203529 }, - { url = "https://files.pythonhosted.org/packages/32/b7/a3cde72c644fd1caf9da07fb38cf2c130f43484d8f91011940b7c4f42c8f/jiter-0.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:1c0dfbd1be3cbefc7510102370d86e35d1d53e5a93d48519688b1bf0f761160a", size = 207527 }, + { url = "https://files.pythonhosted.org/packages/f2/f3/8c11e0e87bd5934c414f9b1cfae3cbfd4a938d4669d57cb427e1c4d11a7f/jiter-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b", size = 303381, upload-time = "2024-12-09T18:09:00.301Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/4cd3f0bcbf40e946bc6a62a82c951afc386a25673d3d8d5ee461f1559bbe/jiter-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393", size = 311718, upload-time = "2024-12-09T18:09:02.53Z" }, + { url = "https://files.pythonhosted.org/packages/0d/17/57acab00507e60bd954eaec0837d9d7b119b4117ff49b8a62f2b646f32ed/jiter-0.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c826a221851a8dc028eb6d7d6429ba03184fa3c7e83ae01cd6d3bd1d4bd17d", size = 335465, upload-time = "2024-12-09T18:09:04.044Z" }, + { url = "https://files.pythonhosted.org/packages/74/b9/1a3ddd2bc95ae17c815b021521020f40c60b32137730126bada962ef32b4/jiter-0.8.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d35c864c2dff13dfd79fb070fc4fc6235d7b9b359efe340e1261deb21b9fcb66", size = 355570, upload-time = "2024-12-09T18:09:05.445Z" }, + { url = "https://files.pythonhosted.org/packages/78/69/6d29e2296a934199a7d0dde673ecccf98c9c8db44caf0248b3f2b65483cb/jiter-0.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f557c55bc2b7676e74d39d19bcb8775ca295c7a028246175d6a8b431e70835e5", size = 381383, upload-time = "2024-12-09T18:09:07.499Z" }, + { url = "https://files.pythonhosted.org/packages/22/d7/fbc4c3fb1bf65f9be22a32759b539f88e897aeb13fe84ab0266e4423487a/jiter-0.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:580ccf358539153db147e40751a0b41688a5ceb275e6f3e93d91c9467f42b2e3", size = 390454, upload-time = "2024-12-09T18:09:09.587Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a0/3993cda2e267fe679b45d0bcc2cef0b4504b0aa810659cdae9737d6bace9/jiter-0.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af102d3372e917cffce49b521e4c32c497515119dc7bd8a75665e90a718bbf08", size = 345039, upload-time = "2024-12-09T18:09:11.045Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ef/69c18562b4c09ce88fab5df1dcaf643f6b1a8b970b65216e7221169b81c4/jiter-0.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cadcc978f82397d515bb2683fc0d50103acff2a180552654bb92d6045dec2c49", size = 376200, upload-time = "2024-12-09T18:09:13.104Z" }, + { url = "https://files.pythonhosted.org/packages/4d/17/0b5a8de46a6ab4d836f70934036278b49b8530c292b29dde3483326d4555/jiter-0.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba5bdf56969cad2019d4e8ffd3f879b5fdc792624129741d3d83fc832fef8c7d", size = 511158, upload-time = "2024-12-09T18:09:15.222Z" }, + { url = "https://files.pythonhosted.org/packages/6c/b2/c401a0a2554b36c9e6d6e4876b43790d75139cf3936f0222e675cbc23451/jiter-0.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3b94a33a241bee9e34b8481cdcaa3d5c2116f575e0226e421bed3f7a6ea71cff", size = 503956, upload-time = "2024-12-09T18:09:16.595Z" }, + { url = "https://files.pythonhosted.org/packages/d4/02/a0291ed7d72c0ac130f172354ee3cf0b2556b69584de391463a8ee534f40/jiter-0.8.2-cp310-cp310-win32.whl", hash = "sha256:6e5337bf454abddd91bd048ce0dca5134056fc99ca0205258766db35d0a2ea43", size = 202846, upload-time = "2024-12-09T18:09:19.347Z" }, + { url = "https://files.pythonhosted.org/packages/ad/20/8c988831ae4bf437e29f1671e198fc99ba8fe49f2895f23789acad1d1811/jiter-0.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:4a9220497ca0cb1fe94e3f334f65b9b5102a0b8147646118f020d8ce1de70105", size = 204414, upload-time = "2024-12-09T18:09:20.904Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/c1a7caa7f9dc5f1f6cfa08722867790fe2d3645d6e7170ca280e6e52d163/jiter-0.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2dd61c5afc88a4fda7d8b2cf03ae5947c6ac7516d32b7a15bf4b49569a5c076b", size = 303666, upload-time = "2024-12-09T18:09:23.145Z" }, + { url = "https://files.pythonhosted.org/packages/f5/97/0468bc9eeae43079aaa5feb9267964e496bf13133d469cfdc135498f8dd0/jiter-0.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a6c710d657c8d1d2adbbb5c0b0c6bfcec28fd35bd6b5f016395f9ac43e878a15", size = 311934, upload-time = "2024-12-09T18:09:25.098Z" }, + { url = "https://files.pythonhosted.org/packages/e5/69/64058e18263d9a5f1e10f90c436853616d5f047d997c37c7b2df11b085ec/jiter-0.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9584de0cd306072635fe4b89742bf26feae858a0683b399ad0c2509011b9dc0", size = 335506, upload-time = "2024-12-09T18:09:26.407Z" }, + { url = "https://files.pythonhosted.org/packages/9d/14/b747f9a77b8c0542141d77ca1e2a7523e854754af2c339ac89a8b66527d6/jiter-0.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a90a923338531b7970abb063cfc087eebae6ef8ec8139762007188f6bc69a9f", size = 355849, upload-time = "2024-12-09T18:09:27.686Z" }, + { url = "https://files.pythonhosted.org/packages/53/e2/98a08161db7cc9d0e39bc385415890928ff09709034982f48eccfca40733/jiter-0.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21974d246ed0181558087cd9f76e84e8321091ebfb3a93d4c341479a736f099", size = 381700, upload-time = "2024-12-09T18:09:28.989Z" }, + { url = "https://files.pythonhosted.org/packages/7a/38/1674672954d35bce3b1c9af99d5849f9256ac8f5b672e020ac7821581206/jiter-0.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32475a42b2ea7b344069dc1e81445cfc00b9d0e3ca837f0523072432332e9f74", size = 389710, upload-time = "2024-12-09T18:09:30.565Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/92f9da9a9e107d019bcf883cd9125fa1690079f323f5a9d5c6986eeec3c0/jiter-0.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9931fd36ee513c26b5bf08c940b0ac875de175341cbdd4fa3be109f0492586", size = 345553, upload-time = "2024-12-09T18:09:32.735Z" }, + { url = "https://files.pythonhosted.org/packages/44/a6/6d030003394e9659cd0d7136bbeabd82e869849ceccddc34d40abbbbb269/jiter-0.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0820f4a3a59ddced7fce696d86a096d5cc48d32a4183483a17671a61edfddc", size = 376388, upload-time = "2024-12-09T18:09:34.723Z" }, + { url = "https://files.pythonhosted.org/packages/ad/8d/87b09e648e4aca5f9af89e3ab3cfb93db2d1e633b2f2931ede8dabd9b19a/jiter-0.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ffc86ae5e3e6a93765d49d1ab47b6075a9c978a2b3b80f0f32628f39caa0c88", size = 511226, upload-time = "2024-12-09T18:09:36.13Z" }, + { url = "https://files.pythonhosted.org/packages/77/95/8008ebe4cdc82eac1c97864a8042ca7e383ed67e0ec17bfd03797045c727/jiter-0.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5127dc1abd809431172bc3fbe8168d6b90556a30bb10acd5ded41c3cfd6f43b6", size = 504134, upload-time = "2024-12-09T18:09:37.581Z" }, + { url = "https://files.pythonhosted.org/packages/26/0d/3056a74de13e8b2562e4d526de6dac2f65d91ace63a8234deb9284a1d24d/jiter-0.8.2-cp311-cp311-win32.whl", hash = "sha256:66227a2c7b575720c1871c8800d3a0122bb8ee94edb43a5685aa9aceb2782d44", size = 203103, upload-time = "2024-12-09T18:09:38.881Z" }, + { url = "https://files.pythonhosted.org/packages/4e/1e/7f96b798f356e531ffc0f53dd2f37185fac60fae4d6c612bbbd4639b90aa/jiter-0.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:cde031d8413842a1e7501e9129b8e676e62a657f8ec8166e18a70d94d4682855", size = 206717, upload-time = "2024-12-09T18:09:41.064Z" }, + { url = "https://files.pythonhosted.org/packages/a1/17/c8747af8ea4e045f57d6cfd6fc180752cab9bc3de0e8a0c9ca4e8af333b1/jiter-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e6ec2be506e7d6f9527dae9ff4b7f54e68ea44a0ef6b098256ddf895218a2f8f", size = 302027, upload-time = "2024-12-09T18:09:43.11Z" }, + { url = "https://files.pythonhosted.org/packages/3c/c1/6da849640cd35a41e91085723b76acc818d4b7d92b0b6e5111736ce1dd10/jiter-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76e324da7b5da060287c54f2fabd3db5f76468006c811831f051942bf68c9d44", size = 310326, upload-time = "2024-12-09T18:09:44.426Z" }, + { url = "https://files.pythonhosted.org/packages/06/99/a2bf660d8ccffee9ad7ed46b4f860d2108a148d0ea36043fd16f4dc37e94/jiter-0.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:180a8aea058f7535d1c84183c0362c710f4750bef66630c05f40c93c2b152a0f", size = 334242, upload-time = "2024-12-09T18:09:45.915Z" }, + { url = "https://files.pythonhosted.org/packages/a7/5f/cea1c17864828731f11427b9d1ab7f24764dbd9aaf4648a7f851164d2718/jiter-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025337859077b41548bdcbabe38698bcd93cfe10b06ff66617a48ff92c9aec60", size = 356654, upload-time = "2024-12-09T18:09:47.619Z" }, + { url = "https://files.pythonhosted.org/packages/e9/13/62774b7e5e7f5d5043efe1d0f94ead66e6d0f894ae010adb56b3f788de71/jiter-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecff0dc14f409599bbcafa7e470c00b80f17abc14d1405d38ab02e4b42e55b57", size = 379967, upload-time = "2024-12-09T18:09:49.987Z" }, + { url = "https://files.pythonhosted.org/packages/ec/fb/096b34c553bb0bd3f2289d5013dcad6074948b8d55212aa13a10d44c5326/jiter-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffd9fee7d0775ebaba131f7ca2e2d83839a62ad65e8e02fe2bd8fc975cedeb9e", size = 389252, upload-time = "2024-12-09T18:09:51.329Z" }, + { url = "https://files.pythonhosted.org/packages/17/61/beea645c0bf398ced8b199e377b61eb999d8e46e053bb285c91c3d3eaab0/jiter-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14601dcac4889e0a1c75ccf6a0e4baf70dbc75041e51bcf8d0e9274519df6887", size = 345490, upload-time = "2024-12-09T18:09:52.646Z" }, + { url = "https://files.pythonhosted.org/packages/d5/df/834aa17ad5dcc3cf0118821da0a0cf1589ea7db9832589278553640366bc/jiter-0.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92249669925bc1c54fcd2ec73f70f2c1d6a817928480ee1c65af5f6b81cdf12d", size = 376991, upload-time = "2024-12-09T18:09:53.972Z" }, + { url = "https://files.pythonhosted.org/packages/67/80/87d140399d382fb4ea5b3d56e7ecaa4efdca17cd7411ff904c1517855314/jiter-0.8.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e725edd0929fa79f8349ab4ec7f81c714df51dc4e991539a578e5018fa4a7152", size = 510822, upload-time = "2024-12-09T18:09:55.439Z" }, + { url = "https://files.pythonhosted.org/packages/5c/37/3394bb47bac1ad2cb0465601f86828a0518d07828a650722e55268cdb7e6/jiter-0.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bf55846c7b7a680eebaf9c3c48d630e1bf51bdf76c68a5f654b8524335b0ad29", size = 503730, upload-time = "2024-12-09T18:09:59.494Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e2/253fc1fa59103bb4e3aa0665d6ceb1818df1cd7bf3eb492c4dad229b1cd4/jiter-0.8.2-cp312-cp312-win32.whl", hash = "sha256:7efe4853ecd3d6110301665a5178b9856be7e2a9485f49d91aa4d737ad2ae49e", size = 203375, upload-time = "2024-12-09T18:10:00.814Z" }, + { url = "https://files.pythonhosted.org/packages/41/69/6d4bbe66b3b3b4507e47aa1dd5d075919ad242b4b1115b3f80eecd443687/jiter-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:83c0efd80b29695058d0fd2fa8a556490dbce9804eac3e281f373bbc99045f6c", size = 204740, upload-time = "2024-12-09T18:10:02.146Z" }, + { url = "https://files.pythonhosted.org/packages/6c/b0/bfa1f6f2c956b948802ef5a021281978bf53b7a6ca54bb126fd88a5d014e/jiter-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ca1f08b8e43dc3bd0594c992fb1fd2f7ce87f7bf0d44358198d6da8034afdf84", size = 301190, upload-time = "2024-12-09T18:10:03.463Z" }, + { url = "https://files.pythonhosted.org/packages/a4/8f/396ddb4e292b5ea57e45ade5dc48229556b9044bad29a3b4b2dddeaedd52/jiter-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5672a86d55416ccd214c778efccf3266b84f87b89063b582167d803246354be4", size = 309334, upload-time = "2024-12-09T18:10:05.774Z" }, + { url = "https://files.pythonhosted.org/packages/7f/68/805978f2f446fa6362ba0cc2e4489b945695940656edd844e110a61c98f8/jiter-0.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58dc9bc9767a1101f4e5e22db1b652161a225874d66f0e5cb8e2c7d1c438b587", size = 333918, upload-time = "2024-12-09T18:10:07.158Z" }, + { url = "https://files.pythonhosted.org/packages/b3/99/0f71f7be667c33403fa9706e5b50583ae5106d96fab997fa7e2f38ee8347/jiter-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b2998606d6dadbb5ccda959a33d6a5e853252d921fec1792fc902351bb4e2c", size = 356057, upload-time = "2024-12-09T18:10:09.341Z" }, + { url = "https://files.pythonhosted.org/packages/8d/50/a82796e421a22b699ee4d2ce527e5bcb29471a2351cbdc931819d941a167/jiter-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab9a87f3784eb0e098f84a32670cfe4a79cb6512fd8f42ae3d0709f06405d18", size = 379790, upload-time = "2024-12-09T18:10:10.702Z" }, + { url = "https://files.pythonhosted.org/packages/3c/31/10fb012b00f6d83342ca9e2c9618869ab449f1aa78c8f1b2193a6b49647c/jiter-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79aec8172b9e3c6d05fd4b219d5de1ac616bd8da934107325a6c0d0e866a21b6", size = 388285, upload-time = "2024-12-09T18:10:12.721Z" }, + { url = "https://files.pythonhosted.org/packages/c8/81/f15ebf7de57be488aa22944bf4274962aca8092e4f7817f92ffa50d3ee46/jiter-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:711e408732d4e9a0208008e5892c2966b485c783cd2d9a681f3eb147cf36c7ef", size = 344764, upload-time = "2024-12-09T18:10:14.075Z" }, + { url = "https://files.pythonhosted.org/packages/b3/e8/0cae550d72b48829ba653eb348cdc25f3f06f8a62363723702ec18e7be9c/jiter-0.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:653cf462db4e8c41995e33d865965e79641ef45369d8a11f54cd30888b7e6ff1", size = 376620, upload-time = "2024-12-09T18:10:15.487Z" }, + { url = "https://files.pythonhosted.org/packages/b8/50/e5478ff9d82534a944c03b63bc217c5f37019d4a34d288db0f079b13c10b/jiter-0.8.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:9c63eaef32b7bebac8ebebf4dabebdbc6769a09c127294db6babee38e9f405b9", size = 510402, upload-time = "2024-12-09T18:10:17.499Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/3de48bbebbc8f7025bd454cedc8c62378c0e32dd483dece5f4a814a5cb55/jiter-0.8.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:eb21aaa9a200d0a80dacc7a81038d2e476ffe473ffdd9c91eb745d623561de05", size = 503018, upload-time = "2024-12-09T18:10:18.92Z" }, + { url = "https://files.pythonhosted.org/packages/d5/cd/d5a5501d72a11fe3e5fd65c78c884e5164eefe80077680533919be22d3a3/jiter-0.8.2-cp313-cp313-win32.whl", hash = "sha256:789361ed945d8d42850f919342a8665d2dc79e7e44ca1c97cc786966a21f627a", size = 203190, upload-time = "2024-12-09T18:10:20.801Z" }, + { url = "https://files.pythonhosted.org/packages/51/bf/e5ca301245ba951447e3ad677a02a64a8845b185de2603dabd83e1e4b9c6/jiter-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ab7f43235d71e03b941c1630f4b6e3055d46b6cb8728a17663eaac9d8e83a865", size = 203551, upload-time = "2024-12-09T18:10:22.822Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3c/71a491952c37b87d127790dd7a0b1ebea0514c6b6ad30085b16bbe00aee6/jiter-0.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b426f72cd77da3fec300ed3bc990895e2dd6b49e3bfe6c438592a3ba660e41ca", size = 308347, upload-time = "2024-12-09T18:10:24.139Z" }, + { url = "https://files.pythonhosted.org/packages/a0/4c/c02408042e6a7605ec063daed138e07b982fdb98467deaaf1c90950cf2c6/jiter-0.8.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2dd880785088ff2ad21ffee205e58a8c1ddabc63612444ae41e5e4b321b39c0", size = 342875, upload-time = "2024-12-09T18:10:25.553Z" }, + { url = "https://files.pythonhosted.org/packages/91/61/c80ef80ed8a0a21158e289ef70dac01e351d929a1c30cb0f49be60772547/jiter-0.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:3ac9f578c46f22405ff7f8b1f5848fb753cc4b8377fbec8470a7dc3997ca7566", size = 202374, upload-time = "2024-12-09T18:10:26.958Z" }, + { url = "https://files.pythonhosted.org/packages/c9/b2/ed7fbabd21c3cf556d6ea849cee35c74f13a509e668baad8323091e2867e/jiter-0.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e41e75344acef3fc59ba4765df29f107f309ca9e8eace5baacabd9217e52a5ee", size = 304502, upload-time = "2024-12-09T18:10:47.204Z" }, + { url = "https://files.pythonhosted.org/packages/75/6e/1386857ac9165c1e9c71031566e7884d8a4f63724ce29ad1ace5bfe1351c/jiter-0.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f22b16b35d5c1df9dfd58843ab2cd25e6bf15191f5a236bed177afade507bfc", size = 300982, upload-time = "2024-12-09T18:10:48.567Z" }, + { url = "https://files.pythonhosted.org/packages/56/4c/b413977c20bbb359b4d6c91d04f7f36fc525af0b7778119815477fc97242/jiter-0.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7200b8f7619d36aa51c803fd52020a2dfbea36ffec1b5e22cab11fd34d95a6d", size = 335344, upload-time = "2024-12-09T18:10:49.913Z" }, + { url = "https://files.pythonhosted.org/packages/b0/59/51b080519938192edd33b4e8d48adb7e9bf9e0d699ec8b91119b9269fc75/jiter-0.8.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70bf4c43652cc294040dbb62256c83c8718370c8b93dd93d934b9a7bf6c4f53c", size = 356298, upload-time = "2024-12-09T18:10:51.482Z" }, + { url = "https://files.pythonhosted.org/packages/72/bb/828db5ea406916d7b2232be31393f782b0f71bcb0b128750c4a028157565/jiter-0.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9d471356dc16f84ed48768b8ee79f29514295c7295cb41e1133ec0b2b8d637d", size = 381703, upload-time = "2024-12-09T18:10:53.405Z" }, + { url = "https://files.pythonhosted.org/packages/c0/88/45d33a8728733e161e9783c54d8ecca0fc4c1aa74b1cebea1d97917eddc3/jiter-0.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:859e8eb3507894093d01929e12e267f83b1d5f6221099d3ec976f0c995cb6bd9", size = 391281, upload-time = "2024-12-09T18:10:55.59Z" }, + { url = "https://files.pythonhosted.org/packages/45/3e/142712e0f45c28ad8a678dc8732a78294ce5a36fc694141f772bb827a8f2/jiter-0.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa58399c01db555346647a907b4ef6d4f584b123943be6ed5588c3f2359c9f4", size = 345553, upload-time = "2024-12-09T18:10:57.401Z" }, + { url = "https://files.pythonhosted.org/packages/36/42/9b463b59fd22687b6da1afcad6c9adc870464a808208651de73f1dbeda09/jiter-0.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8f2d5ed877f089862f4c7aacf3a542627c1496f972a34d0474ce85ee7d939c27", size = 377063, upload-time = "2024-12-09T18:10:58.855Z" }, + { url = "https://files.pythonhosted.org/packages/83/b3/44b1f5cd2e4eb15757eec341b25399da4c90515bb881ef6636b50a8c08a5/jiter-0.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:03c9df035d4f8d647f8c210ddc2ae0728387275340668fb30d2421e17d9a0841", size = 512543, upload-time = "2024-12-09T18:11:00.271Z" }, + { url = "https://files.pythonhosted.org/packages/46/4e/c695c803aa2b668c057b2dea1cdd7a884d1a819ce610cec0be9666210bfd/jiter-0.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8bd2a824d08d8977bb2794ea2682f898ad3d8837932e3a74937e93d62ecbb637", size = 505141, upload-time = "2024-12-09T18:11:02.134Z" }, + { url = "https://files.pythonhosted.org/packages/8e/51/e805b837db056f872db0b7a7a3610b7d764392be696dbe47afa0bea05bf2/jiter-0.8.2-cp39-cp39-win32.whl", hash = "sha256:ca29b6371ebc40e496995c94b988a101b9fbbed48a51190a4461fcb0a68b4a36", size = 203529, upload-time = "2024-12-09T18:11:04.227Z" }, + { url = "https://files.pythonhosted.org/packages/32/b7/a3cde72c644fd1caf9da07fb38cf2c130f43484d8f91011940b7c4f42c8f/jiter-0.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:1c0dfbd1be3cbefc7510102370d86e35d1d53e5a93d48519688b1bf0f761160a", size = 207527, upload-time = "2024-12-09T18:11:06.549Z" }, ] [[package]] name = "jmespath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, ] [[package]] name = "markupsafe" version = "2.1.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384 } +sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384, upload-time = "2024-02-02T16:31:22.863Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", size = 18206 }, - { url = "https://files.pythonhosted.org/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", size = 14079 }, - { url = "https://files.pythonhosted.org/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", size = 26620 }, - { url = "https://files.pythonhosted.org/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", size = 25818 }, - { url = "https://files.pythonhosted.org/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", size = 25493 }, - { url = "https://files.pythonhosted.org/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", size = 30630 }, - { url = "https://files.pythonhosted.org/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", size = 29745 }, - { url = "https://files.pythonhosted.org/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", size = 30021 }, - { url = "https://files.pythonhosted.org/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", size = 16659 }, - { url = "https://files.pythonhosted.org/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", size = 17213 }, - { url = "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", size = 18219 }, - { url = "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", size = 14098 }, - { url = "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", size = 29014 }, - { url = "https://files.pythonhosted.org/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", size = 28220 }, - { url = "https://files.pythonhosted.org/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", size = 27756 }, - { url = "https://files.pythonhosted.org/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", size = 33988 }, - { url = "https://files.pythonhosted.org/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", size = 32718 }, - { url = "https://files.pythonhosted.org/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", size = 33317 }, - { url = "https://files.pythonhosted.org/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", size = 16670 }, - { url = "https://files.pythonhosted.org/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", size = 17224 }, - { url = "https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", size = 18215 }, - { url = "https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", size = 14069 }, - { url = "https://files.pythonhosted.org/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", size = 29452 }, - { url = "https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", size = 28462 }, - { url = "https://files.pythonhosted.org/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", size = 27869 }, - { url = "https://files.pythonhosted.org/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", size = 33906 }, - { url = "https://files.pythonhosted.org/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", size = 32296 }, - { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038 }, - { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572 }, - { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127 }, - { url = "https://files.pythonhosted.org/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", size = 18193 }, - { url = "https://files.pythonhosted.org/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", size = 14073 }, - { url = "https://files.pythonhosted.org/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", size = 26486 }, - { url = "https://files.pythonhosted.org/packages/5f/5a/360da85076688755ea0cceb92472923086993e86b5613bbae9fbc14136b0/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", size = 25685 }, - { url = "https://files.pythonhosted.org/packages/6a/18/ae5a258e3401f9b8312f92b028c54d7026a97ec3ab20bfaddbdfa7d8cce8/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", size = 25338 }, - { url = "https://files.pythonhosted.org/packages/0b/cc/48206bd61c5b9d0129f4d75243b156929b04c94c09041321456fd06a876d/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", size = 30439 }, - { url = "https://files.pythonhosted.org/packages/d1/06/a41c112ab9ffdeeb5f77bc3e331fdadf97fa65e52e44ba31880f4e7f983c/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", size = 29531 }, - { url = "https://files.pythonhosted.org/packages/02/8c/ab9a463301a50dab04d5472e998acbd4080597abc048166ded5c7aa768c8/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", size = 29823 }, - { url = "https://files.pythonhosted.org/packages/bc/29/9bc18da763496b055d8e98ce476c8e718dcfd78157e17f555ce6dd7d0895/MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", size = 16658 }, - { url = "https://files.pythonhosted.org/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", size = 17211 }, + { url = "https://files.pythonhosted.org/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", size = 18206, upload-time = "2024-02-02T16:30:04.105Z" }, + { url = "https://files.pythonhosted.org/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", size = 14079, upload-time = "2024-02-02T16:30:06.5Z" }, + { url = "https://files.pythonhosted.org/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", size = 26620, upload-time = "2024-02-02T16:30:08.31Z" }, + { url = "https://files.pythonhosted.org/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", size = 25818, upload-time = "2024-02-02T16:30:09.577Z" }, + { url = "https://files.pythonhosted.org/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", size = 25493, upload-time = "2024-02-02T16:30:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", size = 30630, upload-time = "2024-02-02T16:30:13.144Z" }, + { url = "https://files.pythonhosted.org/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", size = 29745, upload-time = "2024-02-02T16:30:14.222Z" }, + { url = "https://files.pythonhosted.org/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", size = 30021, upload-time = "2024-02-02T16:30:16.032Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", size = 16659, upload-time = "2024-02-02T16:30:17.079Z" }, + { url = "https://files.pythonhosted.org/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", size = 17213, upload-time = "2024-02-02T16:30:18.251Z" }, + { url = "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", size = 18219, upload-time = "2024-02-02T16:30:19.988Z" }, + { url = "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", size = 14098, upload-time = "2024-02-02T16:30:21.063Z" }, + { url = "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", size = 29014, upload-time = "2024-02-02T16:30:22.926Z" }, + { url = "https://files.pythonhosted.org/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", size = 28220, upload-time = "2024-02-02T16:30:24.76Z" }, + { url = "https://files.pythonhosted.org/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", size = 27756, upload-time = "2024-02-02T16:30:25.877Z" }, + { url = "https://files.pythonhosted.org/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", size = 33988, upload-time = "2024-02-02T16:30:26.935Z" }, + { url = "https://files.pythonhosted.org/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", size = 32718, upload-time = "2024-02-02T16:30:28.111Z" }, + { url = "https://files.pythonhosted.org/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", size = 33317, upload-time = "2024-02-02T16:30:29.214Z" }, + { url = "https://files.pythonhosted.org/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", size = 16670, upload-time = "2024-02-02T16:30:30.915Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", size = 17224, upload-time = "2024-02-02T16:30:32.09Z" }, + { url = "https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", size = 18215, upload-time = "2024-02-02T16:30:33.081Z" }, + { url = "https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", size = 14069, upload-time = "2024-02-02T16:30:34.148Z" }, + { url = "https://files.pythonhosted.org/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", size = 29452, upload-time = "2024-02-02T16:30:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", size = 28462, upload-time = "2024-02-02T16:30:36.166Z" }, + { url = "https://files.pythonhosted.org/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", size = 27869, upload-time = "2024-02-02T16:30:37.834Z" }, + { url = "https://files.pythonhosted.org/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", size = 33906, upload-time = "2024-02-02T16:30:39.366Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", size = 32296, upload-time = "2024-02-02T16:30:40.413Z" }, + { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038, upload-time = "2024-02-02T16:30:42.243Z" }, + { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572, upload-time = "2024-02-02T16:30:43.326Z" }, + { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127, upload-time = "2024-02-02T16:30:44.418Z" }, + { url = "https://files.pythonhosted.org/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", size = 18193, upload-time = "2024-02-02T16:31:10.155Z" }, + { url = "https://files.pythonhosted.org/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", size = 14073, upload-time = "2024-02-02T16:31:11.442Z" }, + { url = "https://files.pythonhosted.org/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", size = 26486, upload-time = "2024-02-02T16:31:12.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5a/360da85076688755ea0cceb92472923086993e86b5613bbae9fbc14136b0/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", size = 25685, upload-time = "2024-02-02T16:31:13.726Z" }, + { url = "https://files.pythonhosted.org/packages/6a/18/ae5a258e3401f9b8312f92b028c54d7026a97ec3ab20bfaddbdfa7d8cce8/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", size = 25338, upload-time = "2024-02-02T16:31:14.812Z" }, + { url = "https://files.pythonhosted.org/packages/0b/cc/48206bd61c5b9d0129f4d75243b156929b04c94c09041321456fd06a876d/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", size = 30439, upload-time = "2024-02-02T16:31:15.946Z" }, + { url = "https://files.pythonhosted.org/packages/d1/06/a41c112ab9ffdeeb5f77bc3e331fdadf97fa65e52e44ba31880f4e7f983c/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", size = 29531, upload-time = "2024-02-02T16:31:17.13Z" }, + { url = "https://files.pythonhosted.org/packages/02/8c/ab9a463301a50dab04d5472e998acbd4080597abc048166ded5c7aa768c8/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", size = 29823, upload-time = "2024-02-02T16:31:18.247Z" }, + { url = "https://files.pythonhosted.org/packages/bc/29/9bc18da763496b055d8e98ce476c8e718dcfd78157e17f555ce6dd7d0895/MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", size = 16658, upload-time = "2024-02-02T16:31:19.583Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", size = 17211, upload-time = "2024-02-02T16:31:20.96Z" }, ] [[package]] @@ -516,20 +517,20 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/51/28/31a650d9209d873b6aec759c944bd284155154d7a01f7f541786d7c435ca/maturin-1.7.4.tar.gz", hash = "sha256:2b349d742a07527d236f0b4b6cab26f53ebecad0ceabfc09ec4c6a396e3176f9", size = 191145 } +sdist = { url = "https://files.pythonhosted.org/packages/51/28/31a650d9209d873b6aec759c944bd284155154d7a01f7f541786d7c435ca/maturin-1.7.4.tar.gz", hash = "sha256:2b349d742a07527d236f0b4b6cab26f53ebecad0ceabfc09ec4c6a396e3176f9", size = 191145, upload-time = "2024-09-26T03:36:19.196Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/85/19/b5be36f3cb30ba72aa2232492d4462409955da134ea25083f0e625618082/maturin-1.7.4-py3-none-linux_armv6l.whl", hash = "sha256:eb7b7753b733ae302c08f80bca7b0c3fda1eea665c2b1922c58795f35a54c833", size = 8215481 }, - { url = "https://files.pythonhosted.org/packages/4f/0a/1b2a2fda3f338dedd219de358d77b01f1138bc4bc6b4c73b6ea01d8ddd9e/maturin-1.7.4-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0182a9638399c8835afd39d2aeacf56908e37cba3f7abb15816b9df6774fab81", size = 15930801 }, - { url = "https://files.pythonhosted.org/packages/21/df/f75dcd8472f3be5b528942b11444eb4a82aa1aced7d105a8ba39bb85ece8/maturin-1.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:41a29c5b23f3ebdfe7633637e3de256579a1b2700c04cd68c16ed46934440c5a", size = 8166643 }, - { url = "https://files.pythonhosted.org/packages/87/43/52baa75e6dae9848ea22ae6bd405e7f7da091ba63409b07912048fde2083/maturin-1.7.4-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:23fae44e345a2da5cb391ae878726fb793394826e2f97febe41710bd4099460e", size = 8560688 }, - { url = "https://files.pythonhosted.org/packages/84/97/5e2bfbcf42725ba5f64310423edcf00d90e684a61d55dd0a26b2313a44b6/maturin-1.7.4-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:8b441521c151f0dbe70ed06fb1feb29b855d787bda038ff4330ca962e5d56641", size = 8939107 }, - { url = "https://files.pythonhosted.org/packages/34/59/e0d58ce67a8a6245dcb74ffb81cb12f0cda8b622c8d902f2371de742ae04/maturin-1.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:7ccb66d0c5297cf06652c5f72cb398f447d3a332eccf5d1e73b3fe14dbc9498c", size = 8425431 }, - { url = "https://files.pythonhosted.org/packages/53/20/4b79324b14a1f39b2c66eb1ad681cf8b0fff1f905374b0cca59fc9c8ef7a/maturin-1.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:71f668f19e719048605dbca6a1f4d0dc03b987c922ad9c4bf5be03b9b278e4c3", size = 8104459 }, - { url = "https://files.pythonhosted.org/packages/7f/fa/8d9497c62451fc19f52cda1ad652c5dca4e9646ff93be35250070afbc2af/maturin-1.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:c179fcb2b494f19186781b667320e43d95b3e71fcb1c98fffad9ef6bd6e276b3", size = 8729663 }, - { url = "https://files.pythonhosted.org/packages/a4/e9/15a24263de981928303ca64465d5d9d5062f248b9ceaab3de5857ee0ba83/maturin-1.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd5b4b95286f2f376437340f8a4908f4761587212170263084455be8099099a7", size = 10142511 }, - { url = "https://files.pythonhosted.org/packages/a5/5d/59765561ea1a5f993141a403eb4ae85b7a8bd118971de0ed14048e3faf7f/maturin-1.7.4-py3-none-win32.whl", hash = "sha256:35487a424467d1fda4567cbb02d21f09febb10eda22f5fd647b130bc0767dc61", size = 6578873 }, - { url = "https://files.pythonhosted.org/packages/72/50/a9b402aa506bad6c066c7775b1cb3036b7b1c74b9de708ed537ee804ea4a/maturin-1.7.4-py3-none-win_amd64.whl", hash = "sha256:f70c1c8ec9bd4749a53c0f3ae8fdbb326ce45be4f1c5551985ee25a6d7150328", size = 7442039 }, - { url = "https://files.pythonhosted.org/packages/30/38/8e27282ab6ff94291f04e3eb11ba960dfb487605d73cec75177d3a29879a/maturin-1.7.4-py3-none-win_arm64.whl", hash = "sha256:f3d38a6d0c7fd7b04bec30dd470b2173cf9bd184ab6220c1acaf49df6b48faf5", size = 6388008 }, + { url = "https://files.pythonhosted.org/packages/85/19/b5be36f3cb30ba72aa2232492d4462409955da134ea25083f0e625618082/maturin-1.7.4-py3-none-linux_armv6l.whl", hash = "sha256:eb7b7753b733ae302c08f80bca7b0c3fda1eea665c2b1922c58795f35a54c833", size = 8215481, upload-time = "2024-09-26T03:35:42.249Z" }, + { url = "https://files.pythonhosted.org/packages/4f/0a/1b2a2fda3f338dedd219de358d77b01f1138bc4bc6b4c73b6ea01d8ddd9e/maturin-1.7.4-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0182a9638399c8835afd39d2aeacf56908e37cba3f7abb15816b9df6774fab81", size = 15930801, upload-time = "2024-09-26T03:35:45.875Z" }, + { url = "https://files.pythonhosted.org/packages/21/df/f75dcd8472f3be5b528942b11444eb4a82aa1aced7d105a8ba39bb85ece8/maturin-1.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:41a29c5b23f3ebdfe7633637e3de256579a1b2700c04cd68c16ed46934440c5a", size = 8166643, upload-time = "2024-09-26T03:35:48.872Z" }, + { url = "https://files.pythonhosted.org/packages/87/43/52baa75e6dae9848ea22ae6bd405e7f7da091ba63409b07912048fde2083/maturin-1.7.4-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:23fae44e345a2da5cb391ae878726fb793394826e2f97febe41710bd4099460e", size = 8560688, upload-time = "2024-09-26T03:35:51.156Z" }, + { url = "https://files.pythonhosted.org/packages/84/97/5e2bfbcf42725ba5f64310423edcf00d90e684a61d55dd0a26b2313a44b6/maturin-1.7.4-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:8b441521c151f0dbe70ed06fb1feb29b855d787bda038ff4330ca962e5d56641", size = 8939107, upload-time = "2024-09-26T03:35:54.444Z" }, + { url = "https://files.pythonhosted.org/packages/34/59/e0d58ce67a8a6245dcb74ffb81cb12f0cda8b622c8d902f2371de742ae04/maturin-1.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:7ccb66d0c5297cf06652c5f72cb398f447d3a332eccf5d1e73b3fe14dbc9498c", size = 8425431, upload-time = "2024-09-26T03:35:57.888Z" }, + { url = "https://files.pythonhosted.org/packages/53/20/4b79324b14a1f39b2c66eb1ad681cf8b0fff1f905374b0cca59fc9c8ef7a/maturin-1.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:71f668f19e719048605dbca6a1f4d0dc03b987c922ad9c4bf5be03b9b278e4c3", size = 8104459, upload-time = "2024-09-26T03:36:01.468Z" }, + { url = "https://files.pythonhosted.org/packages/7f/fa/8d9497c62451fc19f52cda1ad652c5dca4e9646ff93be35250070afbc2af/maturin-1.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:c179fcb2b494f19186781b667320e43d95b3e71fcb1c98fffad9ef6bd6e276b3", size = 8729663, upload-time = "2024-09-26T03:36:04.192Z" }, + { url = "https://files.pythonhosted.org/packages/a4/e9/15a24263de981928303ca64465d5d9d5062f248b9ceaab3de5857ee0ba83/maturin-1.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd5b4b95286f2f376437340f8a4908f4761587212170263084455be8099099a7", size = 10142511, upload-time = "2024-09-26T03:36:07.675Z" }, + { url = "https://files.pythonhosted.org/packages/a5/5d/59765561ea1a5f993141a403eb4ae85b7a8bd118971de0ed14048e3faf7f/maturin-1.7.4-py3-none-win32.whl", hash = "sha256:35487a424467d1fda4567cbb02d21f09febb10eda22f5fd647b130bc0767dc61", size = 6578873, upload-time = "2024-09-26T03:36:10.964Z" }, + { url = "https://files.pythonhosted.org/packages/72/50/a9b402aa506bad6c066c7775b1cb3036b7b1c74b9de708ed537ee804ea4a/maturin-1.7.4-py3-none-win_amd64.whl", hash = "sha256:f70c1c8ec9bd4749a53c0f3ae8fdbb326ce45be4f1c5551985ee25a6d7150328", size = 7442039, upload-time = "2024-09-26T03:36:13.81Z" }, + { url = "https://files.pythonhosted.org/packages/30/38/8e27282ab6ff94291f04e3eb11ba960dfb487605d73cec75177d3a29879a/maturin-1.7.4-py3-none-win_arm64.whl", hash = "sha256:f3d38a6d0c7fd7b04bec30dd470b2173cf9bd184ab6220c1acaf49df6b48faf5", size = 6388008, upload-time = "2024-09-26T03:36:16.663Z" }, ] [[package]] @@ -546,53 +547,51 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7b/1d/aae78d8ecc571d672c4a27794a8f248bc46437a22ddcb9c4eb6fd6616c03/openai-1.64.0.tar.gz", hash = "sha256:2861053538704d61340da56e2f176853d19f1dc5704bc306b7597155f850d57a", size = 357058 } +sdist = { url = "https://files.pythonhosted.org/packages/7b/1d/aae78d8ecc571d672c4a27794a8f248bc46437a22ddcb9c4eb6fd6616c03/openai-1.64.0.tar.gz", hash = "sha256:2861053538704d61340da56e2f176853d19f1dc5704bc306b7597155f850d57a", size = 357058, upload-time = "2025-02-22T20:56:33.693Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/1a/e62718f311daa26d208800976d7944e5ee6d503e1ea474522b2a15a904bb/openai-1.64.0-py3-none-any.whl", hash = "sha256:20f85cde9e95e9fbb416e3cb5a6d3119c0b28308afd6e3cc47bf100623dac623", size = 472289 }, + { url = "https://files.pythonhosted.org/packages/9a/1a/e62718f311daa26d208800976d7944e5ee6d503e1ea474522b2a15a904bb/openai-1.64.0-py3-none-any.whl", hash = "sha256:20f85cde9e95e9fbb416e3cb5a6d3119c0b28308afd6e3cc47bf100623dac623", size = 472289, upload-time = "2025-02-22T20:56:31.054Z" }, ] [[package]] name = "packaging" version = "24.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950, upload-time = "2024-11-08T09:47:47.202Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451, upload-time = "2024-11-08T09:47:44.722Z" }, ] [[package]] name = "pluggy" version = "1.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, ] [[package]] name = "psutil" version = "6.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/5a/07871137bb752428aa4b659f910b399ba6f291156bdea939be3e96cae7cb/psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5", size = 508502 } +sdist = { url = "https://files.pythonhosted.org/packages/1f/5a/07871137bb752428aa4b659f910b399ba6f291156bdea939be3e96cae7cb/psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5", size = 508502, upload-time = "2024-12-19T18:21:20.568Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/d4/8095b53c4950f44dc99b8d983b796f405ae1f58d80978fcc0421491b4201/psutil-6.1.1-cp27-none-win32.whl", hash = "sha256:6d4281f5bbca041e2292be3380ec56a9413b790579b8e593b1784499d0005dac", size = 246855 }, - { url = "https://files.pythonhosted.org/packages/b1/63/0b6425ea4f2375988209a9934c90d6079cc7537847ed58a28fbe30f4277e/psutil-6.1.1-cp27-none-win_amd64.whl", hash = "sha256:c777eb75bb33c47377c9af68f30e9f11bc78e0f07fbf907be4a5d70b2fe5f030", size = 250110 }, - { url = "https://files.pythonhosted.org/packages/61/99/ca79d302be46f7bdd8321089762dd4476ee725fce16fc2b2e1dbba8cac17/psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8", size = 247511 }, - { url = "https://files.pythonhosted.org/packages/0b/6b/73dbde0dd38f3782905d4587049b9be64d76671042fdcaf60e2430c6796d/psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377", size = 248985 }, - { url = "https://files.pythonhosted.org/packages/17/38/c319d31a1d3f88c5b79c68b3116c129e5133f1822157dd6da34043e32ed6/psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003", size = 284488 }, - { url = "https://files.pythonhosted.org/packages/9c/39/0f88a830a1c8a3aba27fededc642da37613c57cbff143412e3536f89784f/psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160", size = 287477 }, - { url = "https://files.pythonhosted.org/packages/47/da/99f4345d4ddf2845cb5b5bd0d93d554e84542d116934fde07a0c50bd4e9f/psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3", size = 289017 }, - { url = "https://files.pythonhosted.org/packages/38/53/bd755c2896f4461fd4f36fa6a6dcb66a88a9e4b9fd4e5b66a77cf9d4a584/psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53", size = 250602 }, - { url = "https://files.pythonhosted.org/packages/7b/d7/7831438e6c3ebbfa6e01a927127a6cb42ad3ab844247f3c5b96bea25d73d/psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649", size = 254444 }, + { url = "https://files.pythonhosted.org/packages/61/99/ca79d302be46f7bdd8321089762dd4476ee725fce16fc2b2e1dbba8cac17/psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8", size = 247511, upload-time = "2024-12-19T18:21:45.163Z" }, + { url = "https://files.pythonhosted.org/packages/0b/6b/73dbde0dd38f3782905d4587049b9be64d76671042fdcaf60e2430c6796d/psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377", size = 248985, upload-time = "2024-12-19T18:21:49.254Z" }, + { url = "https://files.pythonhosted.org/packages/17/38/c319d31a1d3f88c5b79c68b3116c129e5133f1822157dd6da34043e32ed6/psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003", size = 284488, upload-time = "2024-12-19T18:21:51.638Z" }, + { url = "https://files.pythonhosted.org/packages/9c/39/0f88a830a1c8a3aba27fededc642da37613c57cbff143412e3536f89784f/psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160", size = 287477, upload-time = "2024-12-19T18:21:55.306Z" }, + { url = "https://files.pythonhosted.org/packages/47/da/99f4345d4ddf2845cb5b5bd0d93d554e84542d116934fde07a0c50bd4e9f/psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3", size = 289017, upload-time = "2024-12-19T18:21:57.875Z" }, + { url = "https://files.pythonhosted.org/packages/38/53/bd755c2896f4461fd4f36fa6a6dcb66a88a9e4b9fd4e5b66a77cf9d4a584/psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53", size = 250602, upload-time = "2024-12-19T18:22:08.808Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d7/7831438e6c3ebbfa6e01a927127a6cb42ad3ab844247f3c5b96bea25d73d/psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649", size = 254444, upload-time = "2024-12-19T18:22:11.335Z" }, ] [[package]] name = "pyasn1" version = "0.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135 }, + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, ] [[package]] @@ -602,9 +601,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1d/67/6afbf0d507f73c32d21084a79946bfcfca5fbc62a72057e9c23797a737c9/pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c", size = 310028 } +sdist = { url = "https://files.pythonhosted.org/packages/1d/67/6afbf0d507f73c32d21084a79946bfcfca5fbc62a72057e9c23797a737c9/pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c", size = 310028, upload-time = "2024-09-10T22:42:08.349Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/89/bc88a6711935ba795a679ea6ebee07e128050d6382eaa35a0a47c8032bdc/pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd", size = 181537 }, + { url = "https://files.pythonhosted.org/packages/77/89/bc88a6711935ba795a679ea6ebee07e128050d6382eaa35a0a47c8032bdc/pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd", size = 181537, upload-time = "2024-09-11T16:02:10.336Z" }, ] [[package]] @@ -616,9 +615,9 @@ dependencies = [ { name = "pydantic-core" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681 } +sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681, upload-time = "2025-01-24T01:42:12.693Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696 }, + { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696, upload-time = "2025-01-24T01:42:10.371Z" }, ] [[package]] @@ -628,94 +627,94 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938 }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684 }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169 }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227 }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695 }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662 }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370 }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813 }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287 }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414 }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301 }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685 }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876 }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421 }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998 }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167 }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071 }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244 }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470 }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291 }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613 }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355 }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661 }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261 }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361 }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484 }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102 }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, - { url = "https://files.pythonhosted.org/packages/27/97/3aef1ddb65c5ccd6eda9050036c956ff6ecbfe66cb7eb40f280f121a5bb0/pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", size = 1896475 }, - { url = "https://files.pythonhosted.org/packages/ad/d3/5668da70e373c9904ed2f372cb52c0b996426f302e0dee2e65634c92007d/pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", size = 1772279 }, - { url = "https://files.pythonhosted.org/packages/8a/9e/e44b8cb0edf04a2f0a1f6425a65ee089c1d6f9c4c2dcab0209127b6fdfc2/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", size = 1829112 }, - { url = "https://files.pythonhosted.org/packages/1c/90/1160d7ac700102effe11616e8119e268770f2a2aa5afb935f3ee6832987d/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", size = 1866780 }, - { url = "https://files.pythonhosted.org/packages/ee/33/13983426df09a36d22c15980008f8d9c77674fc319351813b5a2739b70f3/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", size = 2037943 }, - { url = "https://files.pythonhosted.org/packages/01/d7/ced164e376f6747e9158c89988c293cd524ab8d215ae4e185e9929655d5c/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", size = 2740492 }, - { url = "https://files.pythonhosted.org/packages/8b/1f/3dc6e769d5b7461040778816aab2b00422427bcaa4b56cc89e9c653b2605/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", size = 1995714 }, - { url = "https://files.pythonhosted.org/packages/07/d7/a0bd09bc39283530b3f7c27033a814ef254ba3bd0b5cfd040b7abf1fe5da/pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", size = 1997163 }, - { url = "https://files.pythonhosted.org/packages/2d/bb/2db4ad1762e1c5699d9b857eeb41959191980de6feb054e70f93085e1bcd/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", size = 2005217 }, - { url = "https://files.pythonhosted.org/packages/53/5f/23a5a3e7b8403f8dd8fc8a6f8b49f6b55c7d715b77dcf1f8ae919eeb5628/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", size = 2127899 }, - { url = "https://files.pythonhosted.org/packages/c2/ae/aa38bb8dd3d89c2f1d8362dd890ee8f3b967330821d03bbe08fa01ce3766/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", size = 2155726 }, - { url = "https://files.pythonhosted.org/packages/98/61/4f784608cc9e98f70839187117ce840480f768fed5d386f924074bf6213c/pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", size = 1817219 }, - { url = "https://files.pythonhosted.org/packages/57/82/bb16a68e4a1a858bb3768c2c8f1ff8d8978014e16598f001ea29a25bf1d1/pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", size = 1985382 }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159 }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331 }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467 }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797 }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839 }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861 }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582 }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985 }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715 }, - { url = "https://files.pythonhosted.org/packages/29/0e/dcaea00c9dbd0348b723cae82b0e0c122e0fa2b43fa933e1622fd237a3ee/pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", size = 1891733 }, - { url = "https://files.pythonhosted.org/packages/86/d3/e797bba8860ce650272bda6383a9d8cad1d1c9a75a640c9d0e848076f85e/pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", size = 1768375 }, - { url = "https://files.pythonhosted.org/packages/41/f7/f847b15fb14978ca2b30262548f5fc4872b2724e90f116393eb69008299d/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", size = 1822307 }, - { url = "https://files.pythonhosted.org/packages/9c/63/ed80ec8255b587b2f108e514dc03eed1546cd00f0af281e699797f373f38/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", size = 1979971 }, - { url = "https://files.pythonhosted.org/packages/a9/6d/6d18308a45454a0de0e975d70171cadaf454bc7a0bf86b9c7688e313f0bb/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", size = 1987616 }, - { url = "https://files.pythonhosted.org/packages/82/8a/05f8780f2c1081b800a7ca54c1971e291c2d07d1a50fb23c7e4aef4ed403/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", size = 1998943 }, - { url = "https://files.pythonhosted.org/packages/5e/3e/fe5b6613d9e4c0038434396b46c5303f5ade871166900b357ada4766c5b7/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", size = 2116654 }, - { url = "https://files.pythonhosted.org/packages/db/ad/28869f58938fad8cc84739c4e592989730bfb69b7c90a8fff138dff18e1e/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", size = 2152292 }, - { url = "https://files.pythonhosted.org/packages/a1/0c/c5c5cd3689c32ed1fe8c5d234b079c12c281c051759770c05b8bed6412b5/pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", size = 2004961 }, + { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, + { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, + { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, + { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, + { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, + { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, + { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, + { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, + { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, + { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, + { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, + { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, + { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, + { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, + { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, + { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, + { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, + { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, + { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, + { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, + { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, + { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, + { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, + { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, + { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, + { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, + { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, + { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, + { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, + { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, + { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, + { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, + { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, + { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, + { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, + { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, + { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, + { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, + { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, + { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, + { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, + { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, + { url = "https://files.pythonhosted.org/packages/27/97/3aef1ddb65c5ccd6eda9050036c956ff6ecbfe66cb7eb40f280f121a5bb0/pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", size = 1896475, upload-time = "2024-12-18T11:30:18.316Z" }, + { url = "https://files.pythonhosted.org/packages/ad/d3/5668da70e373c9904ed2f372cb52c0b996426f302e0dee2e65634c92007d/pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", size = 1772279, upload-time = "2024-12-18T11:30:20.547Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/e44b8cb0edf04a2f0a1f6425a65ee089c1d6f9c4c2dcab0209127b6fdfc2/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", size = 1829112, upload-time = "2024-12-18T11:30:23.255Z" }, + { url = "https://files.pythonhosted.org/packages/1c/90/1160d7ac700102effe11616e8119e268770f2a2aa5afb935f3ee6832987d/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", size = 1866780, upload-time = "2024-12-18T11:30:25.742Z" }, + { url = "https://files.pythonhosted.org/packages/ee/33/13983426df09a36d22c15980008f8d9c77674fc319351813b5a2739b70f3/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", size = 2037943, upload-time = "2024-12-18T11:30:28.036Z" }, + { url = "https://files.pythonhosted.org/packages/01/d7/ced164e376f6747e9158c89988c293cd524ab8d215ae4e185e9929655d5c/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", size = 2740492, upload-time = "2024-12-18T11:30:30.412Z" }, + { url = "https://files.pythonhosted.org/packages/8b/1f/3dc6e769d5b7461040778816aab2b00422427bcaa4b56cc89e9c653b2605/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", size = 1995714, upload-time = "2024-12-18T11:30:34.358Z" }, + { url = "https://files.pythonhosted.org/packages/07/d7/a0bd09bc39283530b3f7c27033a814ef254ba3bd0b5cfd040b7abf1fe5da/pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", size = 1997163, upload-time = "2024-12-18T11:30:37.979Z" }, + { url = "https://files.pythonhosted.org/packages/2d/bb/2db4ad1762e1c5699d9b857eeb41959191980de6feb054e70f93085e1bcd/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", size = 2005217, upload-time = "2024-12-18T11:30:40.367Z" }, + { url = "https://files.pythonhosted.org/packages/53/5f/23a5a3e7b8403f8dd8fc8a6f8b49f6b55c7d715b77dcf1f8ae919eeb5628/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", size = 2127899, upload-time = "2024-12-18T11:30:42.737Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ae/aa38bb8dd3d89c2f1d8362dd890ee8f3b967330821d03bbe08fa01ce3766/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", size = 2155726, upload-time = "2024-12-18T11:30:45.279Z" }, + { url = "https://files.pythonhosted.org/packages/98/61/4f784608cc9e98f70839187117ce840480f768fed5d386f924074bf6213c/pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", size = 1817219, upload-time = "2024-12-18T11:30:47.718Z" }, + { url = "https://files.pythonhosted.org/packages/57/82/bb16a68e4a1a858bb3768c2c8f1ff8d8978014e16598f001ea29a25bf1d1/pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", size = 1985382, upload-time = "2024-12-18T11:30:51.871Z" }, + { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, + { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, + { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, + { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, + { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, + { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, + { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, + { url = "https://files.pythonhosted.org/packages/29/0e/dcaea00c9dbd0348b723cae82b0e0c122e0fa2b43fa933e1622fd237a3ee/pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", size = 1891733, upload-time = "2024-12-18T11:31:26.876Z" }, + { url = "https://files.pythonhosted.org/packages/86/d3/e797bba8860ce650272bda6383a9d8cad1d1c9a75a640c9d0e848076f85e/pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", size = 1768375, upload-time = "2024-12-18T11:31:29.276Z" }, + { url = "https://files.pythonhosted.org/packages/41/f7/f847b15fb14978ca2b30262548f5fc4872b2724e90f116393eb69008299d/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", size = 1822307, upload-time = "2024-12-18T11:31:33.123Z" }, + { url = "https://files.pythonhosted.org/packages/9c/63/ed80ec8255b587b2f108e514dc03eed1546cd00f0af281e699797f373f38/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", size = 1979971, upload-time = "2024-12-18T11:31:35.755Z" }, + { url = "https://files.pythonhosted.org/packages/a9/6d/6d18308a45454a0de0e975d70171cadaf454bc7a0bf86b9c7688e313f0bb/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", size = 1987616, upload-time = "2024-12-18T11:31:38.534Z" }, + { url = "https://files.pythonhosted.org/packages/82/8a/05f8780f2c1081b800a7ca54c1971e291c2d07d1a50fb23c7e4aef4ed403/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", size = 1998943, upload-time = "2024-12-18T11:31:41.853Z" }, + { url = "https://files.pythonhosted.org/packages/5e/3e/fe5b6613d9e4c0038434396b46c5303f5ade871166900b357ada4766c5b7/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", size = 2116654, upload-time = "2024-12-18T11:31:44.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/ad/28869f58938fad8cc84739c4e592989730bfb69b7c90a8fff138dff18e1e/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", size = 2152292, upload-time = "2024-12-18T11:31:48.613Z" }, + { url = "https://files.pythonhosted.org/packages/a1/0c/c5c5cd3689c32ed1fe8c5d234b079c12c281c051759770c05b8bed6412b5/pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", size = 2004961, upload-time = "2024-12-18T11:31:52.446Z" }, ] [[package]] @@ -730,9 +729,9 @@ dependencies = [ { name = "pluggy" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } +sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487, upload-time = "2024-09-10T10:52:15.003Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, + { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341, upload-time = "2024-09-10T10:52:12.54Z" }, ] [[package]] @@ -742,9 +741,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/b4/0b378b7bf26a8ae161c3890c0b48a91a04106c5713ce81b4b080ea2f4f18/pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3", size = 46920 } +sdist = { url = "https://files.pythonhosted.org/packages/de/b4/0b378b7bf26a8ae161c3890c0b48a91a04106c5713ce81b4b080ea2f4f18/pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3", size = 46920, upload-time = "2024-07-17T17:39:34.617Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", size = 17663 }, + { url = "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", size = 17663, upload-time = "2024-07-17T17:39:32.478Z" }, ] [[package]] @@ -754,18 +753,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] [[package]] name = "python-dotenv" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115, upload-time = "2024-01-23T06:33:00.505Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, + { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863, upload-time = "2024-01-23T06:32:58.246Z" }, ] [[package]] @@ -793,6 +792,7 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "ruff" }, + { name = "types-assertpy" }, ] [package.metadata] @@ -815,7 +815,10 @@ requires-dist = [ ] [package.metadata.requires-dev] -dev = [{ name = "ruff", specifier = ">=0.9.10" }] +dev = [ + { name = "ruff", specifier = ">=0.9.10" }, + { name = "types-assertpy" }, +] [[package]] name = "requests" @@ -828,9 +831,9 @@ dependencies = [ { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "urllib3", version = "2.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, ] [[package]] @@ -840,34 +843,34 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/65/7d973b89c4d2351d7fb232c2e452547ddfa243e93131e7cfa766da627b52/rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21", size = 29711 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/65/7d973b89c4d2351d7fb232c2e452547ddfa243e93131e7cfa766da627b52/rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21", size = 29711, upload-time = "2022-07-20T10:28:36.115Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/49/97/fa78e3d2f65c02c8e1268b9aba606569fe97f6c8f7c2d74394553347c145/rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", size = 34315 }, + { url = "https://files.pythonhosted.org/packages/49/97/fa78e3d2f65c02c8e1268b9aba606569fe97f6c8f7c2d74394553347c145/rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", size = 34315, upload-time = "2022-07-20T10:28:34.978Z" }, ] [[package]] name = "ruff" version = "0.9.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", size = 3759776 } +sdist = { url = "https://files.pythonhosted.org/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", size = 3759776, upload-time = "2025-03-07T15:27:44.363Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", size = 10049494 }, - { url = "https://files.pythonhosted.org/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", size = 10853584 }, - { url = "https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", size = 10155692 }, - { url = "https://files.pythonhosted.org/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", size = 10369760 }, - { url = "https://files.pythonhosted.org/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", size = 9912196 }, - { url = "https://files.pythonhosted.org/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", size = 11434985 }, - { url = "https://files.pythonhosted.org/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", size = 12155842 }, - { url = "https://files.pythonhosted.org/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", size = 11613804 }, - { url = "https://files.pythonhosted.org/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", size = 13823776 }, - { url = "https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", size = 11302673 }, - { url = "https://files.pythonhosted.org/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", size = 10235358 }, - { url = "https://files.pythonhosted.org/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", size = 9886177 }, - { url = "https://files.pythonhosted.org/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", size = 10864747 }, - { url = "https://files.pythonhosted.org/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", size = 11360441 }, - { url = "https://files.pythonhosted.org/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", size = 10247401 }, - { url = "https://files.pythonhosted.org/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", size = 11366360 }, - { url = "https://files.pythonhosted.org/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", size = 10436892 }, + { url = "https://files.pythonhosted.org/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", size = 10049494, upload-time = "2025-03-07T15:26:51.268Z" }, + { url = "https://files.pythonhosted.org/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", size = 10853584, upload-time = "2025-03-07T15:26:56.104Z" }, + { url = "https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", size = 10155692, upload-time = "2025-03-07T15:27:01.385Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", size = 10369760, upload-time = "2025-03-07T15:27:04.023Z" }, + { url = "https://files.pythonhosted.org/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", size = 9912196, upload-time = "2025-03-07T15:27:06.93Z" }, + { url = "https://files.pythonhosted.org/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", size = 11434985, upload-time = "2025-03-07T15:27:10.082Z" }, + { url = "https://files.pythonhosted.org/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", size = 12155842, upload-time = "2025-03-07T15:27:12.727Z" }, + { url = "https://files.pythonhosted.org/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", size = 11613804, upload-time = "2025-03-07T15:27:15.944Z" }, + { url = "https://files.pythonhosted.org/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", size = 13823776, upload-time = "2025-03-07T15:27:18.996Z" }, + { url = "https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", size = 11302673, upload-time = "2025-03-07T15:27:21.655Z" }, + { url = "https://files.pythonhosted.org/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", size = 10235358, upload-time = "2025-03-07T15:27:24.72Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", size = 9886177, upload-time = "2025-03-07T15:27:27.282Z" }, + { url = "https://files.pythonhosted.org/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", size = 10864747, upload-time = "2025-03-07T15:27:30.637Z" }, + { url = "https://files.pythonhosted.org/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", size = 11360441, upload-time = "2025-03-07T15:27:33.356Z" }, + { url = "https://files.pythonhosted.org/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", size = 10247401, upload-time = "2025-03-07T15:27:35.994Z" }, + { url = "https://files.pythonhosted.org/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", size = 11366360, upload-time = "2025-03-07T15:27:38.66Z" }, + { url = "https://files.pythonhosted.org/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", size = 10436892, upload-time = "2025-03-07T15:27:41.687Z" }, ] [[package]] @@ -877,36 +880,36 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/2b/5c9562795c2eb2b5f63536961754760c25bf0f34af93d36aa28dea2fb303/s3transfer-0.11.5.tar.gz", hash = "sha256:8c8aad92784779ab8688a61aefff3e28e9ebdce43142808eaa3f0b0f402f68b7", size = 149107 } +sdist = { url = "https://files.pythonhosted.org/packages/c4/2b/5c9562795c2eb2b5f63536961754760c25bf0f34af93d36aa28dea2fb303/s3transfer-0.11.5.tar.gz", hash = "sha256:8c8aad92784779ab8688a61aefff3e28e9ebdce43142808eaa3f0b0f402f68b7", size = 149107, upload-time = "2025-04-17T19:23:19.051Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/39/13402e323666d17850eca87e4cd6ecfcf9fd7809cac9efdcce10272fc29d/s3transfer-0.11.5-py3-none-any.whl", hash = "sha256:757af0f2ac150d3c75bc4177a32355c3862a98d20447b69a0161812992fe0bd4", size = 84782 }, + { url = "https://files.pythonhosted.org/packages/45/39/13402e323666d17850eca87e4cd6ecfcf9fd7809cac9efdcce10272fc29d/s3transfer-0.11.5-py3-none-any.whl", hash = "sha256:757af0f2ac150d3c75bc4177a32355c3862a98d20447b69a0161812992fe0bd4", size = 84782, upload-time = "2025-04-17T19:23:17.516Z" }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "sniffio" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] [[package]] name = "tomli" version = "2.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/b9/de2a5c0144d7d75a57ff355c0c24054f965b2dc3036456ae03a51ea6264b/tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed", size = 16096 } +sdist = { url = "https://files.pythonhosted.org/packages/35/b9/de2a5c0144d7d75a57ff355c0c24054f965b2dc3036456ae03a51ea6264b/tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed", size = 16096, upload-time = "2024-10-02T10:46:13.208Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/db/ce8eda256fa131af12e0a76d481711abe4681b6923c27efb9a255c9e4594/tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", size = 13237 }, + { url = "https://files.pythonhosted.org/packages/cf/db/ce8eda256fa131af12e0a76d481711abe4681b6923c27efb9a255c9e4594/tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", size = 13237, upload-time = "2024-10-02T10:46:11.806Z" }, ] [[package]] @@ -914,20 +917,29 @@ name = "tqdm" version = "4.67.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[package]] +name = "types-assertpy" +version = "1.1.0.20250502" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/51/98d2bf5a9f3a98a933f0bb598b0905531a3fec81ae7ba97625a46f8d57d4/types_assertpy-1.1.0.20250502.tar.gz", hash = "sha256:7735027f3e63f91a1f3a24819024991358f083a40aceb5dd117e5691e9d4a0de", size = 10387, upload-time = "2025-05-02T03:02:21.096Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, + { url = "https://files.pythonhosted.org/packages/19/15/04ac9cde31889ac1954d5d56fe10d695f6c8fe54ce4a833c5690d327e969/types_assertpy-1.1.0.20250502-py3-none-any.whl", hash = "sha256:dc025f53b74b7bd75ecb830755af10261908c57fb20df38fd42caaca427c5aac", size = 12848, upload-time = "2025-05-02T03:02:19.963Z" }, ] [[package]] name = "typing-extensions" version = "4.12.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321, upload-time = "2024-06-07T18:52:15.995Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438, upload-time = "2024-06-07T18:52:13.582Z" }, ] [[package]] @@ -937,9 +949,9 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.10'", ] -sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380 } +sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380, upload-time = "2024-08-29T15:43:11.37Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225 }, + { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225, upload-time = "2024-08-29T15:43:08.921Z" }, ] [[package]] @@ -949,85 +961,85 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.10'", ] -sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } +sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677, upload-time = "2024-09-12T10:52:18.401Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, + { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338, upload-time = "2024-09-12T10:52:16.589Z" }, ] [[package]] name = "websockets" version = "14.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/54/8359678c726243d19fae38ca14a334e740782336c9f19700858c4eb64a1e/websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5", size = 164394 } +sdist = { url = "https://files.pythonhosted.org/packages/94/54/8359678c726243d19fae38ca14a334e740782336c9f19700858c4eb64a1e/websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5", size = 164394, upload-time = "2025-01-19T21:00:56.431Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/fa/76607eb7dcec27b2d18d63f60a32e60e2b8629780f343bb83a4dbb9f4350/websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885", size = 163089 }, - { url = "https://files.pythonhosted.org/packages/9e/00/ad2246b5030575b79e7af0721810fdaecaf94c4b2625842ef7a756fa06dd/websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397", size = 160741 }, - { url = "https://files.pythonhosted.org/packages/72/f7/60f10924d333a28a1ff3fcdec85acf226281331bdabe9ad74947e1b7fc0a/websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610", size = 160996 }, - { url = "https://files.pythonhosted.org/packages/63/7c/c655789cf78648c01ac6ecbe2d6c18f91b75bdc263ffee4d08ce628d12f0/websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3", size = 169974 }, - { url = "https://files.pythonhosted.org/packages/fb/5b/013ed8b4611857ac92ac631079c08d9715b388bd1d88ec62e245f87a39df/websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980", size = 168985 }, - { url = "https://files.pythonhosted.org/packages/cd/33/aa3e32fd0df213a5a442310754fe3f89dd87a0b8e5b4e11e0991dd3bcc50/websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8", size = 169297 }, - { url = "https://files.pythonhosted.org/packages/93/17/dae0174883d6399f57853ac44abf5f228eaba86d98d160f390ffabc19b6e/websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7", size = 169677 }, - { url = "https://files.pythonhosted.org/packages/42/e2/0375af7ac00169b98647c804651c515054b34977b6c1354f1458e4116c1e/websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f", size = 169089 }, - { url = "https://files.pythonhosted.org/packages/73/8d/80f71d2a351a44b602859af65261d3dde3a0ce4e76cf9383738a949e0cc3/websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d", size = 169026 }, - { url = "https://files.pythonhosted.org/packages/48/97/173b1fa6052223e52bb4054a141433ad74931d94c575e04b654200b98ca4/websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d", size = 163967 }, - { url = "https://files.pythonhosted.org/packages/c0/5b/2fcf60f38252a4562b28b66077e0d2b48f91fef645d5f78874cd1dec807b/websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2", size = 164413 }, - { url = "https://files.pythonhosted.org/packages/15/b6/504695fb9a33df0ca56d157f5985660b5fc5b4bf8c78f121578d2d653392/websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166", size = 163088 }, - { url = "https://files.pythonhosted.org/packages/81/26/ebfb8f6abe963c795122439c6433c4ae1e061aaedfc7eff32d09394afbae/websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f", size = 160745 }, - { url = "https://files.pythonhosted.org/packages/a1/c6/1435ad6f6dcbff80bb95e8986704c3174da8866ddb751184046f5c139ef6/websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910", size = 160995 }, - { url = "https://files.pythonhosted.org/packages/96/63/900c27cfe8be1a1f2433fc77cd46771cf26ba57e6bdc7cf9e63644a61863/websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c", size = 170543 }, - { url = "https://files.pythonhosted.org/packages/00/8b/bec2bdba92af0762d42d4410593c1d7d28e9bfd952c97a3729df603dc6ea/websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473", size = 169546 }, - { url = "https://files.pythonhosted.org/packages/6b/a9/37531cb5b994f12a57dec3da2200ef7aadffef82d888a4c29a0d781568e4/websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473", size = 169911 }, - { url = "https://files.pythonhosted.org/packages/60/d5/a6eadba2ed9f7e65d677fec539ab14a9b83de2b484ab5fe15d3d6d208c28/websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56", size = 170183 }, - { url = "https://files.pythonhosted.org/packages/76/57/a338ccb00d1df881c1d1ee1f2a20c9c1b5b29b51e9e0191ee515d254fea6/websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142", size = 169623 }, - { url = "https://files.pythonhosted.org/packages/64/22/e5f7c33db0cb2c1d03b79fd60d189a1da044e2661f5fd01d629451e1db89/websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d", size = 169583 }, - { url = "https://files.pythonhosted.org/packages/aa/2e/2b4662237060063a22e5fc40d46300a07142afe30302b634b4eebd717c07/websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a", size = 163969 }, - { url = "https://files.pythonhosted.org/packages/94/a5/0cda64e1851e73fc1ecdae6f42487babb06e55cb2f0dc8904b81d8ef6857/websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b", size = 164408 }, - { url = "https://files.pythonhosted.org/packages/c1/81/04f7a397653dc8bec94ddc071f34833e8b99b13ef1a3804c149d59f92c18/websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c", size = 163096 }, - { url = "https://files.pythonhosted.org/packages/ec/c5/de30e88557e4d70988ed4d2eabd73fd3e1e52456b9f3a4e9564d86353b6d/websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967", size = 160758 }, - { url = "https://files.pythonhosted.org/packages/e5/8c/d130d668781f2c77d106c007b6c6c1d9db68239107c41ba109f09e6c218a/websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990", size = 160995 }, - { url = "https://files.pythonhosted.org/packages/a6/bc/f6678a0ff17246df4f06765e22fc9d98d1b11a258cc50c5968b33d6742a1/websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda", size = 170815 }, - { url = "https://files.pythonhosted.org/packages/d8/b2/8070cb970c2e4122a6ef38bc5b203415fd46460e025652e1ee3f2f43a9a3/websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95", size = 169759 }, - { url = "https://files.pythonhosted.org/packages/81/da/72f7caabd94652e6eb7e92ed2d3da818626e70b4f2b15a854ef60bf501ec/websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3", size = 170178 }, - { url = "https://files.pythonhosted.org/packages/31/e0/812725b6deca8afd3a08a2e81b3c4c120c17f68c9b84522a520b816cda58/websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9", size = 170453 }, - { url = "https://files.pythonhosted.org/packages/66/d3/8275dbc231e5ba9bb0c4f93144394b4194402a7a0c8ffaca5307a58ab5e3/websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267", size = 169830 }, - { url = "https://files.pythonhosted.org/packages/a3/ae/e7d1a56755ae15ad5a94e80dd490ad09e345365199600b2629b18ee37bc7/websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe", size = 169824 }, - { url = "https://files.pythonhosted.org/packages/b6/32/88ccdd63cb261e77b882e706108d072e4f1c839ed723bf91a3e1f216bf60/websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205", size = 163981 }, - { url = "https://files.pythonhosted.org/packages/b3/7d/32cdb77990b3bdc34a306e0a0f73a1275221e9a66d869f6ff833c95b56ef/websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce", size = 164421 }, - { url = "https://files.pythonhosted.org/packages/82/94/4f9b55099a4603ac53c2912e1f043d6c49d23e94dd82a9ce1eb554a90215/websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e", size = 163102 }, - { url = "https://files.pythonhosted.org/packages/8e/b7/7484905215627909d9a79ae07070057afe477433fdacb59bf608ce86365a/websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad", size = 160766 }, - { url = "https://files.pythonhosted.org/packages/a3/a4/edb62efc84adb61883c7d2c6ad65181cb087c64252138e12d655989eec05/websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03", size = 160998 }, - { url = "https://files.pythonhosted.org/packages/f5/79/036d320dc894b96af14eac2529967a6fc8b74f03b83c487e7a0e9043d842/websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f", size = 170780 }, - { url = "https://files.pythonhosted.org/packages/63/75/5737d21ee4dd7e4b9d487ee044af24a935e36a9ff1e1419d684feedcba71/websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5", size = 169717 }, - { url = "https://files.pythonhosted.org/packages/2c/3c/bf9b2c396ed86a0b4a92ff4cdaee09753d3ee389be738e92b9bbd0330b64/websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a", size = 170155 }, - { url = "https://files.pythonhosted.org/packages/75/2d/83a5aca7247a655b1da5eb0ee73413abd5c3a57fc8b92915805e6033359d/websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20", size = 170495 }, - { url = "https://files.pythonhosted.org/packages/79/dd/699238a92761e2f943885e091486378813ac8f43e3c84990bc394c2be93e/websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2", size = 169880 }, - { url = "https://files.pythonhosted.org/packages/c8/c9/67a8f08923cf55ce61aadda72089e3ed4353a95a3a4bc8bf42082810e580/websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307", size = 169856 }, - { url = "https://files.pythonhosted.org/packages/17/b1/1ffdb2680c64e9c3921d99db460546194c40d4acbef999a18c37aa4d58a3/websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc", size = 163974 }, - { url = "https://files.pythonhosted.org/packages/14/13/8b7fc4cb551b9cfd9890f0fd66e53c18a06240319915533b033a56a3d520/websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f", size = 164420 }, - { url = "https://files.pythonhosted.org/packages/6f/eb/367e0ed7b8a960b4fc12c7c6bf3ebddf06875037de641637994849560d47/websockets-14.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7cd5706caec1686c5d233bc76243ff64b1c0dc445339bd538f30547e787c11fe", size = 163087 }, - { url = "https://files.pythonhosted.org/packages/96/f7/1f18d028ec4a2c14598dfec6a73381a915c27464b693873198c1de872095/websockets-14.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec607328ce95a2f12b595f7ae4c5d71bf502212bddcea528290b35c286932b12", size = 160740 }, - { url = "https://files.pythonhosted.org/packages/5c/db/b4b353fb9c3f0eaa8138ea4c76e6fa555b6d2821ed2d51d0ac3c320bc57e/websockets-14.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da85651270c6bfb630136423037dd4975199e5d4114cae6d3066641adcc9d1c7", size = 160992 }, - { url = "https://files.pythonhosted.org/packages/b9/b1/9149e420c61f375e432654d5c1545e563b90ac1f829ee1a8d1dccaf0869d/websockets-14.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ecadc7ce90accf39903815697917643f5b7cfb73c96702318a096c00aa71f5", size = 169757 }, - { url = "https://files.pythonhosted.org/packages/2b/33/0bb58204191e113212360f1392b6b1e9f85f62c7ca5b3b15f52f2f835516/websockets-14.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1979bee04af6a78608024bad6dfcc0cc930ce819f9e10342a29a05b5320355d0", size = 168762 }, - { url = "https://files.pythonhosted.org/packages/be/3d/c3c192f16210d7b7535fbf4ee9a299612f4dccff665587617b13fa0a6aa3/websockets-14.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dddacad58e2614a24938a50b85969d56f88e620e3f897b7d80ac0d8a5800258", size = 169060 }, - { url = "https://files.pythonhosted.org/packages/a6/73/75efa8d9e4b1b257818a7b7a0b9ac84a07c91120b52148941370ef2c8f16/websockets-14.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:89a71173caaf75fa71a09a5f614f450ba3ec84ad9fca47cb2422a860676716f0", size = 169457 }, - { url = "https://files.pythonhosted.org/packages/a4/11/300cf36cfd6990ffb218394862f0513be8c21917c9ff5e362f94599caedd/websockets-14.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6af6a4b26eea4fc06c6818a6b962a952441e0e39548b44773502761ded8cc1d4", size = 168860 }, - { url = "https://files.pythonhosted.org/packages/c0/3d/5fd82500714ab7c09f003bde671dad1a3a131ac77b6b11ada72e466de4f6/websockets-14.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:80c8efa38957f20bba0117b48737993643204645e9ec45512579132508477cfc", size = 168825 }, - { url = "https://files.pythonhosted.org/packages/88/16/715580eb6caaacc232f303e9619103a42dcd354b0854baa5ed26aacaf828/websockets-14.2-cp39-cp39-win32.whl", hash = "sha256:2e20c5f517e2163d76e2729104abc42639c41cf91f7b1839295be43302713661", size = 163960 }, - { url = "https://files.pythonhosted.org/packages/63/a7/a1035cb198eaa12eaa9621aaaa3ec021b0e3bac96e1df9ceb6bfe5e53e5f/websockets-14.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4c8cef610e8d7c70dea92e62b6814a8cd24fbd01d7103cc89308d2bfe1659ef", size = 164424 }, - { url = "https://files.pythonhosted.org/packages/10/3d/91d3d2bb1325cd83e8e2c02d0262c7d4426dc8fa0831ef1aa4d6bf2041af/websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29", size = 160773 }, - { url = "https://files.pythonhosted.org/packages/33/7c/cdedadfef7381939577858b1b5718a4ab073adbb584e429dd9d9dc9bfe16/websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c", size = 161007 }, - { url = "https://files.pythonhosted.org/packages/ca/35/7a20a3c450b27c04e50fbbfc3dfb161ed8e827b2a26ae31c4b59b018b8c6/websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2", size = 162264 }, - { url = "https://files.pythonhosted.org/packages/e8/9c/e3f9600564b0c813f2448375cf28b47dc42c514344faed3a05d71fb527f9/websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c", size = 161873 }, - { url = "https://files.pythonhosted.org/packages/3f/37/260f189b16b2b8290d6ae80c9f96d8b34692cf1bb3475df54c38d3deb57d/websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a", size = 161818 }, - { url = "https://files.pythonhosted.org/packages/ff/1e/e47dedac8bf7140e59aa6a679e850c4df9610ae844d71b6015263ddea37b/websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3", size = 164465 }, - { url = "https://files.pythonhosted.org/packages/f7/c0/8e9325c4987dcf66d4a0d63ec380d4aefe8dcc1e521af71ad17adf2c1ae2/websockets-14.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bbe03eb853e17fd5b15448328b4ec7fb2407d45fb0245036d06a3af251f8e48f", size = 160773 }, - { url = "https://files.pythonhosted.org/packages/5a/6e/c9a7f2edd4afddc4f8cccfc4e12468b7f6ec40f28d1b1e966a8d0298b875/websockets-14.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3c4aa3428b904d5404a0ed85f3644d37e2cb25996b7f096d77caeb0e96a3b42", size = 161006 }, - { url = "https://files.pythonhosted.org/packages/f3/10/b90ece894828c954e674a81cb0db250e6c324c54db30a8b19e96431f928f/websockets-14.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a4cebf1ceaf0b65ffc42c54856214165fb8ceeba3935852fc33f6b0c55e7f", size = 162260 }, - { url = "https://files.pythonhosted.org/packages/52/93/1147b6b5464a5fb6e8987da3ec7991dcc44f9090f67d9c841d7382fed429/websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad1c1d02357b7665e700eca43a31d52814ad9ad9b89b58118bdabc365454b574", size = 161868 }, - { url = "https://files.pythonhosted.org/packages/32/ab/f7d80b4049bff0aa617507330db3a27389d0e70df54e29f7a3d76bbd2086/websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f390024a47d904613577df83ba700bd189eedc09c57af0a904e5c39624621270", size = 161813 }, - { url = "https://files.pythonhosted.org/packages/cd/cc/adc9fb85f031b8df8e9f3d96cc004df25d2643e503953af5223c5b6825b7/websockets-14.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3c1426c021c38cf92b453cdf371228d3430acd775edee6bac5a4d577efc72365", size = 164457 }, - { url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416 }, + { url = "https://files.pythonhosted.org/packages/28/fa/76607eb7dcec27b2d18d63f60a32e60e2b8629780f343bb83a4dbb9f4350/websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885", size = 163089, upload-time = "2025-01-19T20:58:43.399Z" }, + { url = "https://files.pythonhosted.org/packages/9e/00/ad2246b5030575b79e7af0721810fdaecaf94c4b2625842ef7a756fa06dd/websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397", size = 160741, upload-time = "2025-01-19T20:58:45.309Z" }, + { url = "https://files.pythonhosted.org/packages/72/f7/60f10924d333a28a1ff3fcdec85acf226281331bdabe9ad74947e1b7fc0a/websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610", size = 160996, upload-time = "2025-01-19T20:58:47.563Z" }, + { url = "https://files.pythonhosted.org/packages/63/7c/c655789cf78648c01ac6ecbe2d6c18f91b75bdc263ffee4d08ce628d12f0/websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3", size = 169974, upload-time = "2025-01-19T20:58:51.023Z" }, + { url = "https://files.pythonhosted.org/packages/fb/5b/013ed8b4611857ac92ac631079c08d9715b388bd1d88ec62e245f87a39df/websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980", size = 168985, upload-time = "2025-01-19T20:58:52.698Z" }, + { url = "https://files.pythonhosted.org/packages/cd/33/aa3e32fd0df213a5a442310754fe3f89dd87a0b8e5b4e11e0991dd3bcc50/websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8", size = 169297, upload-time = "2025-01-19T20:58:54.898Z" }, + { url = "https://files.pythonhosted.org/packages/93/17/dae0174883d6399f57853ac44abf5f228eaba86d98d160f390ffabc19b6e/websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7", size = 169677, upload-time = "2025-01-19T20:58:56.36Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/0375af7ac00169b98647c804651c515054b34977b6c1354f1458e4116c1e/websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f", size = 169089, upload-time = "2025-01-19T20:58:58.824Z" }, + { url = "https://files.pythonhosted.org/packages/73/8d/80f71d2a351a44b602859af65261d3dde3a0ce4e76cf9383738a949e0cc3/websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d", size = 169026, upload-time = "2025-01-19T20:59:01.089Z" }, + { url = "https://files.pythonhosted.org/packages/48/97/173b1fa6052223e52bb4054a141433ad74931d94c575e04b654200b98ca4/websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d", size = 163967, upload-time = "2025-01-19T20:59:02.662Z" }, + { url = "https://files.pythonhosted.org/packages/c0/5b/2fcf60f38252a4562b28b66077e0d2b48f91fef645d5f78874cd1dec807b/websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2", size = 164413, upload-time = "2025-01-19T20:59:05.071Z" }, + { url = "https://files.pythonhosted.org/packages/15/b6/504695fb9a33df0ca56d157f5985660b5fc5b4bf8c78f121578d2d653392/websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166", size = 163088, upload-time = "2025-01-19T20:59:06.435Z" }, + { url = "https://files.pythonhosted.org/packages/81/26/ebfb8f6abe963c795122439c6433c4ae1e061aaedfc7eff32d09394afbae/websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f", size = 160745, upload-time = "2025-01-19T20:59:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c6/1435ad6f6dcbff80bb95e8986704c3174da8866ddb751184046f5c139ef6/websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910", size = 160995, upload-time = "2025-01-19T20:59:12.816Z" }, + { url = "https://files.pythonhosted.org/packages/96/63/900c27cfe8be1a1f2433fc77cd46771cf26ba57e6bdc7cf9e63644a61863/websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c", size = 170543, upload-time = "2025-01-19T20:59:15.026Z" }, + { url = "https://files.pythonhosted.org/packages/00/8b/bec2bdba92af0762d42d4410593c1d7d28e9bfd952c97a3729df603dc6ea/websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473", size = 169546, upload-time = "2025-01-19T20:59:17.156Z" }, + { url = "https://files.pythonhosted.org/packages/6b/a9/37531cb5b994f12a57dec3da2200ef7aadffef82d888a4c29a0d781568e4/websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473", size = 169911, upload-time = "2025-01-19T20:59:18.623Z" }, + { url = "https://files.pythonhosted.org/packages/60/d5/a6eadba2ed9f7e65d677fec539ab14a9b83de2b484ab5fe15d3d6d208c28/websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56", size = 170183, upload-time = "2025-01-19T20:59:20.743Z" }, + { url = "https://files.pythonhosted.org/packages/76/57/a338ccb00d1df881c1d1ee1f2a20c9c1b5b29b51e9e0191ee515d254fea6/websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142", size = 169623, upload-time = "2025-01-19T20:59:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/64/22/e5f7c33db0cb2c1d03b79fd60d189a1da044e2661f5fd01d629451e1db89/websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d", size = 169583, upload-time = "2025-01-19T20:59:23.656Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2e/2b4662237060063a22e5fc40d46300a07142afe30302b634b4eebd717c07/websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a", size = 163969, upload-time = "2025-01-19T20:59:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/94/a5/0cda64e1851e73fc1ecdae6f42487babb06e55cb2f0dc8904b81d8ef6857/websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b", size = 164408, upload-time = "2025-01-19T20:59:28.105Z" }, + { url = "https://files.pythonhosted.org/packages/c1/81/04f7a397653dc8bec94ddc071f34833e8b99b13ef1a3804c149d59f92c18/websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c", size = 163096, upload-time = "2025-01-19T20:59:29.763Z" }, + { url = "https://files.pythonhosted.org/packages/ec/c5/de30e88557e4d70988ed4d2eabd73fd3e1e52456b9f3a4e9564d86353b6d/websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967", size = 160758, upload-time = "2025-01-19T20:59:32.095Z" }, + { url = "https://files.pythonhosted.org/packages/e5/8c/d130d668781f2c77d106c007b6c6c1d9db68239107c41ba109f09e6c218a/websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990", size = 160995, upload-time = "2025-01-19T20:59:33.527Z" }, + { url = "https://files.pythonhosted.org/packages/a6/bc/f6678a0ff17246df4f06765e22fc9d98d1b11a258cc50c5968b33d6742a1/websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda", size = 170815, upload-time = "2025-01-19T20:59:35.837Z" }, + { url = "https://files.pythonhosted.org/packages/d8/b2/8070cb970c2e4122a6ef38bc5b203415fd46460e025652e1ee3f2f43a9a3/websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95", size = 169759, upload-time = "2025-01-19T20:59:38.216Z" }, + { url = "https://files.pythonhosted.org/packages/81/da/72f7caabd94652e6eb7e92ed2d3da818626e70b4f2b15a854ef60bf501ec/websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3", size = 170178, upload-time = "2025-01-19T20:59:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/31/e0/812725b6deca8afd3a08a2e81b3c4c120c17f68c9b84522a520b816cda58/websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9", size = 170453, upload-time = "2025-01-19T20:59:41.996Z" }, + { url = "https://files.pythonhosted.org/packages/66/d3/8275dbc231e5ba9bb0c4f93144394b4194402a7a0c8ffaca5307a58ab5e3/websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267", size = 169830, upload-time = "2025-01-19T20:59:44.669Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ae/e7d1a56755ae15ad5a94e80dd490ad09e345365199600b2629b18ee37bc7/websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe", size = 169824, upload-time = "2025-01-19T20:59:46.932Z" }, + { url = "https://files.pythonhosted.org/packages/b6/32/88ccdd63cb261e77b882e706108d072e4f1c839ed723bf91a3e1f216bf60/websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205", size = 163981, upload-time = "2025-01-19T20:59:49.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/7d/32cdb77990b3bdc34a306e0a0f73a1275221e9a66d869f6ff833c95b56ef/websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce", size = 164421, upload-time = "2025-01-19T20:59:50.674Z" }, + { url = "https://files.pythonhosted.org/packages/82/94/4f9b55099a4603ac53c2912e1f043d6c49d23e94dd82a9ce1eb554a90215/websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e", size = 163102, upload-time = "2025-01-19T20:59:52.177Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b7/7484905215627909d9a79ae07070057afe477433fdacb59bf608ce86365a/websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad", size = 160766, upload-time = "2025-01-19T20:59:54.368Z" }, + { url = "https://files.pythonhosted.org/packages/a3/a4/edb62efc84adb61883c7d2c6ad65181cb087c64252138e12d655989eec05/websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03", size = 160998, upload-time = "2025-01-19T20:59:56.671Z" }, + { url = "https://files.pythonhosted.org/packages/f5/79/036d320dc894b96af14eac2529967a6fc8b74f03b83c487e7a0e9043d842/websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f", size = 170780, upload-time = "2025-01-19T20:59:58.085Z" }, + { url = "https://files.pythonhosted.org/packages/63/75/5737d21ee4dd7e4b9d487ee044af24a935e36a9ff1e1419d684feedcba71/websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5", size = 169717, upload-time = "2025-01-19T20:59:59.545Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3c/bf9b2c396ed86a0b4a92ff4cdaee09753d3ee389be738e92b9bbd0330b64/websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a", size = 170155, upload-time = "2025-01-19T21:00:01.887Z" }, + { url = "https://files.pythonhosted.org/packages/75/2d/83a5aca7247a655b1da5eb0ee73413abd5c3a57fc8b92915805e6033359d/websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20", size = 170495, upload-time = "2025-01-19T21:00:04.064Z" }, + { url = "https://files.pythonhosted.org/packages/79/dd/699238a92761e2f943885e091486378813ac8f43e3c84990bc394c2be93e/websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2", size = 169880, upload-time = "2025-01-19T21:00:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c9/67a8f08923cf55ce61aadda72089e3ed4353a95a3a4bc8bf42082810e580/websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307", size = 169856, upload-time = "2025-01-19T21:00:07.192Z" }, + { url = "https://files.pythonhosted.org/packages/17/b1/1ffdb2680c64e9c3921d99db460546194c40d4acbef999a18c37aa4d58a3/websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc", size = 163974, upload-time = "2025-01-19T21:00:08.698Z" }, + { url = "https://files.pythonhosted.org/packages/14/13/8b7fc4cb551b9cfd9890f0fd66e53c18a06240319915533b033a56a3d520/websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f", size = 164420, upload-time = "2025-01-19T21:00:10.182Z" }, + { url = "https://files.pythonhosted.org/packages/6f/eb/367e0ed7b8a960b4fc12c7c6bf3ebddf06875037de641637994849560d47/websockets-14.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7cd5706caec1686c5d233bc76243ff64b1c0dc445339bd538f30547e787c11fe", size = 163087, upload-time = "2025-01-19T21:00:11.717Z" }, + { url = "https://files.pythonhosted.org/packages/96/f7/1f18d028ec4a2c14598dfec6a73381a915c27464b693873198c1de872095/websockets-14.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec607328ce95a2f12b595f7ae4c5d71bf502212bddcea528290b35c286932b12", size = 160740, upload-time = "2025-01-19T21:00:13.219Z" }, + { url = "https://files.pythonhosted.org/packages/5c/db/b4b353fb9c3f0eaa8138ea4c76e6fa555b6d2821ed2d51d0ac3c320bc57e/websockets-14.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da85651270c6bfb630136423037dd4975199e5d4114cae6d3066641adcc9d1c7", size = 160992, upload-time = "2025-01-19T21:00:15.54Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b1/9149e420c61f375e432654d5c1545e563b90ac1f829ee1a8d1dccaf0869d/websockets-14.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ecadc7ce90accf39903815697917643f5b7cfb73c96702318a096c00aa71f5", size = 169757, upload-time = "2025-01-19T21:00:17.589Z" }, + { url = "https://files.pythonhosted.org/packages/2b/33/0bb58204191e113212360f1392b6b1e9f85f62c7ca5b3b15f52f2f835516/websockets-14.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1979bee04af6a78608024bad6dfcc0cc930ce819f9e10342a29a05b5320355d0", size = 168762, upload-time = "2025-01-19T21:00:19.987Z" }, + { url = "https://files.pythonhosted.org/packages/be/3d/c3c192f16210d7b7535fbf4ee9a299612f4dccff665587617b13fa0a6aa3/websockets-14.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dddacad58e2614a24938a50b85969d56f88e620e3f897b7d80ac0d8a5800258", size = 169060, upload-time = "2025-01-19T21:00:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/a6/73/75efa8d9e4b1b257818a7b7a0b9ac84a07c91120b52148941370ef2c8f16/websockets-14.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:89a71173caaf75fa71a09a5f614f450ba3ec84ad9fca47cb2422a860676716f0", size = 169457, upload-time = "2025-01-19T21:00:22.996Z" }, + { url = "https://files.pythonhosted.org/packages/a4/11/300cf36cfd6990ffb218394862f0513be8c21917c9ff5e362f94599caedd/websockets-14.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6af6a4b26eea4fc06c6818a6b962a952441e0e39548b44773502761ded8cc1d4", size = 168860, upload-time = "2025-01-19T21:00:25.24Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3d/5fd82500714ab7c09f003bde671dad1a3a131ac77b6b11ada72e466de4f6/websockets-14.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:80c8efa38957f20bba0117b48737993643204645e9ec45512579132508477cfc", size = 168825, upload-time = "2025-01-19T21:00:26.799Z" }, + { url = "https://files.pythonhosted.org/packages/88/16/715580eb6caaacc232f303e9619103a42dcd354b0854baa5ed26aacaf828/websockets-14.2-cp39-cp39-win32.whl", hash = "sha256:2e20c5f517e2163d76e2729104abc42639c41cf91f7b1839295be43302713661", size = 163960, upload-time = "2025-01-19T21:00:29.166Z" }, + { url = "https://files.pythonhosted.org/packages/63/a7/a1035cb198eaa12eaa9621aaaa3ec021b0e3bac96e1df9ceb6bfe5e53e5f/websockets-14.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4c8cef610e8d7c70dea92e62b6814a8cd24fbd01d7103cc89308d2bfe1659ef", size = 164424, upload-time = "2025-01-19T21:00:30.614Z" }, + { url = "https://files.pythonhosted.org/packages/10/3d/91d3d2bb1325cd83e8e2c02d0262c7d4426dc8fa0831ef1aa4d6bf2041af/websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29", size = 160773, upload-time = "2025-01-19T21:00:32.225Z" }, + { url = "https://files.pythonhosted.org/packages/33/7c/cdedadfef7381939577858b1b5718a4ab073adbb584e429dd9d9dc9bfe16/websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c", size = 161007, upload-time = "2025-01-19T21:00:33.784Z" }, + { url = "https://files.pythonhosted.org/packages/ca/35/7a20a3c450b27c04e50fbbfc3dfb161ed8e827b2a26ae31c4b59b018b8c6/websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2", size = 162264, upload-time = "2025-01-19T21:00:35.255Z" }, + { url = "https://files.pythonhosted.org/packages/e8/9c/e3f9600564b0c813f2448375cf28b47dc42c514344faed3a05d71fb527f9/websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c", size = 161873, upload-time = "2025-01-19T21:00:37.377Z" }, + { url = "https://files.pythonhosted.org/packages/3f/37/260f189b16b2b8290d6ae80c9f96d8b34692cf1bb3475df54c38d3deb57d/websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a", size = 161818, upload-time = "2025-01-19T21:00:38.952Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1e/e47dedac8bf7140e59aa6a679e850c4df9610ae844d71b6015263ddea37b/websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3", size = 164465, upload-time = "2025-01-19T21:00:40.456Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c0/8e9325c4987dcf66d4a0d63ec380d4aefe8dcc1e521af71ad17adf2c1ae2/websockets-14.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bbe03eb853e17fd5b15448328b4ec7fb2407d45fb0245036d06a3af251f8e48f", size = 160773, upload-time = "2025-01-19T21:00:42.145Z" }, + { url = "https://files.pythonhosted.org/packages/5a/6e/c9a7f2edd4afddc4f8cccfc4e12468b7f6ec40f28d1b1e966a8d0298b875/websockets-14.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3c4aa3428b904d5404a0ed85f3644d37e2cb25996b7f096d77caeb0e96a3b42", size = 161006, upload-time = "2025-01-19T21:00:43.72Z" }, + { url = "https://files.pythonhosted.org/packages/f3/10/b90ece894828c954e674a81cb0db250e6c324c54db30a8b19e96431f928f/websockets-14.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a4cebf1ceaf0b65ffc42c54856214165fb8ceeba3935852fc33f6b0c55e7f", size = 162260, upload-time = "2025-01-19T21:00:46.33Z" }, + { url = "https://files.pythonhosted.org/packages/52/93/1147b6b5464a5fb6e8987da3ec7991dcc44f9090f67d9c841d7382fed429/websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad1c1d02357b7665e700eca43a31d52814ad9ad9b89b58118bdabc365454b574", size = 161868, upload-time = "2025-01-19T21:00:48.683Z" }, + { url = "https://files.pythonhosted.org/packages/32/ab/f7d80b4049bff0aa617507330db3a27389d0e70df54e29f7a3d76bbd2086/websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f390024a47d904613577df83ba700bd189eedc09c57af0a904e5c39624621270", size = 161813, upload-time = "2025-01-19T21:00:51.019Z" }, + { url = "https://files.pythonhosted.org/packages/cd/cc/adc9fb85f031b8df8e9f3d96cc004df25d2643e503953af5223c5b6825b7/websockets-14.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3c1426c021c38cf92b453cdf371228d3430acd775edee6bac5a4d577efc72365", size = 164457, upload-time = "2025-01-19T21:00:52.621Z" }, + { url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416, upload-time = "2025-01-19T21:00:54.843Z" }, ] [[package]] @@ -1037,16 +1049,16 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/f9/0ba83eaa0df9b9e9d1efeb2ea351d0677c37d41ee5d0f91e98423c7281c9/werkzeug-3.0.6.tar.gz", hash = "sha256:a8dd59d4de28ca70471a34cba79bed5f7ef2e036a76b3ab0835474246eb41f8d", size = 805170 } +sdist = { url = "https://files.pythonhosted.org/packages/d4/f9/0ba83eaa0df9b9e9d1efeb2ea351d0677c37d41ee5d0f91e98423c7281c9/werkzeug-3.0.6.tar.gz", hash = "sha256:a8dd59d4de28ca70471a34cba79bed5f7ef2e036a76b3ab0835474246eb41f8d", size = 805170, upload-time = "2024-10-25T18:52:31.688Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl", hash = "sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17", size = 227979 }, + { url = "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl", hash = "sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17", size = 227979, upload-time = "2024-10-25T18:52:30.129Z" }, ] [[package]] name = "zipp" version = "3.20.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199 } +sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199, upload-time = "2024-09-13T13:44:16.101Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", size = 9200 }, + { url = "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", size = 9200, upload-time = "2024-09-13T13:44:14.38Z" }, ] diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index 3363efbd39..03432258b4 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -59,20 +59,20 @@ const ErrorCount: React.FC = () => { const { errors, warnings } = useAtomValue(numErrorsAtom) if (errors === 0 && warnings === 0) { return ( -
+
) } if (errors === 0) { return ( -
+
{warnings}
) } return ( -
+
{errors} {warnings} {' '}
) @@ -112,6 +112,27 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre }, [selectedFunc]) console.log('selectedFunc', selectedFunc) + useEffect(() => { + const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' + const ws = new WebSocket(`${scheme}://${window.location.host}/ws`) + + ws.onopen = () => console.log('WebSocket connected') + ws.onmessage = (e) => { + console.log('message!') + try { + const payload = JSON.parse(e.data) + window.postMessage(payload, '*') + } catch (err) { + console.error('invalid WS payload', err) + } + } + ws.onclose = () => console.log('WebSocket disconnected') + + return () => ws.close() + }, []) + + console.log('Websocket execution finished') + useEffect(() => { console.log('adding event listener') const fn = ( @@ -254,11 +275,11 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre return ( <> -
-
{bamlCliVersion && 'baml-cli ' + bamlCliVersion}
- VSCode Runtime Version: {version} +
+
{bamlCliVersion && 'baml-cli ' + bamlCliVersion}
+ VSCode Runtime Version: {version}
- {children} + {children} ) } From ce37d10ca409e3183703c46534d6b837dd2090ca Mon Sep 17 00:00:00 2001 From: egol Date: Mon, 9 Jun 2025 22:09:25 -0700 Subject: [PATCH 02/71] rust talking to frontend --- bundle-hello-world/clients.baml | 41 +++ bundle-hello-world/receipt.baml | 61 +++++ bundle-hello-world/src/file_watcher.rs | 74 ++++++ bundle-hello-world/src/main.rs | 292 +++++++++++++++++---- bundle-hello-world/target/.rustc_info.json | 2 +- 5 files changed, 419 insertions(+), 51 deletions(-) create mode 100644 bundle-hello-world/clients.baml create mode 100644 bundle-hello-world/receipt.baml create mode 100644 bundle-hello-world/src/file_watcher.rs diff --git a/bundle-hello-world/clients.baml b/bundle-hello-world/clients.baml new file mode 100644 index 0000000000..2d45afc2e9 --- /dev/null +++ b/bundle-hello-world/clients.baml @@ -0,0 +1,41 @@ +// These are LLM clients you can use in your functions. We currently support Anthropic, OpenAI / Azure, Gemini, and Ollama as providers. + +// We also support any other provider that follows the OpenAI API specification, such as HuggingFace. + +// For this playground, we have setup a few clients for you to use already with some free credits. + +client GPT4 { + // Use one of the following: https://docs.boundaryml.com/docs/snippets/clients/providers/openai + provider openai + // You can pass in any parameters from the OpenAI Python documentation into the options block. + options { + model gpt-4 + api_key env.OPENAI_API_KEY + } +} + +client GPT4o { + provider openai + options { + model gpt-4o + api_key env.OPENAI_API_KEY + } +} + +client Claude { + provider anthropic + options { + model claude-3-haiku-20240307 + api_key env.ANTHROPIC_API_KEY + max_tokens 1000 + + } +} + +client Gemini { + provider google-ai + options { + model "gemini-1.5-pro-001" + api_key env.GOOGLE_API_KEY + } +} diff --git a/bundle-hello-world/receipt.baml b/bundle-hello-world/receipt.baml new file mode 100644 index 0000000000..0c2622efd4 --- /dev/null +++ b/bundle-hello-world/receipt.baml @@ -0,0 +1,61 @@ +// https://docs.boundaryml.com + +// We want the LLM to extract this info from an image receipt +class Receipt { + establishment_name string + date string @description("ISO8601 formatted date") + total int @description("The total amount of the receipt") + currency string + items Item[] @description("The items on the receipt") +} + +class Item { + name string + price float + quantity int @description("If not specified, assume 1") +} + +// This is our LLM function we can call in Python or Typescript +// the receipt can be an image OR text here! +function ExtractReceipt(receipt: image | string) -> Receipt { + // see clients.baml + client GPT4o + prompt #" + {# start a user message #} + {{ _.role("user") }} + + Extract info from this receipt: + {{ receipt }} + + {# special macro to print the output schema instructions. #} + {{ ctx.output_format }} + "# +} + +// Test when the input is an image +test ImageReceiptTest { + functions [ExtractReceipt] + args { + receipt { url "https://i.redd.it/adzt4bz4llfc1.jpeg"} + } +} + +// Test when the input is a string +test StarbucksTextReceiptTest { + functions [ExtractReceipt] + args { + // use #""# for multi-line strings + receipt #" + Starbucks + Date: 2022-01-01 + Total: $5.00 USD + Items: + - Coffee + - $2.50 + - 1 + - Croissant + - $2.50 + - 1 + "# + } +} diff --git a/bundle-hello-world/src/file_watcher.rs b/bundle-hello-world/src/file_watcher.rs new file mode 100644 index 0000000000..a3413ac82a --- /dev/null +++ b/bundle-hello-world/src/file_watcher.rs @@ -0,0 +1,74 @@ +use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; +use serde_json::json; +use std::{path::Path, sync::Arc}; +use tokio::sync::broadcast; + +pub struct FileWatcher { + tx: broadcast::Sender, +} + +impl FileWatcher { + pub fn new(tx: broadcast::Sender) -> Self { + Self { tx } + } + + pub fn watch(&self, path: &Path) -> notify::Result<()> { + let tx = self.tx.clone(); + let path = Arc::new(path.to_path_buf()); + + let mut watcher = RecommendedWatcher::new( + move |res: Result| { + if let Ok(event) = res { + for path in event.paths { + if !path.extension().map_or(false, |ext| ext == "baml") { + continue; + } + + match event.kind { + EventKind::Create(_) | EventKind::Modify(_) => { + if let Ok(content) = std::fs::read_to_string(&path) { + let parent = + path.parent().and_then(|p| p.to_str()).unwrap_or("."); + + let filename = path + .file_name() + .and_then(|f| f.to_str()) + .unwrap_or("unknown.baml"); + + let payload = json!({ + "command": "add_project", + "content": { + "root_path": parent, + "files": { + filename: content + } + } + }); + + let _ = tx.send(payload.to_string()); + } + } + EventKind::Remove(_) => { + let parent = path.parent().and_then(|p| p.to_str()).unwrap_or("."); + + let payload = json!({ + "command": "remove_project", + "content": { + "root_path": parent + } + }); + + let _ = tx.send(payload.to_string()); + } + _ => {} + } + } + } + }, + Config::default().with_poll_interval(std::time::Duration::from_secs(1)), + )?; + + watcher.watch(path.as_ref(), RecursiveMode::Recursive)?; + Ok(()) + } +} diff --git a/bundle-hello-world/src/main.rs b/bundle-hello-world/src/main.rs index 5a5689fe84..0f4662ade3 100644 --- a/bundle-hello-world/src/main.rs +++ b/bundle-hello-world/src/main.rs @@ -2,8 +2,13 @@ use futures_util::{SinkExt, StreamExt}; use include_dir::{Dir, include_dir}; use mime_guess::from_path; -use serde::Serialize; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fs; +use std::path::PathBuf; +use std::sync::Arc; use std::{convert::Infallible, ops::Range}; +use tokio::sync::RwLock; use tokio::sync::broadcast; use warp::{ Filter, @@ -14,39 +19,253 @@ use warp::{ /// Embed at compile time everything in dist/ static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); -#[derive(Serialize)] -struct Hello { - message: &'static str, +#[derive(Serialize, Deserialize, Debug)] +struct Span { + file_path: String, + start_line: u32, + start: u32, + end_line: u32, + end: u32, } -/// Handle a new WebSocket client: forward every broadcasted String as a text frame. -async fn client_connection(ws: WebSocket, mut rx: broadcast::Receiver) { - let (mut tx, mut _rx) = ws.split(); - // Spawn a task that listens on the broadcast channel... - tokio::spawn(async move { - while let Ok(json_msg) = rx.recv().await { - if tx.send(Message::text(json_msg)).await.is_err() { - // client disconnected - break; +#[derive(Serialize, Deserialize, Debug)] +struct CursorPosition { + file_name: String, + file_text: String, + line: u32, + column: u32, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "command", content = "content")] +enum FrontendMessage { + AddProject { + root_path: String, + files: HashMap, + }, + ModifyFile { + root_path: String, + name: String, + content: Option, + }, + RemoveProject { + root_path: String, + }, + SetFlashingRegions { + spans: Vec, + }, + SelectFunction { + root_path: String, + function_name: String, + }, + UpdateCursor { + cursor: CursorPosition, + }, + BamlSettingsUpdated { + // Add BAML settings fields as needed + settings: HashMap, + }, + RunTest { + test_name: String, + }, +} + +#[derive(Serialize, Deserialize, Debug)] +struct Diagnostic { + file_path: String, + start_line: u32, + start: u32, + end_line: u32, + end: u32, + message: String, + severity: String, +} + +struct BamlState { + files: HashMap, + current_function: Option, + diagnostics: Vec, +} + +impl BamlState { + fn new() -> Self { + Self { + files: HashMap::new(), + current_function: None, + diagnostics: Vec::new(), + } + } + + fn load_baml_files(&mut self) -> Result<(), Box> { + // Load receipt.baml + let receipt_content = fs::read_to_string("receipt.baml")?; + self.files + .insert("receipt.baml".to_string(), receipt_content); + + // Load clients.baml + let clients_content = fs::read_to_string("clients.baml")?; + self.files + .insert("clients.baml".to_string(), clients_content); + + Ok(()) + } +} + +async fn handle_ws_message( + msg: String, + state: Arc>, + tx: broadcast::Sender, +) -> Result<(), Box> { + let message: FrontendMessage = serde_json::from_str(&msg)?; + + match message { + FrontendMessage::AddProject { root_path, files } => { + let mut state = state.write().await; + state.files = files; + + // Process BAML files + if let Some(baml_content) = state.files.get("receipt.baml") { + // TODO: Parse BAML and validate + // TODO: Update diagnostics + // TODO: Send updates to frontend + } + } + FrontendMessage::ModifyFile { + root_path, + name, + content, + } => { + let mut state = state.write().await; + if let Some(content) = content { + state.files.insert(name, content); + // TODO: Revalidate BAML + // TODO: Update diagnostics + // TODO: Send updates to frontend } } + FrontendMessage::RemoveProject { root_path } => { + let mut state = state.write().await; + state.files.clear(); + state.current_function = None; + state.diagnostics.clear(); + } + FrontendMessage::SetFlashingRegions { spans } => { + // TODO: Handle flashing regions + } + FrontendMessage::SelectFunction { + root_path, + function_name, + } => { + let mut state = state.write().await; + state.current_function = Some(function_name); + } + FrontendMessage::UpdateCursor { cursor } => { + // TODO: Handle cursor updates + } + FrontendMessage::BamlSettingsUpdated { settings } => { + // TODO: Handle settings updates + } + FrontendMessage::RunTest { test_name } => { + // TODO: Handle test execution + } + } + + Ok(()) +} + +async fn client_connection( + ws: warp::ws::WebSocket, + state: Arc>, + tx: broadcast::Sender, +) { + let (mut ws_tx, mut ws_rx) = ws.split(); + let mut rx = tx.subscribe(); + + // Load BAML files and send initial state + { + let mut state = state.write().await; + if let Err(e) = state.load_baml_files() { + eprintln!("Error loading BAML files: {}", e); + } + } + + // Send initial port number + let port_msg = serde_json::json!({ + "command": "port_number", + "content": { + "port": 3030 + } + }); + let _ = ws_tx.send(Message::text(port_msg.to_string())).await; + + // Send initial project state + let state_read = state.read().await; + let add_project_msg = serde_json::json!({ + "command": "add_project", + "content": { + "root_path": ".", + "files": state_read.files + } }); - // (Optionally) you can also read from `_rx` if clients send you messages. + let _ = ws_tx.send(Message::text(add_project_msg.to_string())).await; + + // Handle incoming messages + let state_clone = state.clone(); + let tx_clone = tx.clone(); + let handle_incoming = async move { + while let Some(result) = ws_rx.next().await { + match result { + Ok(msg) => { + if let Ok(text) = msg.to_str() { + if let Err(e) = handle_ws_message( + text.to_string(), + state_clone.clone(), + tx_clone.clone(), + ) + .await + { + eprintln!("Error handling message: {}", e); + } + } + } + Err(e) => { + eprintln!("WebSocket error: {}", e); + break; + } + } + } + }; + + // Handle outgoing messages + let handle_outgoing = async move { + while let Ok(msg) = rx.recv().await { + if ws_tx.send(Message::text(msg)).await.is_err() { + break; + } + } + }; + + tokio::select! { + _ = handle_incoming => {}, + _ = handle_outgoing => {}, + } } #[tokio::main] async fn main() { - // 1) Create a broadcast channel for JSON‐payloads let (tx, _rx) = broadcast::channel::(16); + let state = Arc::new(RwLock::new(BamlState::new())); - // 2) Simple API route - let api = warp::path!("api" / "hello").map(|| { - warp::reply::json(&Hello { - message: "Hello from Rust!", - }) - }); + // WebSocket handler + let ws_route = warp::path("ws") + .and(warp::ws()) + .map(move |ws: warp::ws::Ws| { + let tx = tx.clone(); + let state = state.clone(); + ws.on_upgrade(move |socket| client_connection(socket, state, tx)) + }); - // 3) Static‐file SPA handler + // Static file serving let spa = warp::path::full() .and(warp::get()) @@ -67,35 +286,8 @@ async fn main() { } }); - // 4) WebSocket route at /ws - let tx_ws = tx.clone(); - let ws_route = warp::path("ws") - .and(warp::ws()) - .map(move |ws: warp::ws::Ws| { - let rx = tx_ws.subscribe(); - ws.on_upgrade(move |socket| client_connection(socket, rx)) - }); - - // 5) Combine all routes - let routes = ws_route.or(api).or(spa).with(warp::log("bundle-server")); - - // 6) Example: after 5 seconds, broadcast a demo message - let demo_tx = tx.clone(); - tokio::spawn(async move { - for _i in 0..100 { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - let payload = serde_json::json!({ - "command": "add_project", - "content": { - "root_path": "/foo/bar", - "files": { "main.baml": "class Receipt {}" } - } - }); - let _ = demo_tx.send(payload.to_string()); - } - }); + let routes = ws_route.or(spa).with(warp::log("bundle-server")); - // 7) Launch the server println!("Listening on http://localhost:3030 …"); warp::serve(routes).run(([127, 0, 0, 1], 3030)).await; } diff --git a/bundle-hello-world/target/.rustc_info.json b/bundle-hello-world/target/.rustc_info.json index cf06391425..fb773a3714 100644 --- a/bundle-hello-world/target/.rustc_info.json +++ b/bundle-hello-world/target/.rustc_info.json @@ -1 +1 @@ -{"rustc_fingerprint":15275327620044501057,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.87.0 (17067e9ac 2025-05-09)\nbinary: rustc\ncommit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359\ncommit-date: 2025-05-09\nhost: aarch64-apple-darwin\nrelease: 1.87.0\nLLVM version: 20.1.1\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/egor/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""}},"successes":{}} \ No newline at end of file +{"rustc_fingerprint":15275327620044501057,"outputs":{"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/egor/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.87.0 (17067e9ac 2025-05-09)\nbinary: rustc\ncommit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359\ncommit-date: 2025-05-09\nhost: aarch64-apple-darwin\nrelease: 1.87.0\nLLVM version: 20.1.1\n","stderr":""}},"successes":{}} \ No newline at end of file From 2462fd781aae9fced2c42f02da07be1bdee95fd1 Mon Sep 17 00:00:00 2001 From: egol Date: Mon, 9 Jun 2025 22:34:23 -0700 Subject: [PATCH 03/71] cleaned up code --- bundle-hello-world/Cargo.toml | 1 + bundle-hello-world/src/main.rs | 128 +-------------------------------- 2 files changed, 4 insertions(+), 125 deletions(-) diff --git a/bundle-hello-world/Cargo.toml b/bundle-hello-world/Cargo.toml index 59e71968d7..3317a14fa6 100644 --- a/bundle-hello-world/Cargo.toml +++ b/bundle-hello-world/Cargo.toml @@ -12,3 +12,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tokio-stream = { version = "0.1", features = ["sync"] } futures-util = "0.3" +dotenv = "0.15" diff --git a/bundle-hello-world/src/main.rs b/bundle-hello-world/src/main.rs index 0f4662ade3..f5088c5048 100644 --- a/bundle-hello-world/src/main.rs +++ b/bundle-hello-world/src/main.rs @@ -1,15 +1,12 @@ -// src/main.rs use futures_util::{SinkExt, StreamExt}; use include_dir::{Dir, include_dir}; use mime_guess::from_path; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::convert::Infallible; use std::fs; -use std::path::PathBuf; use std::sync::Arc; -use std::{convert::Infallible, ops::Range}; use tokio::sync::RwLock; -use tokio::sync::broadcast; use warp::{ Filter, http::Response, @@ -111,75 +108,8 @@ impl BamlState { } } -async fn handle_ws_message( - msg: String, - state: Arc>, - tx: broadcast::Sender, -) -> Result<(), Box> { - let message: FrontendMessage = serde_json::from_str(&msg)?; - - match message { - FrontendMessage::AddProject { root_path, files } => { - let mut state = state.write().await; - state.files = files; - - // Process BAML files - if let Some(baml_content) = state.files.get("receipt.baml") { - // TODO: Parse BAML and validate - // TODO: Update diagnostics - // TODO: Send updates to frontend - } - } - FrontendMessage::ModifyFile { - root_path, - name, - content, - } => { - let mut state = state.write().await; - if let Some(content) = content { - state.files.insert(name, content); - // TODO: Revalidate BAML - // TODO: Update diagnostics - // TODO: Send updates to frontend - } - } - FrontendMessage::RemoveProject { root_path } => { - let mut state = state.write().await; - state.files.clear(); - state.current_function = None; - state.diagnostics.clear(); - } - FrontendMessage::SetFlashingRegions { spans } => { - // TODO: Handle flashing regions - } - FrontendMessage::SelectFunction { - root_path, - function_name, - } => { - let mut state = state.write().await; - state.current_function = Some(function_name); - } - FrontendMessage::UpdateCursor { cursor } => { - // TODO: Handle cursor updates - } - FrontendMessage::BamlSettingsUpdated { settings } => { - // TODO: Handle settings updates - } - FrontendMessage::RunTest { test_name } => { - // TODO: Handle test execution - } - } - - Ok(()) -} - -async fn client_connection( - ws: warp::ws::WebSocket, - state: Arc>, - tx: broadcast::Sender, -) { +async fn client_connection(ws: warp::ws::WebSocket, state: Arc>) { let (mut ws_tx, mut ws_rx) = ws.split(); - let mut rx = tx.subscribe(); // Load BAML files and send initial state { @@ -189,15 +119,6 @@ async fn client_connection( } } - // Send initial port number - let port_msg = serde_json::json!({ - "command": "port_number", - "content": { - "port": 3030 - } - }); - let _ = ws_tx.send(Message::text(port_msg.to_string())).await; - // Send initial project state let state_read = state.read().await; let add_project_msg = serde_json::json!({ @@ -208,61 +129,18 @@ async fn client_connection( } }); let _ = ws_tx.send(Message::text(add_project_msg.to_string())).await; - - // Handle incoming messages - let state_clone = state.clone(); - let tx_clone = tx.clone(); - let handle_incoming = async move { - while let Some(result) = ws_rx.next().await { - match result { - Ok(msg) => { - if let Ok(text) = msg.to_str() { - if let Err(e) = handle_ws_message( - text.to_string(), - state_clone.clone(), - tx_clone.clone(), - ) - .await - { - eprintln!("Error handling message: {}", e); - } - } - } - Err(e) => { - eprintln!("WebSocket error: {}", e); - break; - } - } - } - }; - - // Handle outgoing messages - let handle_outgoing = async move { - while let Ok(msg) = rx.recv().await { - if ws_tx.send(Message::text(msg)).await.is_err() { - break; - } - } - }; - - tokio::select! { - _ = handle_incoming => {}, - _ = handle_outgoing => {}, - } } #[tokio::main] async fn main() { - let (tx, _rx) = broadcast::channel::(16); let state = Arc::new(RwLock::new(BamlState::new())); // WebSocket handler let ws_route = warp::path("ws") .and(warp::ws()) .map(move |ws: warp::ws::Ws| { - let tx = tx.clone(); let state = state.clone(); - ws.on_upgrade(move |socket| client_connection(socket, state, tx)) + ws.on_upgrade(move |socket| client_connection(socket, state)) }); // Static file serving From 6c663e2887da5b9ff315227db9996e8f60efdcb9 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 10 Jun 2025 10:59:42 -0700 Subject: [PATCH 04/71] add basic file watching for saved files --- bundle-hello-world/Cargo.toml | 1 + bundle-hello-world/src/file_watcher.rs | 99 +++++++---------- bundle-hello-world/src/main.rs | 103 ++++++++++++------ .../src/baml_wasm_web/EventListener.tsx | 22 ++-- 4 files changed, 117 insertions(+), 108 deletions(-) diff --git a/bundle-hello-world/Cargo.toml b/bundle-hello-world/Cargo.toml index 3317a14fa6..0fd2370ab0 100644 --- a/bundle-hello-world/Cargo.toml +++ b/bundle-hello-world/Cargo.toml @@ -13,3 +13,4 @@ serde_json = "1.0" tokio-stream = { version = "0.1", features = ["sync"] } futures-util = "0.3" dotenv = "0.15" +notify = "6.1" diff --git a/bundle-hello-world/src/file_watcher.rs b/bundle-hello-world/src/file_watcher.rs index a3413ac82a..047db8e2dc 100644 --- a/bundle-hello-world/src/file_watcher.rs +++ b/bundle-hello-world/src/file_watcher.rs @@ -1,74 +1,53 @@ +use notify::event::DataChange; use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; -use serde_json::json; -use std::{path::Path, sync::Arc}; -use tokio::sync::broadcast; +use std::path::Path; +use std::sync::mpsc::channel; +use std::time::Duration; pub struct FileWatcher { - tx: broadcast::Sender, + path: String, } impl FileWatcher { - pub fn new(tx: broadcast::Sender) -> Self { - Self { tx } + pub fn new(path: &str) -> Result { + Ok(Self { + path: path.to_string(), + }) } - pub fn watch(&self, path: &Path) -> notify::Result<()> { - let tx = self.tx.clone(); - let path = Arc::new(path.to_path_buf()); - - let mut watcher = RecommendedWatcher::new( - move |res: Result| { - if let Ok(event) = res { - for path in event.paths { - if !path.extension().map_or(false, |ext| ext == "baml") { - continue; - } - - match event.kind { - EventKind::Create(_) | EventKind::Modify(_) => { - if let Ok(content) = std::fs::read_to_string(&path) { - let parent = - path.parent().and_then(|p| p.to_str()).unwrap_or("."); - - let filename = path - .file_name() - .and_then(|f| f.to_str()) - .unwrap_or("unknown.baml"); - - let payload = json!({ - "command": "add_project", - "content": { - "root_path": parent, - "files": { - filename: content - } - } - }); - - let _ = tx.send(payload.to_string()); - } - } - EventKind::Remove(_) => { - let parent = path.parent().and_then(|p| p.to_str()).unwrap_or("."); - - let payload = json!({ - "command": "remove_project", - "content": { - "root_path": parent - } - }); - - let _ = tx.send(payload.to_string()); - } - _ => {} - } + pub fn watch(&self, mut callback: F) -> Result<(), notify::Error> + where + F: FnMut(&str) + Send + 'static, + { + let path = self.path.clone(); + std::thread::spawn(move || { + let (tx, rx) = channel(); + let mut watcher = RecommendedWatcher::new( + move |res: Result| { + if let Ok(event) = res { + tx.send(event).unwrap(); + } + }, + Config::default() + .with_poll_interval(Duration::from_secs(1)) + .with_compare_contents(true), + ) + .unwrap(); + + watcher + .watch(Path::new(&path), RecursiveMode::NonRecursive) + .unwrap(); + + for event in rx { + // Only trigger on actual content changes, not metadata changes + if let EventKind::Modify(kind) = event.kind { + if kind == notify::event::ModifyKind::Data(DataChange::Content) { + callback(&path); } } - }, - Config::default().with_poll_interval(std::time::Duration::from_secs(1)), - )?; + } + }); - watcher.watch(path.as_ref(), RecursiveMode::Recursive)?; Ok(()) } } diff --git a/bundle-hello-world/src/main.rs b/bundle-hello-world/src/main.rs index f5088c5048..98d9a27d45 100644 --- a/bundle-hello-world/src/main.rs +++ b/bundle-hello-world/src/main.rs @@ -1,3 +1,4 @@ +use crate::file_watcher::FileWatcher; use futures_util::{SinkExt, StreamExt}; use include_dir::{Dir, include_dir}; use mime_guess::from_path; @@ -7,11 +8,10 @@ use std::convert::Infallible; use std::fs; use std::sync::Arc; use tokio::sync::RwLock; -use warp::{ - Filter, - http::Response, - ws::{Message, WebSocket}, -}; +use tokio::sync::broadcast; +use warp::{Filter, http::Response, ws::Message}; + +mod file_watcher; /// Embed at compile time everything in dist/ static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); @@ -36,35 +36,26 @@ struct CursorPosition { #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "command", content = "content")] enum FrontendMessage { + #[serde(rename = "add_project")] AddProject { root_path: String, files: HashMap, }, - ModifyFile { - root_path: String, - name: String, - content: Option, - }, - RemoveProject { - root_path: String, - }, - SetFlashingRegions { - spans: Vec, - }, + #[serde(rename = "remove_project")] + RemoveProject { root_path: String }, + #[serde(rename = "set_flashing_regions")] + SetFlashingRegions { spans: Vec }, + #[serde(rename = "select_function")] SelectFunction { root_path: String, function_name: String, }, - UpdateCursor { - cursor: CursorPosition, - }, - BamlSettingsUpdated { - // Add BAML settings fields as needed - settings: HashMap, - }, - RunTest { - test_name: String, - }, + #[serde(rename = "update_cursor")] + UpdateCursor { cursor: CursorPosition }, + #[serde(rename = "baml_settings_updated")] + BamlSettingsUpdated { settings: HashMap }, + #[serde(rename = "run_test")] + RunTest { test_name: String }, } #[derive(Serialize, Deserialize, Debug)] @@ -82,14 +73,17 @@ struct BamlState { files: HashMap, current_function: Option, diagnostics: Vec, + tx: broadcast::Sender, } impl BamlState { fn new() -> Self { + let (tx, _) = broadcast::channel(100); Self { files: HashMap::new(), current_function: None, diagnostics: Vec::new(), + tx, } } @@ -110,6 +104,10 @@ impl BamlState { async fn client_connection(ws: warp::ws::WebSocket, state: Arc>) { let (mut ws_tx, mut ws_rx) = ws.split(); + let mut rx = { + let state = state.read().await; + state.tx.subscribe() + }; // Load BAML files and send initial state { @@ -119,22 +117,61 @@ async fn client_connection(ws: warp::ws::WebSocket, state: Arc } } - // Send initial project state + // Send initial project state (currently to the root folder of where the script is called) let state_read = state.read().await; - let add_project_msg = serde_json::json!({ - "command": "add_project", - "content": { - "root_path": ".", - "files": state_read.files + let add_project_msg = FrontendMessage::AddProject { + root_path: ".".to_string(), + files: state_read.files.clone(), + }; + // Send the add project message to the client + let _ = ws_tx + .send(Message::text( + serde_json::to_string(&add_project_msg).unwrap(), + )) + .await; + + // Forward broadcast messages to this client + // Ensures realtime updates on the UI + tokio::spawn(async move { + while let Ok(msg) = rx.recv().await { + let _ = ws_tx.send(Message::text(msg)).await; } }); - let _ = ws_tx.send(Message::text(add_project_msg.to_string())).await; } #[tokio::main] async fn main() { let state = Arc::new(RwLock::new(BamlState::new())); + // Set up file watchers for .baml files + let baml_files = ["receipt.baml", "clients.baml"]; + for file in baml_files { + if let Ok(watcher) = FileWatcher::new(file) { + let state_clone = state.clone(); + watcher + .watch(move |path| { + println!("BAML file changed: {}", path); + // Reload the file and update state + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let mut state = state_clone.write().await; + if let Ok(content) = fs::read_to_string(path) { + state.files.insert(path.to_string(), content); + + // Notify all clients about the file change + let add_project_msg = FrontendMessage::AddProject { + root_path: ".".to_string(), + files: state.files.clone(), + }; + let msg_str = serde_json::to_string(&add_project_msg).unwrap(); + let _ = state.tx.send(msg_str); + } + }); + }) + .unwrap(); + } + } + // WebSocket handler let ws_route = warp::path("ws") .and(warp::ws()) diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index 03432258b4..7832d81882 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -59,20 +59,20 @@ const ErrorCount: React.FC = () => { const { errors, warnings } = useAtomValue(numErrorsAtom) if (errors === 0 && warnings === 0) { return ( -
+
) } if (errors === 0) { return ( -
+
{warnings}
) } return ( -
+
{errors} {warnings} {' '}
) @@ -137,14 +137,6 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre console.log('adding event listener') const fn = ( event: MessageEvent< - | { - command: 'modify_file' - content: { - root_path: string - name: string - content: string | undefined - } - } | { command: 'add_project' content: { @@ -275,11 +267,11 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre return ( <> -
-
{bamlCliVersion && 'baml-cli ' + bamlCliVersion}
- VSCode Runtime Version: {version} +
+
{bamlCliVersion && 'baml-cli ' + bamlCliVersion}
+ VSCode Runtime Version: {version}
- {children} + {children} ) } From 0a732301174e7160a5009ba9da800135f668b81d Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 10 Jun 2025 12:26:33 -0700 Subject: [PATCH 05/71] improve file watching to watch a baml_src directory --- .../{ => baml_src}/clients.baml | 0 .../{ => baml_src}/receipt.baml | 0 bundle-hello-world/baml_src/test/resume.baml | 52 ++++++++ bundle-hello-world/src/file_watcher.rs | 25 ++-- bundle-hello-world/src/main.rs | 117 +++++++----------- bundle-hello-world/target/.rustc_info.json | 2 +- 6 files changed, 118 insertions(+), 78 deletions(-) rename bundle-hello-world/{ => baml_src}/clients.baml (100%) rename bundle-hello-world/{ => baml_src}/receipt.baml (100%) create mode 100644 bundle-hello-world/baml_src/test/resume.baml diff --git a/bundle-hello-world/clients.baml b/bundle-hello-world/baml_src/clients.baml similarity index 100% rename from bundle-hello-world/clients.baml rename to bundle-hello-world/baml_src/clients.baml diff --git a/bundle-hello-world/receipt.baml b/bundle-hello-world/baml_src/receipt.baml similarity index 100% rename from bundle-hello-world/receipt.baml rename to bundle-hello-world/baml_src/receipt.baml diff --git a/bundle-hello-world/baml_src/test/resume.baml b/bundle-hello-world/baml_src/test/resume.baml new file mode 100644 index 0000000000..526a5818dc --- /dev/null +++ b/bundle-hello-world/baml_src/test/resume.baml @@ -0,0 +1,52 @@ +// This is a BAML config file, which extends the Jinja2 templating language to write LLM functions. + +class Resume { + name string + education Education[] @description("Extract in the same order listed") + skills string[] @description("Only include programming languages") +} + +class Education { + school string + degree string + year int +} + +function ExtractResume(resume_text: string) -> Resume { + // see clients.baml + client GPT4o + + // The prompt uses Jinja syntax. Change the models or this text and watch the prompt preview change! + prompt #" + Parse the following resume and return a structured representation of the data in the schema below. + + Resume: + --- + {{ resume_text }} + --- + + {# special macro to print the output instructions. #} + {{ ctx.output_format }} + + JSON: + "# +} + +test Test1 { + functions [ExtractResume] + args { + resume_text #" + John Doe + + Education + - University of California, Berkeley + - B.S. in Computer Science + - 2020 + + Skills + - Python + - Java + - C++ + "# + } +} \ No newline at end of file diff --git a/bundle-hello-world/src/file_watcher.rs b/bundle-hello-world/src/file_watcher.rs index 047db8e2dc..5e17bfbbe3 100644 --- a/bundle-hello-world/src/file_watcher.rs +++ b/bundle-hello-world/src/file_watcher.rs @@ -22,7 +22,7 @@ impl FileWatcher { let path = self.path.clone(); std::thread::spawn(move || { let (tx, rx) = channel(); - let mut watcher = RecommendedWatcher::new( + let mut watcher = match RecommendedWatcher::new( move |res: Result| { if let Ok(event) = res { tx.send(event).unwrap(); @@ -31,18 +31,29 @@ impl FileWatcher { Config::default() .with_poll_interval(Duration::from_secs(1)) .with_compare_contents(true), - ) - .unwrap(); + ) { + Ok(w) => w, + Err(e) => { + eprintln!("Failed to create watcher for {}: {}", path, e); + return; + } + }; - watcher - .watch(Path::new(&path), RecursiveMode::NonRecursive) - .unwrap(); + if let Err(e) = watcher.watch(Path::new(&path), RecursiveMode::Recursive) { + eprintln!("Failed to watch {}: {}", path, e); + return; + } for event in rx { // Only trigger on actual content changes, not metadata changes if let EventKind::Modify(kind) = event.kind { if kind == notify::event::ModifyKind::Data(DataChange::Content) { - callback(&path); + // Get the full path of the changed file + if let Some(paths) = event.paths.first() { + if let Some(path_str) = paths.to_str() { + callback(path_str); + } + } } } } diff --git a/bundle-hello-world/src/main.rs b/bundle-hello-world/src/main.rs index 98d9a27d45..fb16302664 100644 --- a/bundle-hello-world/src/main.rs +++ b/bundle-hello-world/src/main.rs @@ -15,6 +15,7 @@ mod file_watcher; /// Embed at compile time everything in dist/ static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); +static ROOT_PATH: &str = "."; #[derive(Serialize, Deserialize, Debug)] struct Span { @@ -33,29 +34,35 @@ struct CursorPosition { column: u32, } +// Note: the name add_project should match exactly to the +// EventListener.tsx command definitions due to how serde serializes these into json +#[allow(non_camel_case_types)] #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "command", content = "content")] enum FrontendMessage { - #[serde(rename = "add_project")] - AddProject { + add_project { root_path: String, files: HashMap, }, - #[serde(rename = "remove_project")] - RemoveProject { root_path: String }, - #[serde(rename = "set_flashing_regions")] - SetFlashingRegions { spans: Vec }, - #[serde(rename = "select_function")] - SelectFunction { + remove_project { + root_path: String, + }, + set_flashing_regions { + spans: Vec, + }, + select_function { root_path: String, function_name: String, }, - #[serde(rename = "update_cursor")] - UpdateCursor { cursor: CursorPosition }, - #[serde(rename = "baml_settings_updated")] - BamlSettingsUpdated { settings: HashMap }, - #[serde(rename = "run_test")] - RunTest { test_name: String }, + update_cursor { + cursor: CursorPosition, + }, + baml_settings_updated { + settings: HashMap, + }, + run_test { + test_name: String, + }, } #[derive(Serialize, Deserialize, Debug)] @@ -71,8 +78,6 @@ struct Diagnostic { struct BamlState { files: HashMap, - current_function: Option, - diagnostics: Vec, tx: broadcast::Sender, } @@ -81,46 +86,22 @@ impl BamlState { let (tx, _) = broadcast::channel(100); Self { files: HashMap::new(), - current_function: None, - diagnostics: Vec::new(), tx, } } - - fn load_baml_files(&mut self) -> Result<(), Box> { - // Load receipt.baml - let receipt_content = fs::read_to_string("receipt.baml")?; - self.files - .insert("receipt.baml".to_string(), receipt_content); - - // Load clients.baml - let clients_content = fs::read_to_string("clients.baml")?; - self.files - .insert("clients.baml".to_string(), clients_content); - - Ok(()) - } } async fn client_connection(ws: warp::ws::WebSocket, state: Arc>) { - let (mut ws_tx, mut ws_rx) = ws.split(); + let (mut ws_tx, _ws_rx) = ws.split(); let mut rx = { let state = state.read().await; state.tx.subscribe() }; - // Load BAML files and send initial state - { - let mut state = state.write().await; - if let Err(e) = state.load_baml_files() { - eprintln!("Error loading BAML files: {}", e); - } - } - - // Send initial project state (currently to the root folder of where the script is called) + // Send initial project state let state_read = state.read().await; - let add_project_msg = FrontendMessage::AddProject { - root_path: ".".to_string(), + let add_project_msg = FrontendMessage::add_project { + root_path: ROOT_PATH.to_string(), files: state_read.files.clone(), }; // Send the add project message to the client @@ -143,32 +124,28 @@ async fn client_connection(ws: warp::ws::WebSocket, state: Arc async fn main() { let state = Arc::new(RwLock::new(BamlState::new())); - // Set up file watchers for .baml files - let baml_files = ["receipt.baml", "clients.baml"]; - for file in baml_files { - if let Ok(watcher) = FileWatcher::new(file) { - let state_clone = state.clone(); - watcher - .watch(move |path| { - println!("BAML file changed: {}", path); - // Reload the file and update state - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let mut state = state_clone.write().await; - if let Ok(content) = fs::read_to_string(path) { - state.files.insert(path.to_string(), content); - - // Notify all clients about the file change - let add_project_msg = FrontendMessage::AddProject { - root_path: ".".to_string(), - files: state.files.clone(), - }; - let msg_str = serde_json::to_string(&add_project_msg).unwrap(); - let _ = state.tx.send(msg_str); - } - }); - }) - .unwrap(); + // Set up a single file watcher for the baml_src directory + if let Ok(watcher) = FileWatcher::new("baml_src") { + let state_clone = state.clone(); + if let Err(e) = watcher.watch(move |path| { + println!("BAML file changed: {}", path); + // Reload the file and update state + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let mut state = state_clone.write().await; + if let Ok(content) = fs::read_to_string(path) { + state.files.insert(path.to_string(), content); + + let add_project_msg = FrontendMessage::add_project { + root_path: ROOT_PATH.to_string(), + files: state.files.clone(), + }; + let msg_str = serde_json::to_string(&add_project_msg).unwrap(); + let _ = state.tx.send(msg_str); + } + }); + }) { + eprintln!("Failed to watch baml_src directory: {}", e); } } diff --git a/bundle-hello-world/target/.rustc_info.json b/bundle-hello-world/target/.rustc_info.json index fb773a3714..cf06391425 100644 --- a/bundle-hello-world/target/.rustc_info.json +++ b/bundle-hello-world/target/.rustc_info.json @@ -1 +1 @@ -{"rustc_fingerprint":15275327620044501057,"outputs":{"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/egor/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.87.0 (17067e9ac 2025-05-09)\nbinary: rustc\ncommit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359\ncommit-date: 2025-05-09\nhost: aarch64-apple-darwin\nrelease: 1.87.0\nLLVM version: 20.1.1\n","stderr":""}},"successes":{}} \ No newline at end of file +{"rustc_fingerprint":15275327620044501057,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.87.0 (17067e9ac 2025-05-09)\nbinary: rustc\ncommit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359\ncommit-date: 2025-05-09\nhost: aarch64-apple-darwin\nrelease: 1.87.0\nLLVM version: 20.1.1\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/egor/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""}},"successes":{}} \ No newline at end of file From 730d354f8b622f75b1e75de520b271620c672b49 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 10 Jun 2025 14:43:51 -0700 Subject: [PATCH 06/71] added init which grabs all baml files at baml_src --- bundle-hello-world/.gitignore | 1 + bundle-hello-world/src/main.rs | 46 +++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 bundle-hello-world/.gitignore diff --git a/bundle-hello-world/.gitignore b/bundle-hello-world/.gitignore new file mode 100644 index 0000000000..9f970225ad --- /dev/null +++ b/bundle-hello-world/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/bundle-hello-world/src/main.rs b/bundle-hello-world/src/main.rs index fb16302664..0fd7acfc03 100644 --- a/bundle-hello-world/src/main.rs +++ b/bundle-hello-world/src/main.rs @@ -4,7 +4,6 @@ use include_dir::{Dir, include_dir}; use mime_guess::from_path; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use std::convert::Infallible; use std::fs; use std::sync::Arc; use tokio::sync::RwLock; @@ -17,7 +16,34 @@ mod file_watcher; static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); static ROOT_PATH: &str = "."; +fn get_baml_files() -> Vec { + let mut files = Vec::new(); + + fn search_dir(dir_path: &std::path::Path, files: &mut Vec) { + if let Ok(entries) = fs::read_dir(dir_path) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + // Recursively search subdirectories + search_dir(&path, files); + } else if path.is_file() && path.extension().map_or(false, |ext| ext == "baml") { + if let Ok(absolute) = fs::canonicalize(&path) { + if let Some(path_str) = absolute.to_str() { + files.push(path_str.to_string()); + } + } + } + } + } + } + + // TODO: should consider the possibility of baml_src as root directory? + search_dir(std::path::Path::new("baml_src"), &mut files); + files +} + #[derive(Serialize, Deserialize, Debug)] + struct Span { file_path: String, start_line: u32, @@ -120,10 +146,22 @@ async fn client_connection(ws: warp::ws::WebSocket, state: Arc }); } +async fn initialize_baml_files(state: Arc>) { + let mut state = state.write().await; + for path in get_baml_files() { + if let Ok(content) = fs::read_to_string(&path) { + state.files.insert(path, content); + } + } +} + #[tokio::main] async fn main() { let state = Arc::new(RwLock::new(BamlState::new())); + // Initialize all BAML files from baml_src directory + initialize_baml_files(state.clone()).await; + // Set up a single file watcher for the baml_src directory if let Ok(watcher) = FileWatcher::new("baml_src") { let state_clone = state.clone(); @@ -168,13 +206,15 @@ async fn main() { Some(f) => { let body = f.contents(); let mime = from_path(file).first_or_octet_stream(); - Ok::<_, Infallible>( + Ok::<_, warp::Rejection>( Response::builder() .header("content-type", mime.as_ref()) .body(body.to_vec()), ) } - None => Ok(Response::builder().status(404).body(b"Not Found".to_vec())), + None => Ok::<_, warp::Rejection>( + Response::builder().status(404).body(b"Not Found".to_vec()), + ), } }); From a2fc63e4552c595d398ab4dede58938ef5d6c05f Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 10 Jun 2025 17:23:09 -0700 Subject: [PATCH 07/71] basic implementation for playground via cli --- bundle-hello-world/.gitignore | 1 - bundle-hello-world/Cargo.toml | 16 -- bundle-hello-world/baml_src/clients.baml | 41 ---- bundle-hello-world/baml_src/receipt.baml | 61 ------ bundle-hello-world/baml_src/test/resume.baml | 52 ----- bundle-hello-world/src/file_watcher.rs | 64 ------ bundle-hello-world/target/.rustc_info.json | 1 - bundle-hello-world/target/CACHEDIR.TAG | 3 - engine/Cargo.lock | 184 +++++++++++++++++- engine/cli/Cargo.toml | 10 +- engine/cli/src/commands.rs | 12 +- engine/cli/src/lib.rs | 1 + engine/cli/src/playground/definitions.rs | 65 +++++++ engine/cli/src/playground/file_watcher.rs | 53 +++++ engine/cli/src/playground/mod.rs | 9 + engine/cli/src/playground/playground.rs | 38 ++++ .../cli/src/playground/server.rs | 167 ++++------------ 17 files changed, 399 insertions(+), 379 deletions(-) delete mode 100644 bundle-hello-world/.gitignore delete mode 100644 bundle-hello-world/Cargo.toml delete mode 100644 bundle-hello-world/baml_src/clients.baml delete mode 100644 bundle-hello-world/baml_src/receipt.baml delete mode 100644 bundle-hello-world/baml_src/test/resume.baml delete mode 100644 bundle-hello-world/src/file_watcher.rs delete mode 100644 bundle-hello-world/target/.rustc_info.json delete mode 100644 bundle-hello-world/target/CACHEDIR.TAG create mode 100644 engine/cli/src/playground/definitions.rs create mode 100644 engine/cli/src/playground/file_watcher.rs create mode 100644 engine/cli/src/playground/mod.rs create mode 100644 engine/cli/src/playground/playground.rs rename bundle-hello-world/src/main.rs => engine/cli/src/playground/server.rs (59%) diff --git a/bundle-hello-world/.gitignore b/bundle-hello-world/.gitignore deleted file mode 100644 index 9f970225ad..0000000000 --- a/bundle-hello-world/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ \ No newline at end of file diff --git a/bundle-hello-world/Cargo.toml b/bundle-hello-world/Cargo.toml deleted file mode 100644 index 0fd2370ab0..0000000000 --- a/bundle-hello-world/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "bundle-hello-world" -version = "0.1.0" -edition = "2024" - -[dependencies] -tokio = { version = "1", features = ["full"] } -warp = "0.3" -include_dir = "0.7" -mime_guess = "2.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -tokio-stream = { version = "0.1", features = ["sync"] } -futures-util = "0.3" -dotenv = "0.15" -notify = "6.1" diff --git a/bundle-hello-world/baml_src/clients.baml b/bundle-hello-world/baml_src/clients.baml deleted file mode 100644 index 2d45afc2e9..0000000000 --- a/bundle-hello-world/baml_src/clients.baml +++ /dev/null @@ -1,41 +0,0 @@ -// These are LLM clients you can use in your functions. We currently support Anthropic, OpenAI / Azure, Gemini, and Ollama as providers. - -// We also support any other provider that follows the OpenAI API specification, such as HuggingFace. - -// For this playground, we have setup a few clients for you to use already with some free credits. - -client GPT4 { - // Use one of the following: https://docs.boundaryml.com/docs/snippets/clients/providers/openai - provider openai - // You can pass in any parameters from the OpenAI Python documentation into the options block. - options { - model gpt-4 - api_key env.OPENAI_API_KEY - } -} - -client GPT4o { - provider openai - options { - model gpt-4o - api_key env.OPENAI_API_KEY - } -} - -client Claude { - provider anthropic - options { - model claude-3-haiku-20240307 - api_key env.ANTHROPIC_API_KEY - max_tokens 1000 - - } -} - -client Gemini { - provider google-ai - options { - model "gemini-1.5-pro-001" - api_key env.GOOGLE_API_KEY - } -} diff --git a/bundle-hello-world/baml_src/receipt.baml b/bundle-hello-world/baml_src/receipt.baml deleted file mode 100644 index 0c2622efd4..0000000000 --- a/bundle-hello-world/baml_src/receipt.baml +++ /dev/null @@ -1,61 +0,0 @@ -// https://docs.boundaryml.com - -// We want the LLM to extract this info from an image receipt -class Receipt { - establishment_name string - date string @description("ISO8601 formatted date") - total int @description("The total amount of the receipt") - currency string - items Item[] @description("The items on the receipt") -} - -class Item { - name string - price float - quantity int @description("If not specified, assume 1") -} - -// This is our LLM function we can call in Python or Typescript -// the receipt can be an image OR text here! -function ExtractReceipt(receipt: image | string) -> Receipt { - // see clients.baml - client GPT4o - prompt #" - {# start a user message #} - {{ _.role("user") }} - - Extract info from this receipt: - {{ receipt }} - - {# special macro to print the output schema instructions. #} - {{ ctx.output_format }} - "# -} - -// Test when the input is an image -test ImageReceiptTest { - functions [ExtractReceipt] - args { - receipt { url "https://i.redd.it/adzt4bz4llfc1.jpeg"} - } -} - -// Test when the input is a string -test StarbucksTextReceiptTest { - functions [ExtractReceipt] - args { - // use #""# for multi-line strings - receipt #" - Starbucks - Date: 2022-01-01 - Total: $5.00 USD - Items: - - Coffee - - $2.50 - - 1 - - Croissant - - $2.50 - - 1 - "# - } -} diff --git a/bundle-hello-world/baml_src/test/resume.baml b/bundle-hello-world/baml_src/test/resume.baml deleted file mode 100644 index 526a5818dc..0000000000 --- a/bundle-hello-world/baml_src/test/resume.baml +++ /dev/null @@ -1,52 +0,0 @@ -// This is a BAML config file, which extends the Jinja2 templating language to write LLM functions. - -class Resume { - name string - education Education[] @description("Extract in the same order listed") - skills string[] @description("Only include programming languages") -} - -class Education { - school string - degree string - year int -} - -function ExtractResume(resume_text: string) -> Resume { - // see clients.baml - client GPT4o - - // The prompt uses Jinja syntax. Change the models or this text and watch the prompt preview change! - prompt #" - Parse the following resume and return a structured representation of the data in the schema below. - - Resume: - --- - {{ resume_text }} - --- - - {# special macro to print the output instructions. #} - {{ ctx.output_format }} - - JSON: - "# -} - -test Test1 { - functions [ExtractResume] - args { - resume_text #" - John Doe - - Education - - University of California, Berkeley - - B.S. in Computer Science - - 2020 - - Skills - - Python - - Java - - C++ - "# - } -} \ No newline at end of file diff --git a/bundle-hello-world/src/file_watcher.rs b/bundle-hello-world/src/file_watcher.rs deleted file mode 100644 index 5e17bfbbe3..0000000000 --- a/bundle-hello-world/src/file_watcher.rs +++ /dev/null @@ -1,64 +0,0 @@ -use notify::event::DataChange; -use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; -use std::path::Path; -use std::sync::mpsc::channel; -use std::time::Duration; - -pub struct FileWatcher { - path: String, -} - -impl FileWatcher { - pub fn new(path: &str) -> Result { - Ok(Self { - path: path.to_string(), - }) - } - - pub fn watch(&self, mut callback: F) -> Result<(), notify::Error> - where - F: FnMut(&str) + Send + 'static, - { - let path = self.path.clone(); - std::thread::spawn(move || { - let (tx, rx) = channel(); - let mut watcher = match RecommendedWatcher::new( - move |res: Result| { - if let Ok(event) = res { - tx.send(event).unwrap(); - } - }, - Config::default() - .with_poll_interval(Duration::from_secs(1)) - .with_compare_contents(true), - ) { - Ok(w) => w, - Err(e) => { - eprintln!("Failed to create watcher for {}: {}", path, e); - return; - } - }; - - if let Err(e) = watcher.watch(Path::new(&path), RecursiveMode::Recursive) { - eprintln!("Failed to watch {}: {}", path, e); - return; - } - - for event in rx { - // Only trigger on actual content changes, not metadata changes - if let EventKind::Modify(kind) = event.kind { - if kind == notify::event::ModifyKind::Data(DataChange::Content) { - // Get the full path of the changed file - if let Some(paths) = event.paths.first() { - if let Some(path_str) = paths.to_str() { - callback(path_str); - } - } - } - } - } - }); - - Ok(()) - } -} diff --git a/bundle-hello-world/target/.rustc_info.json b/bundle-hello-world/target/.rustc_info.json deleted file mode 100644 index cf06391425..0000000000 --- a/bundle-hello-world/target/.rustc_info.json +++ /dev/null @@ -1 +0,0 @@ -{"rustc_fingerprint":15275327620044501057,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.87.0 (17067e9ac 2025-05-09)\nbinary: rustc\ncommit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359\ncommit-date: 2025-05-09\nhost: aarch64-apple-darwin\nrelease: 1.87.0\nLLVM version: 20.1.1\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/egor/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""}},"successes":{}} \ No newline at end of file diff --git a/bundle-hello-world/target/CACHEDIR.TAG b/bundle-hello-world/target/CACHEDIR.TAG deleted file mode 100644 index 20d7c319cd..0000000000 --- a/bundle-hello-world/target/CACHEDIR.TAG +++ /dev/null @@ -1,3 +0,0 @@ -Signature: 8a477f597d28d172789f06886806bc55 -# This file is a cache directory tag created by cargo. -# For information about cache directory tags see https://bford.info/cachedir/ diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 399408d34d..9ddea153a2 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -848,7 +848,7 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "headers", + "headers 0.4.0", "http 1.1.0", "http-body 1.0.1", "http-body-util", @@ -922,6 +922,7 @@ dependencies = [ "expect-test", "fastrand 2.3.0", "futures", + "futures-util", "http 1.1.0", "http-body 1.0.1", "include_dir", @@ -937,6 +938,8 @@ dependencies = [ "log", "mime", "mime_guess", + "notify 6.1.1", + "notify-debouncer-full 0.5.0", "open", "pathdiff 0.1.0", "pretty_assertions", @@ -962,6 +965,7 @@ dependencies = [ "url", "uuid", "walkdir", + "warp", "wasm-bindgen-test", "wasm-logger", "web-time", @@ -1193,7 +1197,7 @@ dependencies = [ "mime", "mime_guess", "minijinja", - "notify-debouncer-full", + "notify-debouncer-full 0.3.1", "once_cell", "pin-project-lite", "pretty_assertions", @@ -2042,6 +2046,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + [[package]] name = "deranged" version = "0.4.1" @@ -2392,11 +2402,11 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "file-id" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6584280525fb2059cba3db2c04abf947a1a29a45ddae89f3870f8281704fafc9" +checksum = "6bc904b9bbefcadbd8e3a9fb0d464a9b979de6324c03b3c663e8994f46a5be36" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2774,6 +2784,21 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core 0.2.0", + "http 0.2.12", + "httpdate", + "mime", + "sha1", +] + [[package]] name = "headers" version = "0.4.0" @@ -2782,13 +2807,22 @@ checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ "base64 0.21.7", "bytes", - "headers-core", + "headers-core 0.3.0", "http 1.1.0", "httpdate", "mime", "sha1", ] +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http 0.2.12", +] + [[package]] name = "headers-core" version = "0.3.0" @@ -3327,6 +3361,17 @@ dependencies = [ "libc", ] +[[package]] +name = "inotify" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" +dependencies = [ + "bitflags 2.9.0", + "inotify-sys", + "libc", +] + [[package]] name = "inotify-sys" version = "0.1.5" @@ -4055,10 +4100,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] +[[package]] +name = "multer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 0.2.12", + "httparse", + "log", + "memchr", + "mime", + "spin", + "version_check", +] + [[package]] name = "mutants" version = "0.0.3" @@ -4175,7 +4239,7 @@ dependencies = [ "crossbeam-channel", "filetime", "fsevent-sys", - "inotify", + "inotify 0.9.6", "kqueue", "libc", "log", @@ -4184,6 +4248,25 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "notify" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" +dependencies = [ + "bitflags 2.9.0", + "filetime", + "fsevent-sys", + "inotify 0.11.0", + "kqueue", + "libc", + "log", + "mio 1.0.3", + "notify-types", + "walkdir", + "windows-sys 0.59.0", +] + [[package]] name = "notify-debouncer-full" version = "0.3.1" @@ -4193,11 +4276,30 @@ dependencies = [ "crossbeam-channel", "file-id", "log", - "notify", + "notify 6.1.1", "parking_lot", "walkdir", ] +[[package]] +name = "notify-debouncer-full" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d88b1a7538054351c8258338df7c931a590513fb3745e8c15eb9ff4199b8d1" +dependencies = [ + "file-id", + "log", + "notify 8.0.0", + "notify-types", + "walkdir", +] + +[[package]] +name = "notify-types" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -6269,6 +6371,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.11" @@ -6481,6 +6595,25 @@ dependencies = [ "termcolor", ] +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", + "thiserror 1.0.62", + "url", + "utf-8", +] + [[package]] name = "type-safe-id" version = "0.3.2" @@ -6580,6 +6713,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf16_iter" version = "1.0.5" @@ -6717,6 +6856,35 @@ dependencies = [ "try-lock", ] +[[package]] +name = "warp" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers 0.3.9", + "http 0.2.12", + "hyper 0.14.32", + "log", + "mime", + "mime_guess", + "multer", + "percent-encoding", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-tungstenite", + "tokio-util", + "tower-service", + "tracing", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/engine/cli/Cargo.toml b/engine/cli/Cargo.toml index 3d0b479911..b6c61fb174 100644 --- a/engine/cli/Cargo.toml +++ b/engine/cli/Cargo.toml @@ -69,14 +69,17 @@ tokio = { version = "1", default-features = false, features = [ "time", ] } tokio-stream = "0.1.15" -# NOTE(sam): adding this caused a build error, I suspect because tower uses nightly features or something -# tower = "0.5.0" walkdir.workspace = true uuid = { version = "1.8.0", features = ["v4", "serde"] } web-time.workspace = true static_assertions.workspace = true mime_guess = "2.0.4" mime = "0.3.17" +warp = "0.3" +futures-util = "0.3" +include_dir = "0.7" +notify = "6.1" +notify-debouncer-full = "0.5.0" # For tracing envy = "0.4.2" @@ -85,7 +88,6 @@ stream-cancel = "0.8.2" async-std = "1.12.0" fastrand = "2.1.0" test-log = "0.2.16" -include_dir = "0.7.3" infer = "0.16.0" url = "2.5.2" shell-escape = "0.1.5" @@ -101,8 +103,6 @@ jsonwebtoken = "9.3.0" pretty_assertions = "1.4.0" sha2 = "0.10.8" tracing = "0.1.40" -# Valuable is needed to prevent serializing objects using Debug, and instead use Serialize. -# https://github.com/tokio-rs/tracing/issues/1570 tracing-subscriber = { version = "0.3.18", features = [ "json", "env-filter", diff --git a/engine/cli/src/commands.rs b/engine/cli/src/commands.rs index 40ff37a582..cc839f40e0 100644 --- a/engine/cli/src/commands.rs +++ b/engine/cli/src/commands.rs @@ -48,6 +48,9 @@ pub(crate) enum Commands { #[command(about = "Starts a language server", name = "lsp")] LanguageServer(crate::lsp::LanguageServerArgs), + + #[command(about = "Starts a playground server", name = "playground")] + Playground(crate::playground::PlaygroundArgs), } impl RuntimeCli { @@ -127,12 +130,17 @@ impl RuntimeCli { } } } - Commands::LanguageServer(args) => { + Commands::LanguageServer(args) => match args.run() { + Ok(()) => Ok(crate::ExitCode::Success), + Err(_) => Ok(crate::ExitCode::Other), + }, + Commands::Playground(args) => { + args.from = BamlRuntime::parse_baml_src_path(&args.from)?; match args.run() { Ok(()) => Ok(crate::ExitCode::Success), Err(_) => Ok(crate::ExitCode::Other), } - }, + } } } } diff --git a/engine/cli/src/lib.rs b/engine/cli/src/lib.rs index 5353dbeefb..644f87b244 100644 --- a/engine/cli/src/lib.rs +++ b/engine/cli/src/lib.rs @@ -5,6 +5,7 @@ pub(crate) mod commands; pub(crate) mod deploy; pub(crate) mod format; pub(crate) mod lsp; +pub mod playground; pub(crate) mod propelauth; pub(crate) mod tui; use anyhow::Result; diff --git a/engine/cli/src/playground/definitions.rs b/engine/cli/src/playground/definitions.rs new file mode 100644 index 0000000000..d1de53266e --- /dev/null +++ b/engine/cli/src/playground/definitions.rs @@ -0,0 +1,65 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +// #[derive(Serialize, Deserialize, Debug)] +// pub struct Span { +// pub file_path: String, +// pub start_line: u32, +// pub start: u32, +// pub end_line: u32, +// pub end: u32, +// } + +// #[derive(Serialize, Deserialize, Debug)] +// pub struct CursorPosition { +// pub file_name: String, +// pub file_text: String, +// pub line: u32, +// pub column: u32, +// } + +// Note: the name add_project should match exactly to the +// EventListener.tsx command definitions due to how serde serializes these into json +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "command", content = "content")] +pub enum FrontendMessage { + add_project { + root_path: String, + files: HashMap, + }, + remove_project { + root_path: String, + }, + // set_flashing_regions { + // spans: Vec, + // }, + select_function { + root_path: String, + function_name: String, + }, + // update_cursor { + // cursor: CursorPosition, + // }, + baml_settings_updated { + settings: HashMap, + }, + run_test { + test_name: String, + }, +} + +pub struct BamlState { + pub files: HashMap, + pub tx: tokio::sync::broadcast::Sender, +} + +impl BamlState { + pub fn new() -> Self { + let (tx, _) = tokio::sync::broadcast::channel(100); + Self { + files: HashMap::new(), + tx, + } + } +} diff --git a/engine/cli/src/playground/file_watcher.rs b/engine/cli/src/playground/file_watcher.rs new file mode 100644 index 0000000000..53570de721 --- /dev/null +++ b/engine/cli/src/playground/file_watcher.rs @@ -0,0 +1,53 @@ +use notify_debouncer_full::{new_debouncer, notify::*}; +use std::path::Path; +use std::sync::mpsc::channel; +use std::time::Duration; + +// code based on engine/baml-runtime/src/cli/dev.rs + +pub struct FileWatcher { + path: String, +} + +impl FileWatcher { + pub fn new(path: &str) -> std::io::Result { + Ok(Self { + path: path.to_string(), + }) + } + + pub fn watch(&self, mut callback: F) -> std::io::Result<()> + where + F: FnMut(&str) + Send + 'static, + { + let path = self.path.clone(); + std::thread::spawn(move || { + let (tx, rx) = channel(); + // no specific tickrate, max debounce time 200ms + let mut debouncer = new_debouncer(Duration::from_millis(200), None, tx).unwrap(); + + debouncer + .watch(Path::new(&path), RecursiveMode::Recursive) + .unwrap(); + + for result in rx { + match result { + Ok(events) => { + for event in events { + if let Some(paths) = event.paths.first() { + if let Some(path_str) = paths.to_str() { + callback(path_str); + } + } + } + } + Err(errors) => { + eprintln!("Error watching {}: {:?}", path, errors); + } + } + } + }); + + Ok(()) + } +} diff --git a/engine/cli/src/playground/mod.rs b/engine/cli/src/playground/mod.rs new file mode 100644 index 0000000000..fe9bd23b43 --- /dev/null +++ b/engine/cli/src/playground/mod.rs @@ -0,0 +1,9 @@ +mod definitions; +mod file_watcher; +mod playground; +mod server; + +pub use self::playground::PlaygroundArgs; +pub use definitions::{BamlState, FrontendMessage}; +pub use file_watcher::FileWatcher; +pub use server::{create_routes, initialize_baml_files, setup_file_watcher}; diff --git a/engine/cli/src/playground/playground.rs b/engine/cli/src/playground/playground.rs new file mode 100644 index 0000000000..47c00dbb39 --- /dev/null +++ b/engine/cli/src/playground/playground.rs @@ -0,0 +1,38 @@ +/// Script to run the playground server based of a specified directory. +/// Currently uses a custom filewatcher which detects changes to files in +/// the directory and refreshes the web-view. +use crate::playground::{create_routes, initialize_baml_files, setup_file_watcher, BamlState}; +use anyhow::Result; +use clap::Args; +use std::path::PathBuf; +use std::sync::Arc; +use tokio::sync::RwLock; + +#[derive(Args, Debug, Clone)] +pub struct PlaygroundArgs { + #[arg(long, help = "path/to/baml_src", default_value = "./baml_src")] + pub from: PathBuf, + #[arg(long, help = "port to expose playground on", default_value = "3030")] + port: u16, +} + +impl PlaygroundArgs { + pub fn run(&self) -> Result<()> { + let state = Arc::new(RwLock::new(BamlState::new())); + + // Initialize all BAML files from baml_src directory + let rt = tokio::runtime::Runtime::new()?; + rt.block_on(initialize_baml_files(state.clone(), &self.from)); + + // Set up file watcher + setup_file_watcher(state.clone(), &self.from)?; + + // Sets up the connections for the frontend server + let routes = create_routes(state); + + println!("Hosted playground at http://localhost:{}...", self.port); + rt.block_on(warp::serve(routes).run(([127, 0, 0, 1], self.port))); + + Ok(()) + } +} diff --git a/bundle-hello-world/src/main.rs b/engine/cli/src/playground/server.rs similarity index 59% rename from bundle-hello-world/src/main.rs rename to engine/cli/src/playground/server.rs index 0fd7acfc03..aeb7e361e4 100644 --- a/bundle-hello-world/src/main.rs +++ b/engine/cli/src/playground/server.rs @@ -1,123 +1,21 @@ -use crate::file_watcher::FileWatcher; +use crate::playground::{BamlState, FileWatcher, FrontendMessage}; +use anyhow::Result; use futures_util::{SinkExt, StreamExt}; -use include_dir::{Dir, include_dir}; +use include_dir::{include_dir, Dir}; use mime_guess::from_path; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use std::fs; +use std::path::Path; use std::sync::Arc; use tokio::sync::RwLock; -use tokio::sync::broadcast; -use warp::{Filter, http::Response, ws::Message}; - -mod file_watcher; +use warp::{http::Response, ws::Message, Filter}; /// Embed at compile time everything in dist/ +/// This embeds the entire frontend code into the binary which includes the web-view and playground-common static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); +// Does not matter what this is, it is not currently used in the playground static ROOT_PATH: &str = "."; -fn get_baml_files() -> Vec { - let mut files = Vec::new(); - - fn search_dir(dir_path: &std::path::Path, files: &mut Vec) { - if let Ok(entries) = fs::read_dir(dir_path) { - for entry in entries.flatten() { - let path = entry.path(); - if path.is_dir() { - // Recursively search subdirectories - search_dir(&path, files); - } else if path.is_file() && path.extension().map_or(false, |ext| ext == "baml") { - if let Ok(absolute) = fs::canonicalize(&path) { - if let Some(path_str) = absolute.to_str() { - files.push(path_str.to_string()); - } - } - } - } - } - } - - // TODO: should consider the possibility of baml_src as root directory? - search_dir(std::path::Path::new("baml_src"), &mut files); - files -} - -#[derive(Serialize, Deserialize, Debug)] - -struct Span { - file_path: String, - start_line: u32, - start: u32, - end_line: u32, - end: u32, -} - -#[derive(Serialize, Deserialize, Debug)] -struct CursorPosition { - file_name: String, - file_text: String, - line: u32, - column: u32, -} - -// Note: the name add_project should match exactly to the -// EventListener.tsx command definitions due to how serde serializes these into json -#[allow(non_camel_case_types)] -#[derive(Serialize, Deserialize, Debug)] -#[serde(tag = "command", content = "content")] -enum FrontendMessage { - add_project { - root_path: String, - files: HashMap, - }, - remove_project { - root_path: String, - }, - set_flashing_regions { - spans: Vec, - }, - select_function { - root_path: String, - function_name: String, - }, - update_cursor { - cursor: CursorPosition, - }, - baml_settings_updated { - settings: HashMap, - }, - run_test { - test_name: String, - }, -} - -#[derive(Serialize, Deserialize, Debug)] -struct Diagnostic { - file_path: String, - start_line: u32, - start: u32, - end_line: u32, - end: u32, - message: String, - severity: String, -} - -struct BamlState { - files: HashMap, - tx: broadcast::Sender, -} - -impl BamlState { - fn new() -> Self { - let (tx, _) = broadcast::channel(100); - Self { - files: HashMap::new(), - tx, - } - } -} - -async fn client_connection(ws: warp::ws::WebSocket, state: Arc>) { +pub async fn client_connection(ws: warp::ws::WebSocket, state: Arc>) { let (mut ws_tx, _ws_rx) = ws.split(); let mut rx = { let state = state.read().await; @@ -130,7 +28,6 @@ async fn client_connection(ws: warp::ws::WebSocket, state: Arc root_path: ROOT_PATH.to_string(), files: state_read.files.clone(), }; - // Send the add project message to the client let _ = ws_tx .send(Message::text( serde_json::to_string(&add_project_msg).unwrap(), @@ -146,24 +43,42 @@ async fn client_connection(ws: warp::ws::WebSocket, state: Arc }); } -async fn initialize_baml_files(state: Arc>) { +pub async fn initialize_baml_files(state: Arc>, baml_src: &Path) { let mut state = state.write().await; - for path in get_baml_files() { + for path in get_baml_files(baml_src) { if let Ok(content) = fs::read_to_string(&path) { state.files.insert(path, content); } } } -#[tokio::main] -async fn main() { - let state = Arc::new(RwLock::new(BamlState::new())); +// method that retrieves all baml files in the baml_src directory +pub fn get_baml_files(baml_src: &Path) -> Vec { + let mut files = Vec::new(); + + fn search_dir(dir_path: &std::path::Path, files: &mut Vec) { + if let Ok(entries) = fs::read_dir(dir_path) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + search_dir(&path, files); + } else if path.is_file() && path.extension().map_or(false, |ext| ext == "baml") { + if let Ok(absolute) = fs::canonicalize(&path) { + if let Some(path_str) = absolute.to_str() { + files.push(path_str.to_string()); + } + } + } + } + } + } - // Initialize all BAML files from baml_src directory - initialize_baml_files(state.clone()).await; + search_dir(baml_src, &mut files); + files +} - // Set up a single file watcher for the baml_src directory - if let Ok(watcher) = FileWatcher::new("baml_src") { +pub fn setup_file_watcher(state: Arc>, baml_src: &Path) -> Result<()> { + if let Ok(watcher) = FileWatcher::new(baml_src.to_str().unwrap()) { let state_clone = state.clone(); if let Err(e) = watcher.watch(move |path| { println!("BAML file changed: {}", path); @@ -186,7 +101,12 @@ async fn main() { eprintln!("Failed to watch baml_src directory: {}", e); } } + Ok(()) +} +pub fn create_routes( + state: Arc>, +) -> impl Filter + Clone { // WebSocket handler let ws_route = warp::path("ws") .and(warp::ws()) @@ -195,7 +115,7 @@ async fn main() { ws.on_upgrade(move |socket| client_connection(socket, state)) }); - // Static file serving + // Static file serving needed to serve the index.html of the frontend playground let spa = warp::path::full() .and(warp::get()) @@ -218,8 +138,5 @@ async fn main() { } }); - let routes = ws_route.or(spa).with(warp::log("bundle-server")); - - println!("Listening on http://localhost:3030 …"); - warp::serve(routes).run(([127, 0, 0, 1], 3030)).await; + ws_route.or(spa).with(warp::log("bundle-server")) } From 1d4522238b57c9d5009cf21d0d022014a0c563b5 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 11 Jun 2025 10:07:05 -0700 Subject: [PATCH 08/71] correctly update removed .baml files --- engine/cli/src/playground/server.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/engine/cli/src/playground/server.rs b/engine/cli/src/playground/server.rs index aeb7e361e4..3697d681f8 100644 --- a/engine/cli/src/playground/server.rs +++ b/engine/cli/src/playground/server.rs @@ -1,5 +1,6 @@ use crate::playground::{BamlState, FileWatcher, FrontendMessage}; use anyhow::Result; +use baml_log::bdebug; use futures_util::{SinkExt, StreamExt}; use include_dir::{include_dir, Dir}; use mime_guess::from_path; @@ -81,21 +82,27 @@ pub fn setup_file_watcher(state: Arc>, baml_src: &Path) -> Res if let Ok(watcher) = FileWatcher::new(baml_src.to_str().unwrap()) { let state_clone = state.clone(); if let Err(e) = watcher.watch(move |path| { - println!("BAML file changed: {}", path); + bdebug!("BAML file changed: {}", path); // Reload the file and update state let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { let mut state = state_clone.write().await; + // Remove the modified file from state + state.files.remove(path); + // Re-add it if it still exists + // NOTE: there should be a way to determine if its a delete or move event + // from the file watcher instead of re-checking the entire directory if let Ok(content) = fs::read_to_string(path) { state.files.insert(path.to_string(), content); - - let add_project_msg = FrontendMessage::add_project { - root_path: ROOT_PATH.to_string(), - files: state.files.clone(), - }; - let msg_str = serde_json::to_string(&add_project_msg).unwrap(); - let _ = state.tx.send(msg_str); } + // bdebug!("files: {:?}", state.files.clone()); + + let add_project_msg = FrontendMessage::add_project { + root_path: ROOT_PATH.to_string(), + files: state.files.clone(), + }; + let msg_str = serde_json::to_string(&add_project_msg).unwrap(); + let _ = state.tx.send(msg_str); }); }) { eprintln!("Failed to watch baml_src directory: {}", e); From 7fcec1dc84746adc7ee82fc976c36e3afb4bed02 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 11 Jun 2025 13:24:47 -0700 Subject: [PATCH 09/71] change embedd to pull from web-panel build file directly --- engine/cli/src/playground/server.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/engine/cli/src/playground/server.rs b/engine/cli/src/playground/server.rs index 3697d681f8..24a0ac4a0f 100644 --- a/engine/cli/src/playground/server.rs +++ b/engine/cli/src/playground/server.rs @@ -1,6 +1,6 @@ use crate::playground::{BamlState, FileWatcher, FrontendMessage}; use anyhow::Result; -use baml_log::bdebug; +// use baml_log::bdebug; use futures_util::{SinkExt, StreamExt}; use include_dir::{include_dir, Dir}; use mime_guess::from_path; @@ -12,7 +12,9 @@ use warp::{http::Response, ws::Message, Filter}; /// Embed at compile time everything in dist/ /// This embeds the entire frontend code into the binary which includes the web-view and playground-common -static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); +/// NOTE: requires web-panel for vscode to be built +static STATIC_DIR: Dir<'_> = + include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); // Does not matter what this is, it is not currently used in the playground static ROOT_PATH: &str = "."; @@ -82,7 +84,7 @@ pub fn setup_file_watcher(state: Arc>, baml_src: &Path) -> Res if let Ok(watcher) = FileWatcher::new(baml_src.to_str().unwrap()) { let state_clone = state.clone(); if let Err(e) = watcher.watch(move |path| { - bdebug!("BAML file changed: {}", path); + // bdebug!("BAML file changed: {}", path); // Reload the file and update state let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { @@ -90,8 +92,6 @@ pub fn setup_file_watcher(state: Arc>, baml_src: &Path) -> Res // Remove the modified file from state state.files.remove(path); // Re-add it if it still exists - // NOTE: there should be a way to determine if its a delete or move event - // from the file watcher instead of re-checking the entire directory if let Ok(content) = fs::read_to_string(path) { state.files.insert(path.to_string(), content); } @@ -122,7 +122,7 @@ pub fn create_routes( ws.on_upgrade(move |socket| client_connection(socket, state)) }); - // Static file serving needed to serve the index.html of the frontend playground + // Static file serving needed to serve the frontend files let spa = warp::path::full() .and(warp::get()) From 4f9925dad2e1dd6e3bef854826dad8a22595228e Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 11 Jun 2025 22:14:39 -0700 Subject: [PATCH 10/71] basic LSP playground embed --- engine/language_server/Cargo.toml | 5 + engine/language_server/src/lib.rs | 5 +- .../src/playground/definitions.rs | 45 ++++++ engine/language_server/src/playground/mod.rs | 7 + .../src/playground/playground.rs | 30 ++++ .../src/playground/playground_server.rs | 151 ++++++++++++++++++ engine/language_server/src/server.rs | 40 +++++ engine/language_server/src/session.rs | 55 ++++++- .../language_server/src/session/settings.rs | 7 + 9 files changed, 341 insertions(+), 4 deletions(-) create mode 100644 engine/language_server/src/playground/definitions.rs create mode 100644 engine/language_server/src/playground/mod.rs create mode 100644 engine/language_server/src/playground/playground.rs create mode 100644 engine/language_server/src/playground/playground_server.rs diff --git a/engine/language_server/Cargo.toml b/engine/language_server/Cargo.toml index 459e205b5d..f66de25533 100644 --- a/engine/language_server/Cargo.toml +++ b/engine/language_server/Cargo.toml @@ -71,6 +71,11 @@ simple-logging = "2.0.2" itertools = "0.14.0" url.workspace = true +tokio = { version = "1.36", features = ["full"] } +warp = "0.3" +futures-util = "0.3" +include_dir = "0.7" +mime_guess = "2.0.4" [dev-dependencies] insta = { version = "1.42.1" } diff --git a/engine/language_server/src/lib.rs b/engine/language_server/src/lib.rs index 9df5364338..75c6503794 100644 --- a/engine/language_server/src/lib.rs +++ b/engine/language_server/src/lib.rs @@ -10,8 +10,9 @@ use crate::server::Server; #[macro_use] mod message; -mod edit; -mod logging; +pub mod edit; +pub mod logging; +pub mod playground; pub mod server; pub mod session; #[cfg(test)] diff --git a/engine/language_server/src/playground/definitions.rs b/engine/language_server/src/playground/definitions.rs new file mode 100644 index 0000000000..c2af37ef3e --- /dev/null +++ b/engine/language_server/src/playground/definitions.rs @@ -0,0 +1,45 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use tokio::sync::broadcast; + +// Note: the name add_project should match exactly to the +// EventListener.tsx command definitions due to how serde serializes these into json +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "command", content = "content")] +pub enum FrontendMessage { + add_project { + root_path: String, + files: HashMap, + }, + remove_project { + root_path: String, + }, + select_function { + root_path: String, + function_name: String, + }, + baml_settings_updated { + settings: HashMap, + }, + run_test { + test_name: String, + }, +} + +#[derive(Debug)] +pub struct PlaygroundState { + pub tx: broadcast::Sender, +} + +impl PlaygroundState { + pub fn new() -> Self { + let (tx, _) = broadcast::channel(100); + Self { tx } + } + + pub fn broadcast_update(&self, msg: String) -> anyhow::Result<()> { + self.tx.send(msg)?; + Ok(()) + } +} diff --git a/engine/language_server/src/playground/mod.rs b/engine/language_server/src/playground/mod.rs new file mode 100644 index 0000000000..22e7e0f79d --- /dev/null +++ b/engine/language_server/src/playground/mod.rs @@ -0,0 +1,7 @@ +pub mod definitions; +pub mod playground; +pub mod playground_server; + +pub use definitions::{FrontendMessage, PlaygroundState}; +pub use playground::PlaygroundServer; +pub use playground_server::{broadcast_project_update, create_routes}; diff --git a/engine/language_server/src/playground/playground.rs b/engine/language_server/src/playground/playground.rs new file mode 100644 index 0000000000..76d979efcb --- /dev/null +++ b/engine/language_server/src/playground/playground.rs @@ -0,0 +1,30 @@ +/// Script to run the playground server based of a specified directory. +/// Currently uses a custom filewatcher which detects changes to files in +/// the directory and refreshes the web-view. +use crate::playground::definitions::PlaygroundState; +use crate::playground::playground_server::{broadcast_project_update, create_routes}; +use crate::session::Session; +use anyhow::Result; +use std::sync::Arc; +use tokio::sync::RwLock; + +#[derive(Debug)] +pub struct PlaygroundServer { + state: Arc>, + session: Arc, +} + +impl PlaygroundServer { + pub fn new(session: Arc) -> Self { + Self { + state: Arc::new(RwLock::new(PlaygroundState::new())), + session, + } + } + + pub async fn run(self, port: u16) -> Result<()> { + let routes = create_routes(self.state, self.session); + warp::serve(routes).run(([127, 0, 0, 1], port)).await; + Ok(()) + } +} diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs new file mode 100644 index 0000000000..7d85474922 --- /dev/null +++ b/engine/language_server/src/playground/playground_server.rs @@ -0,0 +1,151 @@ +use crate::playground::definitions::{FrontendMessage, PlaygroundState}; +use crate::session::Session; +use anyhow::Result; +use futures_util::{SinkExt, StreamExt}; +use include_dir::{include_dir, Dir}; +use mime_guess::from_path; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::RwLock; +use warp::{http::Response, ws::Message, Filter}; + +/// Embed at compile time everything in dist/ +static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); + +pub async fn client_connection( + ws: warp::ws::WebSocket, + state: Arc>, + session: Arc, +) { + let (mut ws_tx, mut ws_rx) = ws.split(); + let mut rx = { + let state = state.read().await; + state.tx.subscribe() + }; + + // Send initial project state + let projects = { + let projects = session.baml_src_projects.lock().unwrap(); + projects + .iter() + .map(|(root_path, project)| { + let project = project.lock().unwrap(); + let files = project.baml_project.files.clone(); + let root_path = root_path.to_string_lossy().to_string(); + + // Convert files to the expected format + let files_map: HashMap = files + .into_iter() + .map(|(path, doc)| (path.path().to_string_lossy().to_string(), doc.contents)) + .collect(); + + (root_path, files_map) + }) + .collect::>() + }; + + // Send each project's files + for (root_path, files_map) in projects { + let add_project_msg = FrontendMessage::add_project { + root_path, + files: files_map, + }; + + if let Ok(msg_str) = serde_json::to_string(&add_project_msg) { + if let Err(e) = ws_tx.send(Message::text(msg_str)).await { + tracing::error!("Failed to send initial project state: {}", e); + return; + } + } + } + + // Handle incoming messages and broadcast updates + tokio::spawn(async move { + loop { + tokio::select! { + // Handle incoming messages from the client + Some(result) = ws_rx.next() => { + match result { + Ok(msg) => { + if msg.is_close() { + tracing::info!("Client disconnected"); + break; + } + } + Err(e) => { + tracing::error!("WebSocket error: {}", e); + break; + } + } + } + // Handle broadcast messages + Ok(msg) = rx.recv() => { + if let Err(e) = ws_tx.send(Message::text(msg)).await { + tracing::error!("Failed to send broadcast message: {}", e); + break; + } + } + else => break, + } + } + }); +} + +pub fn create_routes( + state: Arc>, + session: Arc, +) -> impl Filter + Clone { + // WebSocket handler with error handling + let ws_route = warp::path("ws") + .and(warp::ws()) + .map(move |ws: warp::ws::Ws| { + let state = state.clone(); + let session = session.clone(); + ws.on_upgrade(move |socket| async move { + client_connection(socket, state, session).await; + }) + }); + + // Static file serving needed to serve the frontend files + let spa = + warp::path::full() + .and(warp::get()) + .and_then(|full: warp::path::FullPath| async move { + let path = full.as_str().trim_start_matches('/'); + let file = if path.is_empty() { "index.html" } else { path }; + match STATIC_DIR.get_file(file) { + Some(f) => { + let body = f.contents(); + let mime = from_path(file).first_or_octet_stream(); + Ok::<_, warp::Rejection>( + Response::builder() + .header("content-type", mime.as_ref()) + .body(body.to_vec()), + ) + } + None => Ok::<_, warp::Rejection>( + Response::builder().status(404).body(b"Not Found".to_vec()), + ), + } + }); + + ws_route.or(spa).with(warp::log("playground-server")) +} + +// Helper function to broadcast project updates with better error handling +pub async fn broadcast_project_update( + state: &Arc>, + root_path: &str, + files: HashMap, +) -> Result<()> { + let add_project_msg = FrontendMessage::add_project { + root_path: root_path.to_string(), + files, + }; + + let msg_str = serde_json::to_string(&add_project_msg)?; + if let Err(e) = state.read().await.broadcast_update(msg_str) { + tracing::error!("Failed to broadcast project update: {}", e); + } + Ok(()) +} diff --git a/engine/language_server/src/server.rs b/engine/language_server/src/server.rs index 0ddec6a318..316534f6ea 100644 --- a/engine/language_server/src/server.rs +++ b/engine/language_server/src/server.rs @@ -9,7 +9,9 @@ use std::num::NonZeroUsize; #[allow(deprecated)] use std::panic::PanicInfo; use std::path::PathBuf; +use std::sync::Arc; use std::time::{Duration, Instant}; +use tokio::sync::RwLock; use lsp_server::Message; use lsp_types::{ @@ -35,6 +37,8 @@ mod schedule; use crate::message::try_show_message; pub(crate) use connection::ClientSender; +use crate::playground::{PlaygroundServer, PlaygroundState}; + pub type Result = std::result::Result; pub(crate) struct Server { @@ -137,11 +141,15 @@ impl Server { tracing::info!("Starting server with {} worker threads", worker_threads); tracing::info!("-------- Version: {}", env!("CARGO_PKG_VERSION")); + // Create a new tokio runtime for the playground server + let rt = tokio::runtime::Runtime::new()?; + let mut session = Session::new( &client_capabilities, position_encoding, global_settings, &workspaces, + rt.handle().clone(), )?; // Create a client and notifier to pass to reload @@ -151,6 +159,38 @@ impl Server { // Reload the session with the notifier session.reload(Some(notifier))?; + // Initialize playground state if enabled + // if session.baml_settings.enable_playground { + let playground_state = Arc::new(RwLock::new(PlaygroundState::new())); + session.playground_state = Some(playground_state.clone()); + + // Update session_arc with the new session that has playground state + let session_arc = Arc::new(session.clone()); + + // Create and start the playground server + let playground_server = PlaygroundServer::new(session_arc); + let playground_port = session.baml_settings.playground_port.unwrap_or(3030); + + // Spawn the playground server on the runtime + rt.spawn(async move { + match playground_server.run(playground_port).await { + Ok(_) => tracing::info!( + "Hosted playground at http://localhost:{}...", + playground_port + ), + Err(e) => tracing::error!("Failed to start playground server: {}", e), + } + }); + + tracing::info!( + "Hosted playground at http://localhost:{}...", + playground_port + ); + // } + + // Store the runtime in the session + session.playground_runtime = Some(rt); + Ok(Self { connection, worker_threads, diff --git a/engine/language_server/src/session.rs b/engine/language_server/src/session.rs index aa6bd6fbfb..b69186812b 100644 --- a/engine/language_server/src/session.rs +++ b/engine/language_server/src/session.rs @@ -30,8 +30,8 @@ mod capabilities; pub mod index; mod settings; -// TODO(dhruvmanila): In general, the server shouldn't use any salsa queries directly and instead -// should use methods on `ProjectDatabase`. +use crate::playground::{broadcast_project_update, PlaygroundState}; +use tokio::sync::{broadcast, RwLock}; /// The global state for the LSP #[derive(Debug)] @@ -48,6 +48,20 @@ pub struct Session { pub resolved_client_capabilities: Arc, pub baml_settings: BamlSettings, + + pub playground_state: Option>>, + + /// Runtime for the playground server + pub playground_runtime: Option, +} + +impl Drop for Session { + fn drop(&mut self) { + // Shutdown the playground runtime if it exists + if let Some(runtime) = self.playground_runtime.take() { + runtime.shutdown_timeout(std::time::Duration::from_secs(1)); + } + } } impl Clone for Session { @@ -58,6 +72,8 @@ impl Clone for Session { position_encoding: self.position_encoding.clone(), resolved_client_capabilities: self.resolved_client_capabilities.clone(), baml_settings: self.baml_settings.clone(), + playground_state: self.playground_state.clone(), + playground_runtime: None, // Don't clone the runtime } } } @@ -68,6 +84,7 @@ impl Session { position_encoding: PositionEncoding, global_settings: ClientSettings, workspace_folders: &[(Url, ClientSettings)], + runtime_handle: tokio::runtime::Handle, ) -> anyhow::Result { let mut projects = HashMap::new(); let index = index::Index::new(global_settings.clone()); @@ -105,6 +122,8 @@ impl Session { client_capabilities, )), baml_settings: BamlSettings::default(), + playground_state: None, + playground_runtime: None, }) } @@ -235,6 +254,37 @@ impl Session { }); log::info!("Reloaded {} files", files.len()); + // Broadcast the update using the playground runtime + if let Some(runtime) = &self.playground_runtime { + let state = self.playground_state.clone(); + tracing::info!("Runtime init!!"); + tracing::info!("state: {:?}", state); + if let Some(state) = state { + tracing::info!("Broadcasting project update to play-ground!!!"); + let projects = self.baml_src_projects.lock().unwrap(); + for (root_path, project) in projects.iter() { + let project = project.lock().unwrap(); + let files = project.baml_project.files.clone(); + let root_path = root_path.to_string_lossy().to_string(); + let files_map: HashMap = files + .into_iter() + .map(|(path, doc)| { + (path.path().to_string_lossy().to_string(), doc.contents) + }) + .collect(); + + let state = state.clone(); + runtime.spawn(async move { + if let Err(e) = + broadcast_project_update(&state, &root_path, files_map).await + { + tracing::error!("Failed to broadcast project update: {}", e); + } + }); + } + } + } + Ok(()) } @@ -428,6 +478,7 @@ mod tests { position_encoding, global_settings, &workspace_folders, + tokio::runtime::Handle::current(), ) .unwrap() } diff --git a/engine/language_server/src/session/settings.rs b/engine/language_server/src/session/settings.rs index 5826b8e929..9d2cad010a 100644 --- a/engine/language_server/src/session/settings.rs +++ b/engine/language_server/src/session/settings.rs @@ -13,6 +13,13 @@ pub(crate) type WorkspaceSettingsMap = FxHashMap; pub struct BamlSettings { pub(crate) cli_path: Option, pub(crate) generate_code_on_save: Option, + #[serde(default = "default_enable_playground")] + pub enable_playground: bool, + pub playground_port: Option, +} + +fn default_enable_playground() -> bool { + true } /// This is a direct representation of the settings schema sent by the client. From 0c795978dbdcc119737534a94b50016cc7e09f3a Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 12 Jun 2025 11:14:41 -0700 Subject: [PATCH 11/71] add reciever to keep broadcast channel alive --- .../src/playground/definitions.rs | 6 +++-- .../src/playground/playground_server.rs | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/engine/language_server/src/playground/definitions.rs b/engine/language_server/src/playground/definitions.rs index c2af37ef3e..6aec610b99 100644 --- a/engine/language_server/src/playground/definitions.rs +++ b/engine/language_server/src/playground/definitions.rs @@ -30,12 +30,14 @@ pub enum FrontendMessage { #[derive(Debug)] pub struct PlaygroundState { pub tx: broadcast::Sender, + // Keep a reference to the receiver to prevent the channel from being closed + _rx: broadcast::Receiver, } impl PlaygroundState { pub fn new() -> Self { - let (tx, _) = broadcast::channel(100); - Self { tx } + let (tx, rx) = broadcast::channel(100); + Self { tx, _rx: rx } } pub fn broadcast_update(&self, msg: String) -> anyhow::Result<()> { diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 7d85474922..7da8dc1fdd 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -71,6 +71,28 @@ pub async fn client_connection( tracing::info!("Client disconnected"); break; } + + // Process incoming messages + if let Ok(text) = msg.to_str() { + if let Ok(frontend_msg) = serde_json::from_str::(text) { + match frontend_msg { + FrontendMessage::add_project { root_path, files } => { + // Echo back the message to confirm receipt + if let Ok(msg_str) = serde_json::to_string(&frontend_msg) { + if let Err(e) = ws_tx.send(Message::text(msg_str)).await { + tracing::error!("Failed to echo add_project message: {}", e); + break; + } + } + } + _ => { + tracing::info!("Received unhandled message type: {:?}", frontend_msg); + } + } + } else { + tracing::warn!("Failed to parse message as FrontendMessage: {}", text); + } + } } Err(e) => { tracing::error!("WebSocket error: {}", e); From e2cddddf318d69d0b1a11e4c1db785e25cfcc5f5 Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 12 Jun 2025 11:49:57 -0700 Subject: [PATCH 12/71] web update on save working --- .../src/playground/definitions.rs | 3 +- .../src/playground/playground.rs | 9 +-- .../src/playground/playground_server.rs | 63 ++++++------------- engine/language_server/src/server.rs | 20 ++---- 4 files changed, 31 insertions(+), 64 deletions(-) diff --git a/engine/language_server/src/playground/definitions.rs b/engine/language_server/src/playground/definitions.rs index 6aec610b99..5f49246c76 100644 --- a/engine/language_server/src/playground/definitions.rs +++ b/engine/language_server/src/playground/definitions.rs @@ -41,7 +41,8 @@ impl PlaygroundState { } pub fn broadcast_update(&self, msg: String) -> anyhow::Result<()> { - self.tx.send(msg)?; + let n = self.tx.send(msg)?; + tracing::debug!("broadcast sent to {n} receivers"); Ok(()) } } diff --git a/engine/language_server/src/playground/playground.rs b/engine/language_server/src/playground/playground.rs index 76d979efcb..08b64d6323 100644 --- a/engine/language_server/src/playground/playground.rs +++ b/engine/language_server/src/playground/playground.rs @@ -2,7 +2,7 @@ /// Currently uses a custom filewatcher which detects changes to files in /// the directory and refreshes the web-view. use crate::playground::definitions::PlaygroundState; -use crate::playground::playground_server::{broadcast_project_update, create_routes}; +use crate::playground::playground_server::create_routes; use crate::session::Session; use anyhow::Result; use std::sync::Arc; @@ -15,11 +15,8 @@ pub struct PlaygroundServer { } impl PlaygroundServer { - pub fn new(session: Arc) -> Self { - Self { - state: Arc::new(RwLock::new(PlaygroundState::new())), - session, - } + pub fn new(state: Arc>, session: Arc) -> Self { + Self { state, session } } pub async fn run(self, port: u16) -> Result<()> { diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 7da8dc1fdd..65d883a9bb 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -12,18 +12,11 @@ use warp::{http::Response, ws::Message, Filter}; /// Embed at compile time everything in dist/ static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); -pub async fn client_connection( - ws: warp::ws::WebSocket, - state: Arc>, - session: Arc, +/// Helper to send all projects/files to a websocket client +pub async fn send_all_projects_to_client( + ws_tx: &mut (impl SinkExt + Unpin), + session: &Arc, ) { - let (mut ws_tx, mut ws_rx) = ws.split(); - let mut rx = { - let state = state.read().await; - state.tx.subscribe() - }; - - // Send initial project state let projects = { let projects = session.baml_src_projects.lock().unwrap(); projects @@ -32,32 +25,38 @@ pub async fn client_connection( let project = project.lock().unwrap(); let files = project.baml_project.files.clone(); let root_path = root_path.to_string_lossy().to_string(); - - // Convert files to the expected format let files_map: HashMap = files .into_iter() .map(|(path, doc)| (path.path().to_string_lossy().to_string(), doc.contents)) .collect(); - (root_path, files_map) }) .collect::>() }; - - // Send each project's files for (root_path, files_map) in projects { let add_project_msg = FrontendMessage::add_project { root_path, files: files_map, }; - if let Ok(msg_str) = serde_json::to_string(&add_project_msg) { - if let Err(e) = ws_tx.send(Message::text(msg_str)).await { - tracing::error!("Failed to send initial project state: {}", e); - return; - } + let _ = ws_tx.send(Message::text(msg_str)).await; } } +} + +pub async fn client_connection( + ws: warp::ws::WebSocket, + state: Arc>, + session: Arc, +) { + let (mut ws_tx, mut ws_rx) = ws.split(); + let mut rx = { + let state = state.read().await; + state.tx.subscribe() + }; + + // Send initial project state using the helper + send_all_projects_to_client(&mut ws_tx, &session).await; // Handle incoming messages and broadcast updates tokio::spawn(async move { @@ -71,28 +70,6 @@ pub async fn client_connection( tracing::info!("Client disconnected"); break; } - - // Process incoming messages - if let Ok(text) = msg.to_str() { - if let Ok(frontend_msg) = serde_json::from_str::(text) { - match frontend_msg { - FrontendMessage::add_project { root_path, files } => { - // Echo back the message to confirm receipt - if let Ok(msg_str) = serde_json::to_string(&frontend_msg) { - if let Err(e) = ws_tx.send(Message::text(msg_str)).await { - tracing::error!("Failed to echo add_project message: {}", e); - break; - } - } - } - _ => { - tracing::info!("Received unhandled message type: {:?}", frontend_msg); - } - } - } else { - tracing::warn!("Failed to parse message as FrontendMessage: {}", text); - } - } } Err(e) => { tracing::error!("WebSocket error: {}", e); diff --git a/engine/language_server/src/server.rs b/engine/language_server/src/server.rs index 316534f6ea..571408ee49 100644 --- a/engine/language_server/src/server.rs +++ b/engine/language_server/src/server.rs @@ -156,9 +156,6 @@ impl Server { let client = client::Client::new(connection.make_sender()); let notifier = client.notifier(); - // Reload the session with the notifier - session.reload(Some(notifier))?; - // Initialize playground state if enabled // if session.baml_settings.enable_playground { let playground_state = Arc::new(RwLock::new(PlaygroundState::new())); @@ -167,20 +164,12 @@ impl Server { // Update session_arc with the new session that has playground state let session_arc = Arc::new(session.clone()); - // Create and start the playground server - let playground_server = PlaygroundServer::new(session_arc); + // Create and start the playground server using the shared playground_state + let playground_server = PlaygroundServer::new(playground_state.clone(), session_arc); let playground_port = session.baml_settings.playground_port.unwrap_or(3030); // Spawn the playground server on the runtime - rt.spawn(async move { - match playground_server.run(playground_port).await { - Ok(_) => tracing::info!( - "Hosted playground at http://localhost:{}...", - playground_port - ), - Err(e) => tracing::error!("Failed to start playground server: {}", e), - } - }); + rt.spawn(playground_server.run(playground_port)); tracing::info!( "Hosted playground at http://localhost:{}...", @@ -191,6 +180,9 @@ impl Server { // Store the runtime in the session session.playground_runtime = Some(rt); + // Reload the session with the notifier + session.reload(Some(notifier))?; + Ok(Self { connection, worker_threads, From 6922f1ee373fbd3d42d4e13d6088d89c62f12d92 Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 12 Jun 2025 12:18:14 -0700 Subject: [PATCH 13/71] did_change test --- .../server/api/notifications/did_change.rs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/engine/language_server/src/server/api/notifications/did_change.rs b/engine/language_server/src/server/api/notifications/did_change.rs index 7ca6e36336..f2c7747de4 100644 --- a/engine/language_server/src/server/api/notifications/did_change.rs +++ b/engine/language_server/src/server/api/notifications/did_change.rs @@ -2,7 +2,9 @@ use std::time::Instant; use lsp_types::notification::DidChangeTextDocument; use lsp_types::{DidChangeTextDocumentParams, PublishDiagnosticsParams}; +use std::collections::HashMap; +use crate::playground::broadcast_project_update; use crate::server::api::diagnostics::publish_diagnostics; use crate::server::api::traits::{NotificationHandler, SyncNotificationHandler}; use crate::server::api::ResultExt; @@ -52,6 +54,39 @@ impl SyncNotificationHandler for DidChangeTextDocumentHandler { ) .internal_error()?; + // Broadcast the update using the playground runtime + if let Some(runtime) = &session.playground_runtime { + let state = session.playground_state.clone(); + tracing::info!("Runtime init!!"); + tracing::info!("state: {:?}", state); + if let Some(state) = state { + tracing::info!("Broadcasting project update to play-ground!!!"); + let projects = session.baml_src_projects.lock().unwrap(); + for (root_path, project) in projects.iter() { + let project = project.lock().unwrap(); + let files = project.baml_project.files.clone(); + let root_path = root_path.to_string_lossy().to_string(); + let files_map: HashMap = files + .into_iter() + .map(|(path, doc)| { + (path.path().to_string_lossy().to_string(), doc.contents) + }) + .collect(); + + tracing::info!("files_map: {:?}", files_map); + + let state = state.clone(); + runtime.spawn(async move { + if let Err(e) = + broadcast_project_update(&state, &root_path, files_map).await + { + tracing::error!("Failed to broadcast project update: {}", e); + } + }); + } + } + } + tracing::info!("publishing diagnostics"); publish_diagnostics(¬ifier, project, Some(params.text_document.version))?; From 48a74c2f9c42100260f84af74b9947b15eef119a Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 12 Jun 2025 13:46:01 -0700 Subject: [PATCH 14/71] working unsaved update passthrough from lsp to playground --- .../server/api/notifications/did_change.rs | 57 +++++++++--------- engine/language_server/src/session.rs | 58 +++++++++---------- 2 files changed, 56 insertions(+), 59 deletions(-) diff --git a/engine/language_server/src/server/api/notifications/did_change.rs b/engine/language_server/src/server/api/notifications/did_change.rs index f2c7747de4..20ab9cd278 100644 --- a/engine/language_server/src/server/api/notifications/did_change.rs +++ b/engine/language_server/src/server/api/notifications/did_change.rs @@ -54,36 +54,33 @@ impl SyncNotificationHandler for DidChangeTextDocumentHandler { ) .internal_error()?; - // Broadcast the update using the playground runtime - if let Some(runtime) = &session.playground_runtime { - let state = session.playground_state.clone(); - tracing::info!("Runtime init!!"); - tracing::info!("state: {:?}", state); - if let Some(state) = state { - tracing::info!("Broadcasting project update to play-ground!!!"); - let projects = session.baml_src_projects.lock().unwrap(); - for (root_path, project) in projects.iter() { - let project = project.lock().unwrap(); - let files = project.baml_project.files.clone(); - let root_path = root_path.to_string_lossy().to_string(); - let files_map: HashMap = files - .into_iter() - .map(|(path, doc)| { - (path.path().to_string_lossy().to_string(), doc.contents) - }) - .collect(); - - tracing::info!("files_map: {:?}", files_map); - - let state = state.clone(); - runtime.spawn(async move { - if let Err(e) = - broadcast_project_update(&state, &root_path, files_map).await - { - tracing::error!("Failed to broadcast project update: {}", e); - } - }); - } + // Broadcast update to playground clients + if let Some(state) = &session.playground_state { + let project = project.lock().unwrap(); + let files_map: std::collections::HashMap = project + .baml_project + .files + .iter() + .map(|(path, doc)| { + let key = path.path().to_string_lossy().to_string(); + // If there's an unsaved version, use it + let contents = project + .baml_project + .unsaved_files + .get(path) + .map(|unsaved| unsaved.contents.clone()) + .unwrap_or_else(|| doc.contents.clone()); + (key, contents) + }) + .collect(); + let root_path = project.root_path().to_string_lossy().to_string(); + let state = state.clone(); + if let Some(runtime) = &session.playground_runtime { + runtime.spawn(async move { + let _ = + crate::playground::broadcast_project_update(&state, &root_path, files_map) + .await; + }); } } diff --git a/engine/language_server/src/session.rs b/engine/language_server/src/session.rs index b69186812b..fde3f4f422 100644 --- a/engine/language_server/src/session.rs +++ b/engine/language_server/src/session.rs @@ -255,35 +255,35 @@ impl Session { log::info!("Reloaded {} files", files.len()); // Broadcast the update using the playground runtime - if let Some(runtime) = &self.playground_runtime { - let state = self.playground_state.clone(); - tracing::info!("Runtime init!!"); - tracing::info!("state: {:?}", state); - if let Some(state) = state { - tracing::info!("Broadcasting project update to play-ground!!!"); - let projects = self.baml_src_projects.lock().unwrap(); - for (root_path, project) in projects.iter() { - let project = project.lock().unwrap(); - let files = project.baml_project.files.clone(); - let root_path = root_path.to_string_lossy().to_string(); - let files_map: HashMap = files - .into_iter() - .map(|(path, doc)| { - (path.path().to_string_lossy().to_string(), doc.contents) - }) - .collect(); - - let state = state.clone(); - runtime.spawn(async move { - if let Err(e) = - broadcast_project_update(&state, &root_path, files_map).await - { - tracing::error!("Failed to broadcast project update: {}", e); - } - }); - } - } - } + // if let Some(runtime) = &self.playground_runtime { + // let state = self.playground_state.clone(); + // tracing::info!("Runtime init!!"); + // tracing::info!("state: {:?}", state); + // if let Some(state) = state { + // tracing::info!("Broadcasting project update to play-ground!!!"); + // let projects = self.baml_src_projects.lock().unwrap(); + // for (root_path, project) in projects.iter() { + // let project = project.lock().unwrap(); + // let files = project.baml_project.files.clone(); + // let root_path = root_path.to_string_lossy().to_string(); + // let files_map: HashMap = files + // .into_iter() + // .map(|(path, doc)| { + // (path.path().to_string_lossy().to_string(), doc.contents) + // }) + // .collect(); + + // let state = state.clone(); + // runtime.spawn(async move { + // if let Err(e) = + // broadcast_project_update(&state, &root_path, files_map).await + // { + // tracing::error!("Failed to broadcast project update: {}", e); + // } + // }); + // } + // } + // } Ok(()) } From f565298699e8833d92a6077d6bd5a8bceea609b2 Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 12 Jun 2025 14:02:52 -0700 Subject: [PATCH 15/71] Connection error for webview --- engine/Cargo.lock | 5 ++ .../src/playground/playground_server.rs | 4 +- engine/language_server/src/session.rs | 31 ------------ .../src/baml_wasm_web/EventListener.tsx | 50 +++++++++++++++++-- 4 files changed, 54 insertions(+), 36 deletions(-) diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 9ddea153a2..7b9d84216f 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -3815,7 +3815,9 @@ dependencies = [ "crossbeam", "crossbeam-channel", "filetime", + "futures-util", "ignore", + "include_dir", "indexmap 2.8.0", "insta", "internal-baml-codegen", @@ -3829,6 +3831,7 @@ dependencies = [ "lsp-server", "lsp-types", "memchr", + "mime_guess", "path-absolutize", "pathdiff 0.2.2", "regex", @@ -3842,10 +3845,12 @@ dependencies = [ "similar", "simple-logging", "thiserror 2.0.12", + "tokio", "tracing", "tracing-log", "tracing-subscriber", "url", + "warp", ] [[package]] diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 65d883a9bb..d3fbf666c9 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -10,7 +10,9 @@ use tokio::sync::RwLock; use warp::{http::Response, ws::Message, Filter}; /// Embed at compile time everything in dist/ -static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); +// static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); +static STATIC_DIR: Dir<'_> = + include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); /// Helper to send all projects/files to a websocket client pub async fn send_all_projects_to_client( diff --git a/engine/language_server/src/session.rs b/engine/language_server/src/session.rs index fde3f4f422..a44f4f2b21 100644 --- a/engine/language_server/src/session.rs +++ b/engine/language_server/src/session.rs @@ -254,37 +254,6 @@ impl Session { }); log::info!("Reloaded {} files", files.len()); - // Broadcast the update using the playground runtime - // if let Some(runtime) = &self.playground_runtime { - // let state = self.playground_state.clone(); - // tracing::info!("Runtime init!!"); - // tracing::info!("state: {:?}", state); - // if let Some(state) = state { - // tracing::info!("Broadcasting project update to play-ground!!!"); - // let projects = self.baml_src_projects.lock().unwrap(); - // for (root_path, project) in projects.iter() { - // let project = project.lock().unwrap(); - // let files = project.baml_project.files.clone(); - // let root_path = root_path.to_string_lossy().to_string(); - // let files_map: HashMap = files - // .into_iter() - // .map(|(path, doc)| { - // (path.path().to_string_lossy().to_string(), doc.contents) - // }) - // .collect(); - - // let state = state.clone(); - // runtime.spawn(async move { - // if let Err(e) = - // broadcast_project_update(&state, &root_path, files_map).await - // { - // tracing::error!("Failed to broadcast project update: {}", e); - // } - // }); - // } - // } - // } - Ok(()) } diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index 7832d81882..9d4d3475d6 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -4,7 +4,7 @@ import 'react18-json-view/src/style.css' import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai' import { atomWithStorage } from 'jotai/utils' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import CustomErrorBoundary from '../utils/ErrorFallback' import { vscodeLocalStorageStore } from './JotaiProvider' import { vscode } from '@/shared/baml-project-panel/vscode' @@ -78,12 +78,38 @@ const ErrorCount: React.FC = () => { ) } +export const isConnectedAtom = atom(true) + +const ConnectionStatus: React.FC = () => { + const isConnected = useAtomValue(isConnectedAtom) + const isVSCodeWebview = typeof vscode !== 'undefined' + + if (isVSCodeWebview || isConnected) return null + + return ( +
+
+ + Disconnected from LSP server +
+ +
+ ) +} + // We don't use ASTContext.provider because we should the default value of the context export const EventListener: React.FC<{ children: React.ReactNode }> = ({ children }) => { const updateCursor = useSetAtom(updateCursorAtom) const setFiles = useSetAtom(filesAtom) const debouncedSetFiles = useDebounceCallback(setFiles, 50, true) const setFlashRanges = useSetAtom(flashRangesAtom) + const setIsConnected = useSetAtom(isConnectedAtom) + const isVSCodeWebview = typeof vscode !== 'undefined' const [selectedFunc, setSelectedFunction] = useAtom(selectedFunctionAtom) const setSelectedTestcase = useSetAtom(selectedTestcaseAtom) @@ -113,10 +139,18 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre console.log('selectedFunc', selectedFunc) useEffect(() => { + if (isVSCodeWebview) { + setIsConnected(true) + return + } + const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' const ws = new WebSocket(`${scheme}://${window.location.host}/ws`) - ws.onopen = () => console.log('WebSocket connected') + ws.onopen = () => { + console.log('WebSocket connected') + setIsConnected(true) + } ws.onmessage = (e) => { console.log('message!') try { @@ -126,10 +160,17 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre console.error('invalid WS payload', err) } } - ws.onclose = () => console.log('WebSocket disconnected') + ws.onclose = () => { + console.log('WebSocket disconnected') + setIsConnected(false) + } + ws.onerror = () => { + console.error('WebSocket error') + setIsConnected(false) + } return () => ws.close() - }, []) + }, [setIsConnected, isVSCodeWebview]) console.log('Websocket execution finished') @@ -267,6 +308,7 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre return ( <> +
{bamlCliVersion && 'baml-cli ' + bamlCliVersion}
VSCode Runtime Version: {version} From 59db9b17ef149fd504cde92eaec60e88ae715586 Mon Sep 17 00:00:00 2001 From: Sam Lijin Date: Fri, 30 May 2025 11:25:50 -0700 Subject: [PATCH 16/71] fix icon, description --- jetbrains/README.md | 2 +- jetbrains/build.gradle.kts | 23 ++++++++++--------- jetbrains/gradle.properties | 2 +- .../main/resources/META-INF/pluginIcon.svg | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) mode change 100644 => 120000 jetbrains/src/main/resources/META-INF/pluginIcon.svg diff --git a/jetbrains/README.md b/jetbrains/README.md index 622651b1eb..b8610d9ca7 100644 --- a/jetbrains/README.md +++ b/jetbrains/README.md @@ -12,7 +12,7 @@ > Click the Use this template button and clone it in IntelliJ IDEA. -**IntelliJ Platform Plugin Template** is a repository that provides a pure template to make it easier to create a new plugin project (check the [Creating a repository from a template][gh:template] article). +**baml placeholder** is a repository that provides a pure template to make it easier to create a new plugin project (check the [Creating a repository from a template][gh:template] article). The main goal of this template is to speed up the setup phase of plugin development for both new and experienced developers by preconfiguring the project scaffold and CI, linking to the proper documentation pages, and keeping everything organized. diff --git a/jetbrains/build.gradle.kts b/jetbrains/build.gradle.kts index 6a8994acfe..4304d99821 100644 --- a/jetbrains/build.gradle.kts +++ b/jetbrains/build.gradle.kts @@ -55,17 +55,18 @@ intellijPlatform { version = providers.gradleProperty("pluginVersion") // Extract the section from README.md and provide for the plugin's manifest - description = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map { - val start = "" - val end = "" - - with(it.lines()) { - if (!containsAll(listOf(start, end))) { - throw GradleException("Plugin description section not found in README.md:\n$start ... $end") - } - subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) - } - } + description = providers.fileContents(layout.projectDirectory.file("../README.md")).asText.map(::markdownToHTML) +// description = providers.fileContents(layout.projectDirectory.file("../README.md")).asText.map { +// val start = "" +// val end = "" +// +// with(it.lines()) { +// if (!containsAll(listOf(start, end))) { +// throw GradleException("Plugin description section not found in README.md:\n$start ... $end") +// } +// subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) +// } +// } val changelog = project.changelog // local variable for configuration cache compatibility // Get the latest available change notes from the changelog file diff --git a/jetbrains/gradle.properties b/jetbrains/gradle.properties index 580cee43e4..5b8f6ac6de 100644 --- a/jetbrains/gradle.properties +++ b/jetbrains/gradle.properties @@ -5,7 +5,7 @@ pluginName = BoundaryML pluginId = baml pluginRepositoryUrl = https://github.com/boundaryml/baml # SemVer format -> https://semver.org -pluginVersion = 0.88.0-beta +pluginVersion = 0.88.4-beta # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # To depend on the TextMate bundle API, the plugin must start build from 241 diff --git a/jetbrains/src/main/resources/META-INF/pluginIcon.svg b/jetbrains/src/main/resources/META-INF/pluginIcon.svg deleted file mode 100644 index fb1499c55d..0000000000 --- a/jetbrains/src/main/resources/META-INF/pluginIcon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/jetbrains/src/main/resources/META-INF/pluginIcon.svg b/jetbrains/src/main/resources/META-INF/pluginIcon.svg new file mode 120000 index 0000000000..303b688230 --- /dev/null +++ b/jetbrains/src/main/resources/META-INF/pluginIcon.svg @@ -0,0 +1 @@ +../icons/baml-lamb-purple.svg \ No newline at end of file From 5904fb3e4013600b4627b05d0241c35f7f92cf81 Mon Sep 17 00:00:00 2001 From: Sam Lijin Date: Fri, 30 May 2025 14:24:07 -0700 Subject: [PATCH 17/71] MyBundle -> BamlBundle --- .../boundaryml/jetbrains_ext/{MyBundle.kt => BamlBundle.kt} | 4 ++-- jetbrains/src/main/resources/META-INF/plugin.xml | 2 +- .../messages/{MyBundle.properties => BamlBundle.properties} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/{MyBundle.kt => BamlBundle.kt} (83%) rename jetbrains/src/main/resources/messages/{MyBundle.properties => BamlBundle.properties} (100%) diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/MyBundle.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlBundle.kt similarity index 83% rename from jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/MyBundle.kt rename to jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlBundle.kt index 220df7b334..412d5022ef 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/MyBundle.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlBundle.kt @@ -5,9 +5,9 @@ import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.PropertyKey @NonNls -private const val BUNDLE = "messages.MyBundle" +private const val BUNDLE = "messages.BamlBundle" -object MyBundle : DynamicBundle(BUNDLE) { +object BamlBundle : DynamicBundle(BUNDLE) { @JvmStatic fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = diff --git a/jetbrains/src/main/resources/META-INF/plugin.xml b/jetbrains/src/main/resources/META-INF/plugin.xml index 4443a7c324..65b8ddfe7a 100644 --- a/jetbrains/src/main/resources/META-INF/plugin.xml +++ b/jetbrains/src/main/resources/META-INF/plugin.xml @@ -7,7 +7,7 @@ com.intellij.modules.platform org.jetbrains.plugins.textmate - messages.MyBundle + messages.BamlBundle Date: Fri, 30 May 2025 16:32:47 -0700 Subject: [PATCH 18/71] set up lang server runner --- .../input/named-args/single/named-enum.baml | 2 +- jetbrains/build.gradle.kts | 4 +++ jetbrains/gradle.properties | 2 +- .../jetbrains_ext/BamlLanguageServer.java | 13 ++++++++++ .../BamlLanguageServerFactory.java | 26 +++++++++++++++++++ .../com/boundaryml/jetbrains_ext/BamlIcons.kt | 2 +- .../jetbrains_ext/BamlProjectService.kt | 6 ++++- .../main/resources/META-INF/baml-lsp4ij.xml | 22 ++++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 4 +++ 9 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer.java create mode 100644 jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java create mode 100644 jetbrains/src/main/resources/META-INF/baml-lsp4ij.xml diff --git a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-enum.baml b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-enum.baml index 839c56128f..3a24f7b11d 100644 --- a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-enum.baml +++ b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-enum.baml @@ -12,7 +12,7 @@ function FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string { } test FnTestNamedArgsSingleEnum { - functions [FnTestNamedArgsSingleEnum] + fuctns [FnTestNamedArgsSingleEnum] args { myArg ONE } diff --git a/jetbrains/build.gradle.kts b/jetbrains/build.gradle.kts index 4304d99821..dbbd56e44a 100644 --- a/jetbrains/build.gradle.kts +++ b/jetbrains/build.gradle.kts @@ -46,6 +46,10 @@ dependencies { testFramework(TestFrameworkType.Platform) } + +// implementation("com.redhat.microprofile:com.redhat.qute.ls:0.17.0") { +// exclude("org.eclipse.lsp4j") +// } } // Configure IntelliJ Platform Gradle Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html diff --git a/jetbrains/gradle.properties b/jetbrains/gradle.properties index 5b8f6ac6de..1d0e988bbd 100644 --- a/jetbrains/gradle.properties +++ b/jetbrains/gradle.properties @@ -22,7 +22,7 @@ platformVersion = 2024.2.5 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.jetbrains.php:203.4449.22, org.intellij.scala:2023.3.27@EAP -platformPlugins = +platformPlugins = com.redhat.devtools.lsp4ij:0.13.0 # Example: platformBundledPlugins = com.intellij.java platformBundledPlugins = org.jetbrains.plugins.textmate diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer.java new file mode 100644 index 0000000000..056c10c692 --- /dev/null +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer.java @@ -0,0 +1,13 @@ +package com.boundaryml.jetbrains_ext; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.redhat.devtools.lsp4ij.server.OSProcessStreamConnectionProvider; + +public class BamlLanguageServer extends OSProcessStreamConnectionProvider { + + public BamlLanguageServer() { + System.out.printf("baml language server started via osprocess\n"); + GeneralCommandLine commandLine = new GeneralCommandLine("/Users/sam/baml3/engine/target/debug/baml-cli", "lsp"); + super.setCommandLine(commandLine); + } +} diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java new file mode 100644 index 0000000000..0bdac568f1 --- /dev/null +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java @@ -0,0 +1,26 @@ +package com.boundaryml.jetbrains_ext; + +import com.intellij.openapi.project.Project; +import com.redhat.devtools.lsp4ij.LanguageServerFactory; +import com.redhat.devtools.lsp4ij.client.LanguageClientImpl; +import com.redhat.devtools.lsp4ij.server.StreamConnectionProvider; +import org.jetbrains.annotations.NotNull; + +public class BamlLanguageServerFactory implements LanguageServerFactory { + + @Override + public @NotNull StreamConnectionProvider createConnectionProvider(@NotNull Project project) { + return new BamlLanguageServer(); + } +// +// @Override // If you need to provide client specific features +// public @NotNull LanguageClientImpl createLanguageClient(@NotNull Project project) { +// return new BamlLanguageServerFactory(project); +// } + +// @Override // If you need to expose a custom server API +// public @NotNull Class getServerInterface() { +// return MyCustomServerAPI.class; +// } + +} diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlIcons.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlIcons.kt index d4fab6eed0..9ad13cad6b 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlIcons.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlIcons.kt @@ -4,5 +4,5 @@ import com.intellij.openapi.util.IconLoader import javax.swing.Icon object BamlIcons { - val FILETYPE: Icon = IconLoader.getIcon("/icons/baml-lamb-purple.svg", BamlIcons::class.java) + public val FILETYPE: Icon = IconLoader.getIcon("/icons/baml-lamb-purple.svg", BamlIcons::class.java) } \ No newline at end of file diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlProjectService.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlProjectService.kt index ce06c6eff4..bb63190917 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlProjectService.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlProjectService.kt @@ -9,9 +9,13 @@ import com.intellij.openapi.project.Project class BamlProjectService(project: Project) { init { - thisLogger().info(MyBundle.message("projectService", project.name)) + thisLogger().info(BamlBundle.message("projectService", project.name)) thisLogger().info("BAML Jetbrains extension service has started") } fun getRandomNumber() = (1..100).random() + + fun downloadCli(cliVersion: String) { + println("Downloading CLI version={cliVersion}") + } } \ No newline at end of file diff --git a/jetbrains/src/main/resources/META-INF/baml-lsp4ij.xml b/jetbrains/src/main/resources/META-INF/baml-lsp4ij.xml new file mode 100644 index 0000000000..d284f8439f --- /dev/null +++ b/jetbrains/src/main/resources/META-INF/baml-lsp4ij.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jetbrains/src/main/resources/META-INF/plugin.xml b/jetbrains/src/main/resources/META-INF/plugin.xml index 65b8ddfe7a..7185dca694 100644 --- a/jetbrains/src/main/resources/META-INF/plugin.xml +++ b/jetbrains/src/main/resources/META-INF/plugin.xml @@ -6,6 +6,7 @@ com.intellij.modules.platform org.jetbrains.plugins.textmate + com.redhat.devtools.lsp4ij messages.BamlBundle @@ -39,4 +40,7 @@ + + From 15591c7eb53eee6b91adb09ba9750177de68f56f Mon Sep 17 00:00:00 2001 From: Sam Lijin Date: Fri, 30 May 2025 17:13:08 -0700 Subject: [PATCH 19/71] add working code --- jetbrains/gradle.properties | 3 +- .../BamlLanguageServerFactory.java | 11 +++ .../BamlLanguageServerInstaller.java | 98 +++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java diff --git a/jetbrains/gradle.properties b/jetbrains/gradle.properties index 1d0e988bbd..fe2a779013 100644 --- a/jetbrains/gradle.properties +++ b/jetbrains/gradle.properties @@ -22,7 +22,8 @@ platformVersion = 2024.2.5 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.jetbrains.php:203.4449.22, org.intellij.scala:2023.3.27@EAP -platformPlugins = com.redhat.devtools.lsp4ij:0.13.0 +#platformPlugins = com.redhat.devtools.lsp4ij:0.13.0 +platformPlugins = com.redhat.devtools.lsp4ij:0.13.1-20250530-194419@nightly # Example: platformBundledPlugins = com.intellij.java platformBundledPlugins = org.jetbrains.plugins.textmate diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java index 0bdac568f1..37c4fc647f 100644 --- a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java @@ -3,6 +3,7 @@ import com.intellij.openapi.project.Project; import com.redhat.devtools.lsp4ij.LanguageServerFactory; import com.redhat.devtools.lsp4ij.client.LanguageClientImpl; +import com.redhat.devtools.lsp4ij.client.features.LSPClientFeatures; import com.redhat.devtools.lsp4ij.server.StreamConnectionProvider; import org.jetbrains.annotations.NotNull; @@ -12,6 +13,14 @@ public class BamlLanguageServerFactory implements LanguageServerFactory { public @NotNull StreamConnectionProvider createConnectionProvider(@NotNull Project project) { return new BamlLanguageServer(); } + + @Override + public LSPClientFeatures createClientFeatures() { +// return null; + var features = new LSPClientFeatures(); + features.setServerInstaller(new BamlLanguageServerInstaller()); // customize language server installer + return features; + } // // @Override // If you need to provide client specific features // public @NotNull LanguageClientImpl createLanguageClient(@NotNull Project project) { @@ -24,3 +33,5 @@ public class BamlLanguageServerFactory implements LanguageServerFactory { // } } + + diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java new file mode 100644 index 0000000000..fe34bf06ee --- /dev/null +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java @@ -0,0 +1,98 @@ +package com.boundaryml.jetbrains_ext; + +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.redhat.devtools.lsp4ij.installation.LanguageServerInstallerBase; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +public class BamlLanguageServerInstaller extends LanguageServerInstallerBase { + + private static final Path BAML_CACHE_DIR = Path.of(System.getProperty("user.home"), ".baml"); + private static final Path BREADCRUMB_PATH = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github"); + private static final Path TAR_GZ_PATH = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github.tar.gz"); + + @Override + protected boolean checkServerInstalled(@NotNull ProgressIndicator indicator) { + progress("Checking if the language server is installed...", indicator); + ProgressManager.checkCanceled(); + return Files.exists(BREADCRUMB_PATH); + } + + @Override + protected void install(@NotNull ProgressIndicator indicator) throws Exception { + progress("Downloading server components...", 0.25, indicator); + Thread.sleep(1000); + ProgressManager.checkCanceled(); + + progress("Configuring server...", 0.5, indicator); + Thread.sleep(1000); + ProgressManager.checkCanceled(); + + progress("Finalizing installation...", 0.75, indicator); + Thread.sleep(1000); + ProgressManager.checkCanceled(); + + // Simulate writing a breadcrumb file to mark successful installation + Files.createDirectories(BREADCRUMB_PATH.getParent()); + String urlStr = "https://github.com/BoundaryML/baml/releases/download/0.89.0/baml-cli-0.89.0-aarch64-apple-darwin.tar.gz"; + // Step 1: Download the file + downloadFile(urlStr, TAR_GZ_PATH); + // Step 2: Extract the archive + extractTarGz(TAR_GZ_PATH, BAML_CACHE_DIR); + // TODO: make extracted files writable +// Files.writeString(BREADCRUMB_PATH, "baml-cli installed", StandardOpenOption.CREATE, StandardOpenOption.APPEND); + + progress("Installation complete!", 1.0, indicator); + Thread.sleep(1000); + ProgressManager.checkCanceled(); + } + + + + + private static void downloadFile(String urlStr, Path outputPath) throws IOException { + HttpURLConnection conn = (HttpURLConnection) new URL(urlStr).openConnection(); + conn.setInstanceFollowRedirects(true); + conn.connect(); + + try (InputStream in = conn.getInputStream(); + OutputStream out = Files.newOutputStream(outputPath)) { + in.transferTo(out); + } + System.out.println("Downloaded to " + outputPath); + } + + private static void extractTarGz(Path tarGzPath, Path destDir) throws IOException { + try (InputStream fileIn = Files.newInputStream(tarGzPath); + GzipCompressorInputStream gzipIn = new GzipCompressorInputStream(fileIn); + TarArchiveInputStream tarIn = new TarArchiveInputStream(gzipIn)) { + + TarArchiveEntry entry; + while ((entry = tarIn.getNextTarEntry()) != null) { + Path outPath = destDir.resolve(entry.getName()); + if (entry.isDirectory()) { + Files.createDirectories(outPath); + } else { + Files.createDirectories(outPath.getParent()); + try (OutputStream out = Files.newOutputStream(outPath)) { + tarIn.transferTo(out); + } + } + } + } + System.out.println("Extraction complete."); + } +} From 19df09c6ee18de3aae20081cb3c5226a785d5a9c Mon Sep 17 00:00:00 2001 From: Sam Lijin Date: Mon, 2 Jun 2025 12:09:53 -0700 Subject: [PATCH 20/71] better comment --- .../boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java index fe34bf06ee..27b4fdda02 100644 --- a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java @@ -52,7 +52,7 @@ protected void install(@NotNull ProgressIndicator indicator) throws Exception { downloadFile(urlStr, TAR_GZ_PATH); // Step 2: Extract the archive extractTarGz(TAR_GZ_PATH, BAML_CACHE_DIR); - // TODO: make extracted files writable + // TODO: make extracted files executable // Files.writeString(BREADCRUMB_PATH, "baml-cli installed", StandardOpenOption.CREATE, StandardOpenOption.APPEND); progress("Installation complete!", 1.0, indicator); From f551b70c74fda262f1df2fff049e3fb38a609c1a Mon Sep 17 00:00:00 2001 From: Sam Lijin Date: Fri, 13 Jun 2025 14:59:20 -0700 Subject: [PATCH 21/71] java to kotlin --- integ-tests/baml_src/generators.baml | 5 - .../input/named-args/single/named-enum.baml | 2 +- ...geServer.java => BamlLanguageServer2.java} | 4 +- ...y.java => BamlLanguageServerFactory2.java} | 7 +- ...java => BamlLanguageServerInstaller2.java} | 4 +- .../boundaryml/jetbrains_ext/BamlBundle.kt | 2 +- .../com/boundaryml/jetbrains_ext/BamlIcons.kt | 1 + .../jetbrains_ext/BamlLanguageServer.kt | 13 +++ .../BamlLanguageServerFactory.kt | 29 ++++++ .../BamlLanguageServerInstaller.kt | 92 +++++++++++++++++++ .../main/resources/META-INF/baml-lsp4ij.xml | 2 +- 11 files changed, 144 insertions(+), 17 deletions(-) rename jetbrains/src/main/java/com/boundaryml/jetbrains_ext/{BamlLanguageServer.java => BamlLanguageServer2.java} (79%) rename jetbrains/src/main/java/com/boundaryml/jetbrains_ext/{BamlLanguageServerFactory.java => BamlLanguageServerFactory2.java} (83%) rename jetbrains/src/main/java/com/boundaryml/jetbrains_ext/{BamlLanguageServerInstaller.java => BamlLanguageServerInstaller2.java} (96%) create mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt create mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt create mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt diff --git a/integ-tests/baml_src/generators.baml b/integ-tests/baml_src/generators.baml index 752ff59b4e..7c2ff28435 100644 --- a/integ-tests/baml_src/generators.baml +++ b/integ-tests/baml_src/generators.baml @@ -4,11 +4,6 @@ generator lang_python { version "0.89.0" } -generator lang_python_v1 { - output_type python/pydantic/v1 - output_dir "../python-v1" - version "0.89.0" -} generator lang_typescript { output_type typescript diff --git a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-enum.baml b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-enum.baml index 3a24f7b11d..839c56128f 100644 --- a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-enum.baml +++ b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-enum.baml @@ -12,7 +12,7 @@ function FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string { } test FnTestNamedArgsSingleEnum { - fuctns [FnTestNamedArgsSingleEnum] + functions [FnTestNamedArgsSingleEnum] args { myArg ONE } diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer2.java similarity index 79% rename from jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer.java rename to jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer2.java index 056c10c692..8f1e5b9c45 100644 --- a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer.java +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer2.java @@ -3,9 +3,9 @@ import com.intellij.execution.configurations.GeneralCommandLine; import com.redhat.devtools.lsp4ij.server.OSProcessStreamConnectionProvider; -public class BamlLanguageServer extends OSProcessStreamConnectionProvider { +public class BamlLanguageServer2 extends OSProcessStreamConnectionProvider { - public BamlLanguageServer() { + public BamlLanguageServer2() { System.out.printf("baml language server started via osprocess\n"); GeneralCommandLine commandLine = new GeneralCommandLine("/Users/sam/baml3/engine/target/debug/baml-cli", "lsp"); super.setCommandLine(commandLine); diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory2.java similarity index 83% rename from jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java rename to jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory2.java index 37c4fc647f..1494d9f8be 100644 --- a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.java +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory2.java @@ -2,23 +2,22 @@ import com.intellij.openapi.project.Project; import com.redhat.devtools.lsp4ij.LanguageServerFactory; -import com.redhat.devtools.lsp4ij.client.LanguageClientImpl; import com.redhat.devtools.lsp4ij.client.features.LSPClientFeatures; import com.redhat.devtools.lsp4ij.server.StreamConnectionProvider; import org.jetbrains.annotations.NotNull; -public class BamlLanguageServerFactory implements LanguageServerFactory { +public class BamlLanguageServerFactory2 implements LanguageServerFactory { @Override public @NotNull StreamConnectionProvider createConnectionProvider(@NotNull Project project) { - return new BamlLanguageServer(); + return new BamlLanguageServer2(); } @Override public LSPClientFeatures createClientFeatures() { // return null; var features = new LSPClientFeatures(); - features.setServerInstaller(new BamlLanguageServerInstaller()); // customize language server installer + features.setServerInstaller(new BamlLanguageServerInstaller2()); // customize language server installer return features; } // diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller2.java similarity index 96% rename from jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java rename to jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller2.java index 27b4fdda02..a9c5af9dba 100644 --- a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.java +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller2.java @@ -8,7 +8,6 @@ import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.jetbrains.annotations.NotNull; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -16,9 +15,8 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -public class BamlLanguageServerInstaller extends LanguageServerInstallerBase { +public class BamlLanguageServerInstaller2 extends LanguageServerInstallerBase { private static final Path BAML_CACHE_DIR = Path.of(System.getProperty("user.home"), ".baml"); private static final Path BREADCRUMB_PATH = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github"); diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlBundle.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlBundle.kt index 412d5022ef..4f24452445 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlBundle.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlBundle.kt @@ -5,7 +5,7 @@ import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.PropertyKey @NonNls -private const val BUNDLE = "messages.BamlBundle" +private const val BUNDLE: String = "messages.BamlBundle" object BamlBundle : DynamicBundle(BUNDLE) { diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlIcons.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlIcons.kt index 9ad13cad6b..4ac41dc50b 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlIcons.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlIcons.kt @@ -4,5 +4,6 @@ import com.intellij.openapi.util.IconLoader import javax.swing.Icon object BamlIcons { + @JvmField public val FILETYPE: Icon = IconLoader.getIcon("/icons/baml-lamb-purple.svg", BamlIcons::class.java) } \ No newline at end of file diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt new file mode 100644 index 0000000000..27469cde47 --- /dev/null +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt @@ -0,0 +1,13 @@ +package com.boundaryml.jetbrains_ext + +import com.intellij.execution.configurations.GeneralCommandLine +import com.redhat.devtools.lsp4ij.server.OSProcessStreamConnectionProvider + +class BamlLanguageServer : OSProcessStreamConnectionProvider() { + + init { + println("baml language server started via osprocess") + val commandLine = GeneralCommandLine("/Users/sam/baml3/engine/target/debug/baml-cli", "lsp") + super.setCommandLine(commandLine) + } +} diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt new file mode 100644 index 0000000000..2aa368e03f --- /dev/null +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt @@ -0,0 +1,29 @@ +package com.boundaryml.jetbrains_ext + +import com.intellij.openapi.project.Project +import com.redhat.devtools.lsp4ij.LanguageServerFactory +import com.redhat.devtools.lsp4ij.client.features.LSPClientFeatures +import com.redhat.devtools.lsp4ij.server.StreamConnectionProvider + +class BamlLanguageServerFactory : LanguageServerFactory { + + override fun createConnectionProvider(project: Project): StreamConnectionProvider { + return BamlLanguageServer() + } + + override fun createClientFeatures(): LSPClientFeatures { + val features = LSPClientFeatures() + features.setServerInstaller(BamlLanguageServerInstaller()) // customize language server installer + return features + } + +// // If you need to provide client specific features +// override fun createLanguageClient(project: Project): LanguageClientImpl { +// return BamlLanguageServerFactory(project) +// } + +// // If you need to expose a custom server API +// override fun getServerInterface(): Class { +// return MyCustomServerAPI::class.java +// } +} diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt new file mode 100644 index 0000000000..c8513766e0 --- /dev/null +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt @@ -0,0 +1,92 @@ +package com.boundaryml.jetbrains_ext + +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.ProgressManager +import com.redhat.devtools.lsp4ij.installation.LanguageServerInstallerBase +import org.apache.commons.compress.archivers.tar.TarArchiveEntry +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream +import org.jetbrains.annotations.NotNull +import java.io.File +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import java.net.HttpURLConnection +import java.net.URL +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardOpenOption + +class BamlLanguageServerInstaller : LanguageServerInstallerBase() { + + private val BAML_CACHE_DIR: Path = Path.of(System.getProperty("user.home"), ".baml") + private val BREADCRUMB_PATH: Path = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github") + private val TAR_GZ_PATH: Path = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github.tar.gz") + + override fun checkServerInstalled(indicator: ProgressIndicator): Boolean { + super.progress("Checking if the language server is installed...", indicator) + ProgressManager.checkCanceled() + return Files.exists(BREADCRUMB_PATH) + } + + override fun install(indicator: ProgressIndicator) { + super.progress("Downloading server components...", 0.25, indicator) + Thread.sleep(1000) + ProgressManager.checkCanceled() + + super.progress("Configuring server...", 0.5, indicator) + Thread.sleep(1000) + ProgressManager.checkCanceled() + + super.progress("Finalizing installation...", 0.75, indicator) + Thread.sleep(1000) + ProgressManager.checkCanceled() + + Files.createDirectories(BREADCRUMB_PATH.parent) + val urlStr = "https://github.com/BoundaryML/baml/releases/download/0.89.0/baml-cli-0.89.0-aarch64-apple-darwin.tar.gz" + + this.downloadFile(urlStr, TAR_GZ_PATH) + this.extractTarGz(TAR_GZ_PATH, BAML_CACHE_DIR) + + super.progress("Installation complete!", 1.0, indicator) + Thread.sleep(1000) + ProgressManager.checkCanceled() + } + + private fun downloadFile(urlStr: String, outputPath: Path) { + val url = URL(urlStr) + val conn = url.openConnection() as HttpURLConnection + conn.instanceFollowRedirects = true + conn.connect() + + conn.inputStream.use { input -> + Files.newOutputStream(outputPath).use { output -> + input.transferTo(output) + } + } + println("Downloaded to $outputPath") + } + + private fun extractTarGz(tarGzPath: Path, destDir: Path) { + Files.newInputStream(tarGzPath).use { fileIn -> + GzipCompressorInputStream(fileIn).use { gzipIn -> + TarArchiveInputStream(gzipIn).use { tarIn -> + var entry: TarArchiveEntry? = tarIn.nextTarEntry + while (entry != null) { + val outPath = destDir.resolve(entry.name) + if (entry.isDirectory) { + Files.createDirectories(outPath) + } else { + Files.createDirectories(outPath.parent) + Files.newOutputStream(outPath).use { out -> + tarIn.transferTo(out) + } + } + entry = tarIn.nextTarEntry + } + } + } + } + println("Extraction complete.") + } +} diff --git a/jetbrains/src/main/resources/META-INF/baml-lsp4ij.xml b/jetbrains/src/main/resources/META-INF/baml-lsp4ij.xml index d284f8439f..e3db68b73f 100644 --- a/jetbrains/src/main/resources/META-INF/baml-lsp4ij.xml +++ b/jetbrains/src/main/resources/META-INF/baml-lsp4ij.xml @@ -2,7 +2,7 @@ Date: Fri, 13 Jun 2025 15:12:39 -0700 Subject: [PATCH 22/71] delete the java code --- .../jetbrains_ext/BamlLanguageServer2.java | 13 --- .../BamlLanguageServerFactory2.java | 36 ------- .../BamlLanguageServerInstaller2.java | 96 ------------------- .../jetbrains_ext/ExampleJavaClass.java | 8 ++ .../src/main/resources/META-INF/plugin.xml | 52 ++++++++++ 5 files changed, 60 insertions(+), 145 deletions(-) delete mode 100644 jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer2.java delete mode 100644 jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory2.java delete mode 100644 jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller2.java create mode 100644 jetbrains/src/main/java/com/boundaryml/jetbrains_ext/ExampleJavaClass.java diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer2.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer2.java deleted file mode 100644 index 8f1e5b9c45..0000000000 --- a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServer2.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.boundaryml.jetbrains_ext; - -import com.intellij.execution.configurations.GeneralCommandLine; -import com.redhat.devtools.lsp4ij.server.OSProcessStreamConnectionProvider; - -public class BamlLanguageServer2 extends OSProcessStreamConnectionProvider { - - public BamlLanguageServer2() { - System.out.printf("baml language server started via osprocess\n"); - GeneralCommandLine commandLine = new GeneralCommandLine("/Users/sam/baml3/engine/target/debug/baml-cli", "lsp"); - super.setCommandLine(commandLine); - } -} diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory2.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory2.java deleted file mode 100644 index 1494d9f8be..0000000000 --- a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory2.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.boundaryml.jetbrains_ext; - -import com.intellij.openapi.project.Project; -import com.redhat.devtools.lsp4ij.LanguageServerFactory; -import com.redhat.devtools.lsp4ij.client.features.LSPClientFeatures; -import com.redhat.devtools.lsp4ij.server.StreamConnectionProvider; -import org.jetbrains.annotations.NotNull; - -public class BamlLanguageServerFactory2 implements LanguageServerFactory { - - @Override - public @NotNull StreamConnectionProvider createConnectionProvider(@NotNull Project project) { - return new BamlLanguageServer2(); - } - - @Override - public LSPClientFeatures createClientFeatures() { -// return null; - var features = new LSPClientFeatures(); - features.setServerInstaller(new BamlLanguageServerInstaller2()); // customize language server installer - return features; - } -// -// @Override // If you need to provide client specific features -// public @NotNull LanguageClientImpl createLanguageClient(@NotNull Project project) { -// return new BamlLanguageServerFactory(project); -// } - -// @Override // If you need to expose a custom server API -// public @NotNull Class getServerInterface() { -// return MyCustomServerAPI.class; -// } - -} - - diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller2.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller2.java deleted file mode 100644 index a9c5af9dba..0000000000 --- a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller2.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.boundaryml.jetbrains_ext; - -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.redhat.devtools.lsp4ij.installation.LanguageServerInstallerBase; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; - -public class BamlLanguageServerInstaller2 extends LanguageServerInstallerBase { - - private static final Path BAML_CACHE_DIR = Path.of(System.getProperty("user.home"), ".baml"); - private static final Path BREADCRUMB_PATH = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github"); - private static final Path TAR_GZ_PATH = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github.tar.gz"); - - @Override - protected boolean checkServerInstalled(@NotNull ProgressIndicator indicator) { - progress("Checking if the language server is installed...", indicator); - ProgressManager.checkCanceled(); - return Files.exists(BREADCRUMB_PATH); - } - - @Override - protected void install(@NotNull ProgressIndicator indicator) throws Exception { - progress("Downloading server components...", 0.25, indicator); - Thread.sleep(1000); - ProgressManager.checkCanceled(); - - progress("Configuring server...", 0.5, indicator); - Thread.sleep(1000); - ProgressManager.checkCanceled(); - - progress("Finalizing installation...", 0.75, indicator); - Thread.sleep(1000); - ProgressManager.checkCanceled(); - - // Simulate writing a breadcrumb file to mark successful installation - Files.createDirectories(BREADCRUMB_PATH.getParent()); - String urlStr = "https://github.com/BoundaryML/baml/releases/download/0.89.0/baml-cli-0.89.0-aarch64-apple-darwin.tar.gz"; - // Step 1: Download the file - downloadFile(urlStr, TAR_GZ_PATH); - // Step 2: Extract the archive - extractTarGz(TAR_GZ_PATH, BAML_CACHE_DIR); - // TODO: make extracted files executable -// Files.writeString(BREADCRUMB_PATH, "baml-cli installed", StandardOpenOption.CREATE, StandardOpenOption.APPEND); - - progress("Installation complete!", 1.0, indicator); - Thread.sleep(1000); - ProgressManager.checkCanceled(); - } - - - - - private static void downloadFile(String urlStr, Path outputPath) throws IOException { - HttpURLConnection conn = (HttpURLConnection) new URL(urlStr).openConnection(); - conn.setInstanceFollowRedirects(true); - conn.connect(); - - try (InputStream in = conn.getInputStream(); - OutputStream out = Files.newOutputStream(outputPath)) { - in.transferTo(out); - } - System.out.println("Downloaded to " + outputPath); - } - - private static void extractTarGz(Path tarGzPath, Path destDir) throws IOException { - try (InputStream fileIn = Files.newInputStream(tarGzPath); - GzipCompressorInputStream gzipIn = new GzipCompressorInputStream(fileIn); - TarArchiveInputStream tarIn = new TarArchiveInputStream(gzipIn)) { - - TarArchiveEntry entry; - while ((entry = tarIn.getNextTarEntry()) != null) { - Path outPath = destDir.resolve(entry.getName()); - if (entry.isDirectory()) { - Files.createDirectories(outPath); - } else { - Files.createDirectories(outPath.getParent()); - try (OutputStream out = Files.newOutputStream(outPath)) { - tarIn.transferTo(out); - } - } - } - } - System.out.println("Extraction complete."); - } -} diff --git a/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/ExampleJavaClass.java b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/ExampleJavaClass.java new file mode 100644 index 0000000000..59e417d038 --- /dev/null +++ b/jetbrains/src/main/java/com/boundaryml/jetbrains_ext/ExampleJavaClass.java @@ -0,0 +1,8 @@ +package com.boundaryml.jetbrains_ext; + +public class ExampleJavaClass { + + public ExampleJavaClass() { + System.out.println("We should use Kotlin by default, but if we need to copy-paste Java code it can go here."); + } +} diff --git a/jetbrains/src/main/resources/META-INF/plugin.xml b/jetbrains/src/main/resources/META-INF/plugin.xml index 7185dca694..38affa5674 100644 --- a/jetbrains/src/main/resources/META-INF/plugin.xml +++ b/jetbrains/src/main/resources/META-INF/plugin.xml @@ -10,6 +10,58 @@ messages.BamlBundle + + + + + + + + + + + + + + + + + + + + + + + + + Date: Fri, 13 Jun 2025 17:49:20 -0700 Subject: [PATCH 23/71] add command support for LSP --- engine/language_server/src/server/api.rs | 1 + .../src/server/api/requests.rs | 2 +- .../src/server/api/requests/code_lens.rs | 17 ++++++ .../jetbrains_ext/OpenBamlPlaygroundAction.kt | 14 +++++ .../jetbrains_ext/RunBamlTestAction.kt | 14 +++++ .../src/main/resources/META-INF/plugin.xml | 59 ++++--------------- 6 files changed, 60 insertions(+), 47 deletions(-) create mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt create mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt diff --git a/engine/language_server/src/server/api.rs b/engine/language_server/src/server/api.rs index de8d5fafe0..eb71663ed8 100644 --- a/engine/language_server/src/server/api.rs +++ b/engine/language_server/src/server/api.rs @@ -72,6 +72,7 @@ pub(super) fn request<'a>(req: lsp_server::Request) -> Task<'a> { } request::Completion::METHOD => local_request_task::(req), request::CodeLens::METHOD => local_request_task::(req), + request::CodeLensResolve::METHOD => local_request_task::(req), request::GotoDefinition::METHOD => local_request_task::(req), request::Rename::METHOD => local_request_task::(req), request::DocumentDiagnosticRequestHandler::METHOD => { diff --git a/engine/language_server/src/server/api/requests.rs b/engine/language_server/src/server/api/requests.rs index 815a594acf..b46d4d6f56 100644 --- a/engine/language_server/src/server/api/requests.rs +++ b/engine/language_server/src/server/api/requests.rs @@ -6,7 +6,7 @@ mod go_to_definition; mod hover; mod rename; -pub use code_lens::CodeLens; +pub use code_lens::{CodeLens, CodeLensResolve}; pub(super) use completion::Completion; pub(super) use diagnostic::DocumentDiagnosticRequestHandler; pub(super) use format::DocumentFormatting; diff --git a/engine/language_server/src/server/api/requests/code_lens.rs b/engine/language_server/src/server/api/requests/code_lens.rs index cb9d13ce22..e556c9c995 100644 --- a/engine/language_server/src/server/api/requests/code_lens.rs +++ b/engine/language_server/src/server/api/requests/code_lens.rs @@ -136,3 +136,20 @@ impl SyncRequestHandler for CodeLens { Ok(Some(function_lenses)) } } + +pub struct CodeLensResolve; + +impl RequestHandler for CodeLensResolve { + type RequestType = request::CodeLensResolve; +} + +impl SyncRequestHandler for CodeLensResolve { + fn run( + session: &mut Session, + notifier: Notifier, + _requester: &mut Requester, + params: lsp_types::CodeLens, + ) -> Result { + Ok(params) + } +} diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt new file mode 100644 index 0000000000..6414633f68 --- /dev/null +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt @@ -0,0 +1,14 @@ +package com.boundaryml.jetbrains_ext + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.wm.ToolWindowManager + + +class OpenBamlPlaygroundAction : AnAction() { + + override fun actionPerformed(e: AnActionEvent) { + val project = e.project ?: return + ToolWindowManager.getInstance(project).getToolWindow("BAML Playground")?.show() + } +} \ No newline at end of file diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt new file mode 100644 index 0000000000..806995e73d --- /dev/null +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt @@ -0,0 +1,14 @@ +package com.boundaryml.jetbrains_ext + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.wm.ToolWindowManager + + +class RunBamlTestAction : AnAction() { + + override fun actionPerformed(e: AnActionEvent) { + val project = e.project ?: return + ToolWindowManager.getInstance(project).getToolWindow("BAML Playground")?.show() + } +} diff --git a/jetbrains/src/main/resources/META-INF/plugin.xml b/jetbrains/src/main/resources/META-INF/plugin.xml index 38affa5674..c1c6c5f882 100644 --- a/jetbrains/src/main/resources/META-INF/plugin.xml +++ b/jetbrains/src/main/resources/META-INF/plugin.xml @@ -13,52 +13,19 @@ - - - - - - - - - - - - - - - - - - - - + class="com.boundaryml.jetbrains_ext.OpenBamlPlaygroundAction" + text="Open BAML Playground" + description="Opens an interactive playground for running and testing BAML code." + icon="/icons/baml-lamb-light-mode.svg" + > + + From 91fb79178538da4089b331af3e8919bd21d29970 Mon Sep 17 00:00:00 2001 From: Sam Lijin Date: Fri, 13 Jun 2025 19:35:18 -0700 Subject: [PATCH 24/71] get a basic downloading impl partially working --- jetbrains/build.gradle.kts | 4 +- .../jetbrains_ext/BamlLanguageServer.kt | 4 +- .../BamlLanguageServerInstaller.kt | 222 ++++++++++++++---- 3 files changed, 173 insertions(+), 57 deletions(-) diff --git a/jetbrains/build.gradle.kts b/jetbrains/build.gradle.kts index dbbd56e44a..45f01edb94 100644 --- a/jetbrains/build.gradle.kts +++ b/jetbrains/build.gradle.kts @@ -47,9 +47,7 @@ dependencies { testFramework(TestFrameworkType.Platform) } -// implementation("com.redhat.microprofile:com.redhat.qute.ls:0.17.0") { -// exclude("org.eclipse.lsp4j") -// } + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") } // Configure IntelliJ Platform Gradle Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt index 27469cde47..c678e316ed 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt @@ -2,12 +2,12 @@ package com.boundaryml.jetbrains_ext import com.intellij.execution.configurations.GeneralCommandLine import com.redhat.devtools.lsp4ij.server.OSProcessStreamConnectionProvider +import java.nio.file.Path class BamlLanguageServer : OSProcessStreamConnectionProvider() { init { - println("baml language server started via osprocess") - val commandLine = GeneralCommandLine("/Users/sam/baml3/engine/target/debug/baml-cli", "lsp") + val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), ".baml/jetbrains", "baml-cli-0.89.0-aarch64-apple-darwin", "baml-cli").toString(), "lsp") super.setCommandLine(commandLine) } } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt index c8513766e0..bfd9a20890 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt @@ -2,91 +2,209 @@ package com.boundaryml.jetbrains_ext import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager +import com.intellij.util.io.HttpRequests import com.redhat.devtools.lsp4ij.installation.LanguageServerInstallerBase +import kotlinx.serialization.SerialName import org.apache.commons.compress.archivers.tar.TarArchiveEntry import org.apache.commons.compress.archivers.tar.TarArchiveInputStream import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream -import org.jetbrains.annotations.NotNull -import java.io.File -import java.io.IOException -import java.io.InputStream -import java.io.OutputStream -import java.net.HttpURLConnection -import java.net.URL -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardOpenOption +import java.nio.file.* +import java.nio.file.attribute.PosixFilePermission +import java.security.MessageDigest +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonNamingStrategy +import java.util.zip.ZipInputStream class BamlLanguageServerInstaller : LanguageServerInstallerBase() { - private val BAML_CACHE_DIR: Path = Path.of(System.getProperty("user.home"), ".baml") - private val BREADCRUMB_PATH: Path = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github") - private val TAR_GZ_PATH: Path = Path.of(System.getProperty("user.home"), ".baml", "baml-cli-0.89.0-from-github.tar.gz") + private val REPO = "BoundaryML/baml" + private val GH_API_LATEST = "https://api.github.com/repos/$REPO/releases/latest" + private val GH_RELEASES_BASE = "https://github.com/$REPO/releases/download" + + private val bamlCacheDir: Path = Path.of(System.getProperty("user.home"), ".baml/jetbrains") + private val breadcrumbFile: Path = bamlCacheDir.resolve("baml-cli-installed.txt") override fun checkServerInstalled(indicator: ProgressIndicator): Boolean { - super.progress("Checking if the language server is installed...", indicator) + super.progress("Checking if BAML CLI is installed...", indicator) ProgressManager.checkCanceled() - return Files.exists(BREADCRUMB_PATH) + return Files.exists(breadcrumbFile) } override fun install(indicator: ProgressIndicator) { - super.progress("Downloading server components...", 0.25, indicator) - Thread.sleep(1000) + super.progress("Installing BAML CLI...", indicator) ProgressManager.checkCanceled() - super.progress("Configuring server...", 0.5, indicator) - Thread.sleep(1000) - ProgressManager.checkCanceled() + val latestVersion = fetchLatestReleaseVersion(indicator) + val (arch, platform, extension) = getPlatformTriple() - super.progress("Finalizing installation...", 0.75, indicator) - Thread.sleep(1000) - ProgressManager.checkCanceled() + val artifactName = "baml-cli-$latestVersion-$arch-$platform" + val destDir = bamlCacheDir.resolve(artifactName) + val targetExecutable = if (platform == "pc-windows-msvc") + destDir.resolve("baml-cli.exe") + else + destDir.resolve("baml-cli") + + if (Files.exists(targetExecutable)) { + super.progress("BAML CLI already installed.", indicator) + return + } + + val archivePath = downloadFile(artifactName, extension, latestVersion, indicator) + verifyChecksum(artifactName, extension, latestVersion, archivePath, indicator) - Files.createDirectories(BREADCRUMB_PATH.parent) - val urlStr = "https://github.com/BoundaryML/baml/releases/download/0.89.0/baml-cli-0.89.0-aarch64-apple-darwin.tar.gz" + super.progress("Extracting BAML CLI...", indicator) + extractArchive(archivePath, extension, destDir) - this.downloadFile(urlStr, TAR_GZ_PATH) - this.extractTarGz(TAR_GZ_PATH, BAML_CACHE_DIR) + Files.deleteIfExists(archivePath) + setExecutable(targetExecutable) + + Files.createDirectories(bamlCacheDir) + Files.writeString(breadcrumbFile, latestVersion) super.progress("Installation complete!", 1.0, indicator) - Thread.sleep(1000) + } + + @Serializable + data class GitHubRelease( + @SerialName("tag_name") + val tagName: String + ) + + private fun fetchLatestReleaseVersion(indicator: ProgressIndicator): String { + super.progress("Fetching latest version info...", indicator) ProgressManager.checkCanceled() + + return try { + val jsonText = HttpRequests.request(GH_API_LATEST).readString() + val jsonParser = Json { + ignoreUnknownKeys = true + } + val release = jsonParser.decodeFromString(jsonText) + release.tagName.removePrefix("v") + } catch (e: Exception) { + super.progress("GitHub fetch failed, falling back to local cache...", indicator) + // hardcoded fallback to 0.89 + // TODO: fallback to latest downloaded version + "0.89.0" + } } - private fun downloadFile(urlStr: String, outputPath: Path) { - val url = URL(urlStr) - val conn = url.openConnection() as HttpURLConnection - conn.instanceFollowRedirects = true - conn.connect() + private fun getPlatformTriple(): Triple { + val os = System.getProperty("os.name").lowercase() + val arch = System.getProperty("os.arch").lowercase() + + val releaseArch = when { + arch.contains("aarch64") || arch.contains("arm64") -> "aarch64" + arch.contains("x86_64") || arch.contains("amd64") -> "x86_64" + else -> throw IllegalArgumentException("Unsupported architecture: $arch") + } + + val releasePlatform = when { + os.contains("mac") -> "apple-darwin" + os.contains("win") -> "pc-windows-msvc" + os.contains("linux") -> "unknown-linux-gnu" + else -> throw IllegalArgumentException("Unsupported platform: $os") + } + + val extension = when (releasePlatform) { + "pc-windows-msvc" -> "zip" + else -> "tar.gz" + } + + return Triple(releaseArch, releasePlatform, extension) + } - conn.inputStream.use { input -> - Files.newOutputStream(outputPath).use { output -> - input.transferTo(output) + private fun downloadFile(artifactName: String, extension: String, version: String, indicator: ProgressIndicator): Path { + val url = "$GH_RELEASES_BASE/$version/$artifactName.$extension" + val tempFile = Files.createTempFile("baml-cli", ".$extension") + + super.progress("Downloading $artifactName...", indicator) + ProgressManager.checkCanceled() + + HttpRequests.request(url).connect { request -> + request.saveToFile(tempFile.toFile(), indicator) + } + + return tempFile + } + + private fun verifyChecksum(artifactName: String, extension: String, version: String, archivePath: Path, indicator: ProgressIndicator) { + super.progress("Verifying checksum...", indicator) + ProgressManager.checkCanceled() + + val checksumUrl = "$GH_RELEASES_BASE/$version/$artifactName.$extension.sha256" + val checksumContent = HttpRequests.request(checksumUrl).readString().trim() + val expectedChecksum = checksumContent.split(Regex("\\s+"))[0] + val actualChecksum = calculateSha256(archivePath) + + if (!expectedChecksum.equals(actualChecksum, ignoreCase = true)) { + throw IllegalStateException("Checksum mismatch! Expected $expectedChecksum, got $actualChecksum") + } + } + + private fun calculateSha256(file: Path): String { + val digest = MessageDigest.getInstance("SHA-256") + Files.newInputStream(file).use { stream -> + val buffer = ByteArray(8192) + var read: Int + while (stream.read(buffer).also { read = it } != -1) { + digest.update(buffer, 0, read) } } - println("Downloaded to $outputPath") + return digest.digest().joinToString("") { "%02x".format(it) } } - private fun extractTarGz(tarGzPath: Path, destDir: Path) { - Files.newInputStream(tarGzPath).use { fileIn -> - GzipCompressorInputStream(fileIn).use { gzipIn -> - TarArchiveInputStream(gzipIn).use { tarIn -> - var entry: TarArchiveEntry? = tarIn.nextTarEntry - while (entry != null) { - val outPath = destDir.resolve(entry.name) - if (entry.isDirectory) { - Files.createDirectories(outPath) - } else { - Files.createDirectories(outPath.parent) - Files.newOutputStream(outPath).use { out -> - tarIn.transferTo(out) + private fun extractArchive(archivePath: Path, extension: String, destDir: Path) { + Files.createDirectories(destDir) + + if (extension == "tar.gz") { + Files.newInputStream(archivePath).use { fileIn -> + GzipCompressorInputStream(fileIn).use { gzipIn -> + TarArchiveInputStream(gzipIn).use { tarIn -> + var entry: TarArchiveEntry? = tarIn.nextTarEntry + while (entry != null) { + val outPath = destDir.resolve(entry.name) + if (entry.isDirectory) { + Files.createDirectories(outPath) + } else { + Files.createDirectories(outPath.parent) + Files.copy(tarIn, outPath, StandardCopyOption.REPLACE_EXISTING) } + entry = tarIn.nextTarEntry } - entry = tarIn.nextTarEntry } } } + } else if (extension == "zip") { + ZipInputStream(Files.newInputStream(archivePath)).use { zipIn -> + var entry = zipIn.nextEntry + while (entry != null) { + val outPath = destDir.resolve(entry.name) + if (entry.isDirectory) { + Files.createDirectories(outPath) + } else { + Files.createDirectories(outPath.parent) + Files.copy(zipIn, outPath, StandardCopyOption.REPLACE_EXISTING) + } + entry = zipIn.nextEntry + } + } + } else { + throw IllegalArgumentException("Unsupported archive extension: $extension") + } + } + + private fun setExecutable(file: Path) { + if (!Files.exists(file)) return + try { + val perms = Files.getPosixFilePermissions(file) + val updatedPerms = perms + setOf( + PosixFilePermission.OWNER_EXECUTE, + ) + Files.setPosixFilePermissions(file, updatedPerms) + } catch (e: UnsupportedOperationException) { + // Windows doesn't support POSIX permissions — safely ignore } - println("Extraction complete.") } } From 51e9208dbb410f8b956fb2468e285cea78838ba1 Mon Sep 17 00:00:00 2001 From: egol Date: Mon, 16 Jun 2025 14:46:28 -0700 Subject: [PATCH 25/71] init zed extension support --- engine/Cargo.lock | 178 ++++++++++++++++++++++- engine/Cargo.toml | 1 + engine/zed/.gitignore | 3 + engine/zed/Cargo.toml | 20 +++ engine/zed/extension.toml | 15 ++ engine/zed/languages/baml/config.toml | 9 ++ engine/zed/languages/baml/highlights.scm | 69 +++++++++ engine/zed/languages/baml/outline.scm | 0 engine/zed/languages/baml/runnables.scm | 0 engine/zed/src/lib.rs | 174 ++++++++++++++++++++++ 10 files changed, 468 insertions(+), 1 deletion(-) create mode 100644 engine/zed/.gitignore create mode 100644 engine/zed/Cargo.toml create mode 100644 engine/zed/extension.toml create mode 100644 engine/zed/languages/baml/config.toml create mode 100644 engine/zed/languages/baml/highlights.scm create mode 100644 engine/zed/languages/baml/outline.scm create mode 100644 engine/zed/languages/baml/runnables.scm create mode 100644 engine/zed/src/lib.rs diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 7b9d84216f..ff3d3db208 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -2837,6 +2837,9 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "heck" @@ -3229,6 +3232,12 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + [[package]] name = "ident_case" version = "1.0.1" @@ -3865,6 +3874,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" version = "0.2.171" @@ -5967,6 +5982,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spdx" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193" +dependencies = [ + "smallvec", +] + [[package]] name = "spin" version = "0.9.8" @@ -6682,6 +6706,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unindent" version = "0.2.3" @@ -6902,7 +6932,7 @@ version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen-rt 0.39.0", ] [[package]] @@ -7002,6 +7032,15 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "wasm-encoder" +version = "0.201.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a" +dependencies = [ + "leb128", +] + [[package]] name = "wasm-logger" version = "0.2.0" @@ -7013,6 +7052,22 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-metadata" +version = "0.201.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2" +dependencies = [ + "anyhow", + "indexmap 2.8.0", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder", + "wasmparser", +] + [[package]] name = "wasm-streams" version = "0.4.0" @@ -7026,6 +7081,17 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmparser" +version = "0.201.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708" +dependencies = [ + "bitflags 2.9.0", + "indexmap 2.8.0", + "semver", +] + [[package]] name = "wasmtimer" version = "0.4.1" @@ -7322,6 +7388,33 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wit-bindgen" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "288f992ea30e6b5c531b52cdd5f3be81c148554b09ea416f058d16556ba92c27" +dependencies = [ + "bitflags 2.9.0", + "wit-bindgen-rt 0.22.0", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e85e72719ffbccf279359ad071497e47eb0675fe22106dea4ed2d8a7fcb60ba4" +dependencies = [ + "anyhow", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb8738270f32a2d6739973cbbb7c1b6dd8959ce515578a6e19165853272ee64" + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -7331,6 +7424,71 @@ dependencies = [ "bitflags 2.9.0", ] +[[package]] +name = "wit-bindgen-rust" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a39a15d1ae2077688213611209849cad40e9e5cccf6e61951a425850677ff3" +dependencies = [ + "anyhow", + "heck 0.4.1", + "indexmap 2.8.0", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d376d3ae5850526dfd00d937faea0d81a06fa18f7ac1e26f386d760f241a8f4b" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.87", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.201.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825" +dependencies = [ + "anyhow", + "bitflags 2.9.0", + "indexmap 2.8.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.201.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.8.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "write16" version = "1.0.0" @@ -7379,6 +7537,24 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zed" +version = "0.89.0" +dependencies = [ + "zed_extension_api", +] + +[[package]] +name = "zed_extension_api" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "594fd10dd0f2f853eb243e2425e7c95938cef49adb81d9602921d002c5e6d9d9" +dependencies = [ + "serde", + "serde_json", + "wit-bindgen", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 08333c476c..7c11d5c7f1 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -16,6 +16,7 @@ members = [ "language_server", "language_client_cffi", "sandbox", + "zed", ] default-members = [ "baml-lsp-types", diff --git a/engine/zed/.gitignore b/engine/zed/.gitignore new file mode 100644 index 0000000000..eed2cb54de --- /dev/null +++ b/engine/zed/.gitignore @@ -0,0 +1,3 @@ +/target +/grammars +*.wasm \ No newline at end of file diff --git a/engine/zed/Cargo.toml b/engine/zed/Cargo.toml new file mode 100644 index 0000000000..3f5a6c448e --- /dev/null +++ b/engine/zed/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "zed" +edition = "2024" +version.workspace = true +authors.workspace = true +description.workspace = true +license-file.workspace = true + +[lib] +crate-type = ["cdylib"] + +[features] +# This enables the debug mode by default +# default = ["debug"] +# Use this for releases +default = [] +debug = [] + +[dependencies] +zed_extension_api = "0.1.0" diff --git a/engine/zed/extension.toml b/engine/zed/extension.toml new file mode 100644 index 0000000000..7c42ab9207 --- /dev/null +++ b/engine/zed/extension.toml @@ -0,0 +1,15 @@ +id = "baml" +name = "Baml" +description = "Baml support." +version = "0.0.1" +schema_version = 1 +authors = ["Boundary "] +repository = "https://github.com/zed-extensions/baml" + +[language_servers.baml-language-server] +name = "Baml Language Server" +language = "Baml" + +[grammars.baml] +repository = "https://github.com/BoundaryML/tree-sitter-baml" +commit = "3edd0d25e2cf352295ade681f4a2c2f3a9cdc58b" diff --git a/engine/zed/languages/baml/config.toml b/engine/zed/languages/baml/config.toml new file mode 100644 index 0000000000..441761b3ee --- /dev/null +++ b/engine/zed/languages/baml/config.toml @@ -0,0 +1,9 @@ +name = "Baml" +grammar = "baml" +path_suffixes = ["baml"] +line_comments = ["// ", "/// "] +# brackets = [ +# { start = "{", end = "}", close = true, newline = true }, +# { start = "[", end = "]", close = true, newline = true }, +# { start = "(", end = ")", close = true, newline = false }, +# ] \ No newline at end of file diff --git a/engine/zed/languages/baml/highlights.scm b/engine/zed/languages/baml/highlights.scm new file mode 100644 index 0000000000..1d4c8d73e1 --- /dev/null +++ b/engine/zed/languages/baml/highlights.scm @@ -0,0 +1,69 @@ +;; Comments +(comment) @comment +(doc_comment) @comment.doc +(block_comment) @comment + +;; Operators +[ + "->" + "|" + "=" + "?" + "[]" + "<" + ">" +] @operator + +;; Delimiters +[ + "{" + "}" + "(" + ")" + "," + ";" + ":" +] @punctuation.bracket + +;; Strings +[ + (raw_string_literal) + (quoted_string_literal) + (string_literal) + (unquoted_string_literal) +] @string + +;; Identifiers +(identifier) @variable + +(lambda) @function + +(value_expression_keyword) @keyword + +;; Types & declarations +(type_expression_block + block_keyword: (identifier) @keyword + name: (identifier) @type.name + args: (named_argument_list)? @type.arguments + body: (_) @type.body +) + +;; Arguments and parameters +(arguments_list) @parameter +(named_argument_list) @parameter + +;; Map keys +(map_key) @property.key + +;; Jinja expressions +(jinja_expression) @string + +;; Literals +(numeric_literal) @number + +;; ── LLM prompt calls ───────────────────────────────────────────────────────── +;; match only expressions of the form: prompt +((value_expression + name: (identifier) @keyword ; highlight the word "prompt" + value: (string_literal) @string) + (#eq? @keyword "prompt")) ; but only when the identifier text is "prompt" \ No newline at end of file diff --git a/engine/zed/languages/baml/outline.scm b/engine/zed/languages/baml/outline.scm new file mode 100644 index 0000000000..e69de29bb2 diff --git a/engine/zed/languages/baml/runnables.scm b/engine/zed/languages/baml/runnables.scm new file mode 100644 index 0000000000..e69de29bb2 diff --git a/engine/zed/src/lib.rs b/engine/zed/src/lib.rs new file mode 100644 index 0000000000..6cceb16686 --- /dev/null +++ b/engine/zed/src/lib.rs @@ -0,0 +1,174 @@ +use std::fs; +use zed_extension_api::{self as zed, LanguageServerId, Result, settings::LspSettings}; + +// Follows csharp extension as a template: +// https://github.com/zed-extensions/csharp/blob/main/src/csharp.rs + +const GITHUB_REPO: &str = "BoundaryML/baml"; + +// Embed the binary for debug mode +#[cfg(feature = "debug")] +const BAML_CLI_BINARY: &[u8] = include_bytes!("../baml-cli"); + +struct BamlBinary { + path: String, + args: Option>, +} + +struct BamlExtension { + cached_binary_path: Option, +} + +impl BamlExtension { + fn language_server_binary( + &mut self, + language_server_id: &LanguageServerId, + worktree: &zed::Worktree, + ) -> Result { + let binary_settings = LspSettings::for_worktree("baml", worktree) + .ok() + .and_then(|lsp_settings| lsp_settings.binary); + let binary_args = binary_settings + .as_ref() + .and_then(|binary_settings| binary_settings.arguments.clone()); + + if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) { + return Ok(BamlBinary { + path, + args: binary_args, + }); + } + + if let Some(path) = &self.cached_binary_path { + if fs::metadata(path).map_or(false, |stat| stat.is_file()) { + return Ok(BamlBinary { + path: path.clone(), + args: binary_args, + }); + } + } + + #[cfg(feature = "debug")] + { + let binary_path = "baml-cli"; + fs::write(binary_path, BAML_CLI_BINARY) + .map_err(|e| format!("failed to write embedded binary: {}", e))?; + zed::make_file_executable(binary_path)?; + self.cached_binary_path = Some(binary_path.to_string()); + return Ok(BamlBinary { + path: binary_path.to_string(), + args: binary_args, + }); + } + + #[cfg(not(feature = "debug"))] + { + zed::set_language_server_installation_status( + language_server_id, + &zed::LanguageServerInstallationStatus::CheckingForUpdate, + ); + + let release = zed::latest_github_release( + GITHUB_REPO, + zed::GithubReleaseOptions { + require_assets: true, + pre_release: false, + }, + )?; + + let (platform, arch) = zed::current_platform(); + let asset_name = format!( + "baml-cli-{version}-{arch}-{os}{extension}", + os = match platform { + zed::Os::Mac => "apple-darwin", + zed::Os::Linux => "unknown-linux-gnu", + zed::Os::Windows => "pc-windows-msvc", + }, + arch = match arch { + zed::Architecture::Aarch64 => "aarch64", + zed::Architecture::X86 => "i686", + zed::Architecture::X8664 => "x86_64", + }, + extension = match platform { + zed::Os::Mac | zed::Os::Linux => ".tar.gz", + zed::Os::Windows => ".exe", + }, + version = release.version, + ); + + let asset = release + .assets + .iter() + .find(|asset| asset.name == asset_name) + .ok_or_else(|| format!("no asset found matching {:?}", asset_name))?; + + let version_dir = format!("baml-cli-{}", release.version); + let binary_path = format!("{version_dir}/baml-cli"); + + if !fs::metadata(&binary_path).map_or(false, |stat| stat.is_file()) { + zed::set_language_server_installation_status( + language_server_id, + &zed::LanguageServerInstallationStatus::Downloading, + ); + + zed::download_file( + &asset.download_url, + &version_dir, + match platform { + zed::Os::Mac | zed::Os::Linux => zed::DownloadedFileType::GzipTar, + zed::Os::Windows => zed::DownloadedFileType::Zip, + }, + ) + .map_err(|e| format!("failed to download file: {e}"))?; + + let entries = fs::read_dir(".") + .map_err(|e| format!("failed to list working directory {e}"))?; + for entry in entries { + let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?; + if entry.file_name().to_str() != Some(&version_dir) { + fs::remove_dir_all(entry.path()).ok(); + } + } + } + + self.cached_binary_path = Some(binary_path.clone()); + Ok(BamlBinary { + path: binary_path, + args: binary_args, + }) + } + } +} + +impl zed::Extension for BamlExtension { + fn new() -> Self { + Self { + cached_binary_path: None, + } + } + + fn language_server_command( + &mut self, + language_server_id: &zed::LanguageServerId, + worktree: &zed::Worktree, + ) -> Result { + let baml_binary = self.language_server_binary(language_server_id, worktree)?; + Ok(zed::Command { + command: baml_binary.path, + args: baml_binary.args.unwrap_or_else(|| vec!["lsp".into()]), + env: Default::default(), + }) + } + + // fn language_server_initialization_options( + // &mut self, + // _language_server_id: &LanguageServerId, + // _worktree: &zed::Worktree, + // ) -> Result> { + // Ok(Some(zed::serde_json::json!({ + // "watchPatterns": ["**/baml_src/**/*.baml", "**/baml_src/**/*.json"] + // }))) + // } +} + +zed::register_extension!(BamlExtension); From 80990b47e51ca6ff514c1744f71106c4997900da Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 10:03:46 -0700 Subject: [PATCH 26/71] added on hover function switching to LSP --- engine/cli/src/commands.rs | 10 -- engine/cli/src/lib.rs | 1 - engine/cli/src/playground/definitions.rs | 65 -------- engine/cli/src/playground/file_watcher.rs | 53 ------- engine/cli/src/playground/mod.rs | 9 -- engine/cli/src/playground/playground.rs | 38 ----- engine/cli/src/playground/server.rs | 149 ------------------ engine/language_server/src/playground/mod.rs | 4 +- .../src/playground/playground_server.rs | 24 ++- .../src/server/api/requests/code_lens.rs | 30 ++++ .../src/server/api/requests/hover.rs | 30 ++++ engine/zed/.gitignore | 3 +- engine/zed/Cargo.toml | 4 +- engine/zed/languages/baml/config.toml | 10 +- engine/zed/src/lib.rs | 6 +- .../src/baml_wasm_web/EventListener.tsx | 14 +- 16 files changed, 105 insertions(+), 345 deletions(-) delete mode 100644 engine/cli/src/playground/definitions.rs delete mode 100644 engine/cli/src/playground/file_watcher.rs delete mode 100644 engine/cli/src/playground/mod.rs delete mode 100644 engine/cli/src/playground/playground.rs delete mode 100644 engine/cli/src/playground/server.rs diff --git a/engine/cli/src/commands.rs b/engine/cli/src/commands.rs index cc839f40e0..b5e300f2a1 100644 --- a/engine/cli/src/commands.rs +++ b/engine/cli/src/commands.rs @@ -48,9 +48,6 @@ pub(crate) enum Commands { #[command(about = "Starts a language server", name = "lsp")] LanguageServer(crate::lsp::LanguageServerArgs), - - #[command(about = "Starts a playground server", name = "playground")] - Playground(crate::playground::PlaygroundArgs), } impl RuntimeCli { @@ -134,13 +131,6 @@ impl RuntimeCli { Ok(()) => Ok(crate::ExitCode::Success), Err(_) => Ok(crate::ExitCode::Other), }, - Commands::Playground(args) => { - args.from = BamlRuntime::parse_baml_src_path(&args.from)?; - match args.run() { - Ok(()) => Ok(crate::ExitCode::Success), - Err(_) => Ok(crate::ExitCode::Other), - } - } } } } diff --git a/engine/cli/src/lib.rs b/engine/cli/src/lib.rs index 644f87b244..5353dbeefb 100644 --- a/engine/cli/src/lib.rs +++ b/engine/cli/src/lib.rs @@ -5,7 +5,6 @@ pub(crate) mod commands; pub(crate) mod deploy; pub(crate) mod format; pub(crate) mod lsp; -pub mod playground; pub(crate) mod propelauth; pub(crate) mod tui; use anyhow::Result; diff --git a/engine/cli/src/playground/definitions.rs b/engine/cli/src/playground/definitions.rs deleted file mode 100644 index d1de53266e..0000000000 --- a/engine/cli/src/playground/definitions.rs +++ /dev/null @@ -1,65 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; - -// #[derive(Serialize, Deserialize, Debug)] -// pub struct Span { -// pub file_path: String, -// pub start_line: u32, -// pub start: u32, -// pub end_line: u32, -// pub end: u32, -// } - -// #[derive(Serialize, Deserialize, Debug)] -// pub struct CursorPosition { -// pub file_name: String, -// pub file_text: String, -// pub line: u32, -// pub column: u32, -// } - -// Note: the name add_project should match exactly to the -// EventListener.tsx command definitions due to how serde serializes these into json -#[allow(non_camel_case_types)] -#[derive(Serialize, Deserialize, Debug)] -#[serde(tag = "command", content = "content")] -pub enum FrontendMessage { - add_project { - root_path: String, - files: HashMap, - }, - remove_project { - root_path: String, - }, - // set_flashing_regions { - // spans: Vec, - // }, - select_function { - root_path: String, - function_name: String, - }, - // update_cursor { - // cursor: CursorPosition, - // }, - baml_settings_updated { - settings: HashMap, - }, - run_test { - test_name: String, - }, -} - -pub struct BamlState { - pub files: HashMap, - pub tx: tokio::sync::broadcast::Sender, -} - -impl BamlState { - pub fn new() -> Self { - let (tx, _) = tokio::sync::broadcast::channel(100); - Self { - files: HashMap::new(), - tx, - } - } -} diff --git a/engine/cli/src/playground/file_watcher.rs b/engine/cli/src/playground/file_watcher.rs deleted file mode 100644 index 53570de721..0000000000 --- a/engine/cli/src/playground/file_watcher.rs +++ /dev/null @@ -1,53 +0,0 @@ -use notify_debouncer_full::{new_debouncer, notify::*}; -use std::path::Path; -use std::sync::mpsc::channel; -use std::time::Duration; - -// code based on engine/baml-runtime/src/cli/dev.rs - -pub struct FileWatcher { - path: String, -} - -impl FileWatcher { - pub fn new(path: &str) -> std::io::Result { - Ok(Self { - path: path.to_string(), - }) - } - - pub fn watch(&self, mut callback: F) -> std::io::Result<()> - where - F: FnMut(&str) + Send + 'static, - { - let path = self.path.clone(); - std::thread::spawn(move || { - let (tx, rx) = channel(); - // no specific tickrate, max debounce time 200ms - let mut debouncer = new_debouncer(Duration::from_millis(200), None, tx).unwrap(); - - debouncer - .watch(Path::new(&path), RecursiveMode::Recursive) - .unwrap(); - - for result in rx { - match result { - Ok(events) => { - for event in events { - if let Some(paths) = event.paths.first() { - if let Some(path_str) = paths.to_str() { - callback(path_str); - } - } - } - } - Err(errors) => { - eprintln!("Error watching {}: {:?}", path, errors); - } - } - } - }); - - Ok(()) - } -} diff --git a/engine/cli/src/playground/mod.rs b/engine/cli/src/playground/mod.rs deleted file mode 100644 index fe9bd23b43..0000000000 --- a/engine/cli/src/playground/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod definitions; -mod file_watcher; -mod playground; -mod server; - -pub use self::playground::PlaygroundArgs; -pub use definitions::{BamlState, FrontendMessage}; -pub use file_watcher::FileWatcher; -pub use server::{create_routes, initialize_baml_files, setup_file_watcher}; diff --git a/engine/cli/src/playground/playground.rs b/engine/cli/src/playground/playground.rs deleted file mode 100644 index 47c00dbb39..0000000000 --- a/engine/cli/src/playground/playground.rs +++ /dev/null @@ -1,38 +0,0 @@ -/// Script to run the playground server based of a specified directory. -/// Currently uses a custom filewatcher which detects changes to files in -/// the directory and refreshes the web-view. -use crate::playground::{create_routes, initialize_baml_files, setup_file_watcher, BamlState}; -use anyhow::Result; -use clap::Args; -use std::path::PathBuf; -use std::sync::Arc; -use tokio::sync::RwLock; - -#[derive(Args, Debug, Clone)] -pub struct PlaygroundArgs { - #[arg(long, help = "path/to/baml_src", default_value = "./baml_src")] - pub from: PathBuf, - #[arg(long, help = "port to expose playground on", default_value = "3030")] - port: u16, -} - -impl PlaygroundArgs { - pub fn run(&self) -> Result<()> { - let state = Arc::new(RwLock::new(BamlState::new())); - - // Initialize all BAML files from baml_src directory - let rt = tokio::runtime::Runtime::new()?; - rt.block_on(initialize_baml_files(state.clone(), &self.from)); - - // Set up file watcher - setup_file_watcher(state.clone(), &self.from)?; - - // Sets up the connections for the frontend server - let routes = create_routes(state); - - println!("Hosted playground at http://localhost:{}...", self.port); - rt.block_on(warp::serve(routes).run(([127, 0, 0, 1], self.port))); - - Ok(()) - } -} diff --git a/engine/cli/src/playground/server.rs b/engine/cli/src/playground/server.rs deleted file mode 100644 index 24a0ac4a0f..0000000000 --- a/engine/cli/src/playground/server.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::playground::{BamlState, FileWatcher, FrontendMessage}; -use anyhow::Result; -// use baml_log::bdebug; -use futures_util::{SinkExt, StreamExt}; -use include_dir::{include_dir, Dir}; -use mime_guess::from_path; -use std::fs; -use std::path::Path; -use std::sync::Arc; -use tokio::sync::RwLock; -use warp::{http::Response, ws::Message, Filter}; - -/// Embed at compile time everything in dist/ -/// This embeds the entire frontend code into the binary which includes the web-view and playground-common -/// NOTE: requires web-panel for vscode to be built -static STATIC_DIR: Dir<'_> = - include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); -// Does not matter what this is, it is not currently used in the playground -static ROOT_PATH: &str = "."; - -pub async fn client_connection(ws: warp::ws::WebSocket, state: Arc>) { - let (mut ws_tx, _ws_rx) = ws.split(); - let mut rx = { - let state = state.read().await; - state.tx.subscribe() - }; - - // Send initial project state - let state_read = state.read().await; - let add_project_msg = FrontendMessage::add_project { - root_path: ROOT_PATH.to_string(), - files: state_read.files.clone(), - }; - let _ = ws_tx - .send(Message::text( - serde_json::to_string(&add_project_msg).unwrap(), - )) - .await; - - // Forward broadcast messages to this client - // Ensures realtime updates on the UI - tokio::spawn(async move { - while let Ok(msg) = rx.recv().await { - let _ = ws_tx.send(Message::text(msg)).await; - } - }); -} - -pub async fn initialize_baml_files(state: Arc>, baml_src: &Path) { - let mut state = state.write().await; - for path in get_baml_files(baml_src) { - if let Ok(content) = fs::read_to_string(&path) { - state.files.insert(path, content); - } - } -} - -// method that retrieves all baml files in the baml_src directory -pub fn get_baml_files(baml_src: &Path) -> Vec { - let mut files = Vec::new(); - - fn search_dir(dir_path: &std::path::Path, files: &mut Vec) { - if let Ok(entries) = fs::read_dir(dir_path) { - for entry in entries.flatten() { - let path = entry.path(); - if path.is_dir() { - search_dir(&path, files); - } else if path.is_file() && path.extension().map_or(false, |ext| ext == "baml") { - if let Ok(absolute) = fs::canonicalize(&path) { - if let Some(path_str) = absolute.to_str() { - files.push(path_str.to_string()); - } - } - } - } - } - } - - search_dir(baml_src, &mut files); - files -} - -pub fn setup_file_watcher(state: Arc>, baml_src: &Path) -> Result<()> { - if let Ok(watcher) = FileWatcher::new(baml_src.to_str().unwrap()) { - let state_clone = state.clone(); - if let Err(e) = watcher.watch(move |path| { - // bdebug!("BAML file changed: {}", path); - // Reload the file and update state - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let mut state = state_clone.write().await; - // Remove the modified file from state - state.files.remove(path); - // Re-add it if it still exists - if let Ok(content) = fs::read_to_string(path) { - state.files.insert(path.to_string(), content); - } - // bdebug!("files: {:?}", state.files.clone()); - - let add_project_msg = FrontendMessage::add_project { - root_path: ROOT_PATH.to_string(), - files: state.files.clone(), - }; - let msg_str = serde_json::to_string(&add_project_msg).unwrap(); - let _ = state.tx.send(msg_str); - }); - }) { - eprintln!("Failed to watch baml_src directory: {}", e); - } - } - Ok(()) -} - -pub fn create_routes( - state: Arc>, -) -> impl Filter + Clone { - // WebSocket handler - let ws_route = warp::path("ws") - .and(warp::ws()) - .map(move |ws: warp::ws::Ws| { - let state = state.clone(); - ws.on_upgrade(move |socket| client_connection(socket, state)) - }); - - // Static file serving needed to serve the frontend files - let spa = - warp::path::full() - .and(warp::get()) - .and_then(|full: warp::path::FullPath| async move { - let path = full.as_str().trim_start_matches('/'); - let file = if path.is_empty() { "index.html" } else { path }; - match STATIC_DIR.get_file(file) { - Some(f) => { - let body = f.contents(); - let mime = from_path(file).first_or_octet_stream(); - Ok::<_, warp::Rejection>( - Response::builder() - .header("content-type", mime.as_ref()) - .body(body.to_vec()), - ) - } - None => Ok::<_, warp::Rejection>( - Response::builder().status(404).body(b"Not Found".to_vec()), - ), - } - }); - - ws_route.or(spa).with(warp::log("bundle-server")) -} diff --git a/engine/language_server/src/playground/mod.rs b/engine/language_server/src/playground/mod.rs index 22e7e0f79d..793fd1ba5d 100644 --- a/engine/language_server/src/playground/mod.rs +++ b/engine/language_server/src/playground/mod.rs @@ -4,4 +4,6 @@ pub mod playground_server; pub use definitions::{FrontendMessage, PlaygroundState}; pub use playground::PlaygroundServer; -pub use playground_server::{broadcast_project_update, create_routes}; +pub use playground_server::{ + broadcast_function_change, broadcast_project_update, create_routes, +}; diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index d3fbf666c9..4a201899fe 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -10,7 +10,7 @@ use tokio::sync::RwLock; use warp::{http::Response, ws::Message, Filter}; /// Embed at compile time everything in dist/ -// static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/dist"); +// WARNING: this is a relative path, will easily break if file structure changes static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); @@ -96,6 +96,8 @@ pub fn create_routes( state: Arc>, session: Arc, ) -> impl Filter + Clone { + // tracing::info!("Creating playground routes"); + // WebSocket handler with error handling let ws_route = warp::path("ws") .and(warp::ws()) @@ -150,3 +152,23 @@ pub async fn broadcast_project_update( } Ok(()) } + +// Helper function to broadcast function changes +pub async fn broadcast_function_change( + state: &Arc>, + root_path: &str, + function_name: String, +) -> Result<()> { + // tracing::info!("Broadcasting function change for: {}", function_name); + + let select_function_msg = FrontendMessage::select_function { + root_path: root_path.to_string(), + function_name, + }; + + let msg_str = serde_json::to_string(&select_function_msg)?; + if let Err(e) = state.read().await.broadcast_update(msg_str) { + tracing::error!("Failed to broadcast function change: {}", e); + } + Ok(()) +} diff --git a/engine/language_server/src/server/api/requests/code_lens.rs b/engine/language_server/src/server/api/requests/code_lens.rs index 8c79db6ec5..de564ee70f 100644 --- a/engine/language_server/src/server/api/requests/code_lens.rs +++ b/engine/language_server/src/server/api/requests/code_lens.rs @@ -98,6 +98,36 @@ impl SyncRequestHandler for CodeLens { tracing::info!("Function lenses calculated"); + // Uncomment this to broadcast function change using code lens + // if let Some(state) = &session.playground_state { + // // Get the first function from the lenses if available + // if let Some(first_function) = function_lenses.first() { + // if let Some(command) = &first_function.command { + // if let Some(args) = &command.arguments { + // if let Some(function_name) = + // args[0].get("functionName").and_then(|v| v.as_str()) + // { + // tracing::info!("Broadcasting function change for: {}", function_name); + // let root_path = project_lock.root_path().to_string_lossy().to_string(); + // let state = state.clone(); + // let function_name = function_name.to_string(); + // if let Some(runtime) = &session.playground_runtime { + // runtime.spawn(async move { + // let _ = crate::playground::broadcast_function_change( + // &state, + // &root_path, + // function_name, + // HashMap::new(), // We don't need the files map anymore + // ) + // .await; + // }); + // } + // } + // } + // } + // } + // } + let test_case_lenses: Vec = project_lock .list_testcases() .unwrap_or(vec![]) diff --git a/engine/language_server/src/server/api/requests/hover.rs b/engine/language_server/src/server/api/requests/hover.rs index 5a63368397..9039d08a8b 100644 --- a/engine/language_server/src/server/api/requests/hover.rs +++ b/engine/language_server/src/server/api/requests/hover.rs @@ -4,6 +4,7 @@ use crate::server::client::Requester; use crate::server::{client::Notifier, Result}; use crate::{DocumentKey, Session}; use lsp_types::{self as types, request as req, HoverParams, TextDocumentItem}; +use std::collections::HashMap; pub(crate) struct Hover; @@ -64,6 +65,35 @@ impl SyncRequestHandler for Hover { None } }; + + // Broadcast function change to playground clients + if let Some(state) = &session.playground_state { + let project_lock = project.lock().unwrap(); + // Get the first function from the current file if available + if let Some(function) = project_lock + .list_functions() + .unwrap_or(vec![]) + .into_iter() + .filter(|f| f.span.file_path == document_key.path().to_string_lossy()) + .next() + { + tracing::info!("Broadcasting function change for: {}", function.name); + let root_path = project_lock.root_path().to_string_lossy().to_string(); + let state = state.clone(); + let function_name = function.name.clone(); + if let Some(runtime) = &session.playground_runtime { + runtime.spawn(async move { + let _ = crate::playground::broadcast_function_change( + &state, + &root_path, + function_name, + ) + .await; + }); + } + } + } + Ok(hover) } } diff --git a/engine/zed/.gitignore b/engine/zed/.gitignore index eed2cb54de..41c93caf69 100644 --- a/engine/zed/.gitignore +++ b/engine/zed/.gitignore @@ -1,3 +1,4 @@ /target /grammars -*.wasm \ No newline at end of file +*.wasm +/baml-cli \ No newline at end of file diff --git a/engine/zed/Cargo.toml b/engine/zed/Cargo.toml index 3f5a6c448e..917979e0fd 100644 --- a/engine/zed/Cargo.toml +++ b/engine/zed/Cargo.toml @@ -11,9 +11,9 @@ crate-type = ["cdylib"] [features] # This enables the debug mode by default -# default = ["debug"] +default = ["debug"] # Use this for releases -default = [] +# default = [] debug = [] [dependencies] diff --git a/engine/zed/languages/baml/config.toml b/engine/zed/languages/baml/config.toml index 441761b3ee..5e04c5b32a 100644 --- a/engine/zed/languages/baml/config.toml +++ b/engine/zed/languages/baml/config.toml @@ -2,8 +2,8 @@ name = "Baml" grammar = "baml" path_suffixes = ["baml"] line_comments = ["// ", "/// "] -# brackets = [ -# { start = "{", end = "}", close = true, newline = true }, -# { start = "[", end = "]", close = true, newline = true }, -# { start = "(", end = ")", close = true, newline = false }, -# ] \ No newline at end of file +brackets = [ + { start = "{", end = "}", close = true, newline = true }, + { start = "[", end = "]", close = true, newline = true }, + { start = "(", end = ")", close = true, newline = false }, +] diff --git a/engine/zed/src/lib.rs b/engine/zed/src/lib.rs index 6cceb16686..5bd6f4d2a9 100644 --- a/engine/zed/src/lib.rs +++ b/engine/zed/src/lib.rs @@ -8,8 +8,8 @@ const GITHUB_REPO: &str = "BoundaryML/baml"; // Embed the binary for debug mode #[cfg(feature = "debug")] -const BAML_CLI_BINARY: &[u8] = include_bytes!("../baml-cli"); - +const BAML_CLI_BINARY: &[u8] = include_bytes!("../../target/debug/baml-cli"); +// const BAML_CLI_BINARY: &[u8] = include_bytes!("../baml-cli"); struct BamlBinary { path: String, args: Option>, @@ -86,7 +86,7 @@ impl BamlExtension { }, arch = match arch { zed::Architecture::Aarch64 => "aarch64", - zed::Architecture::X86 => "i686", + zed::Architecture::X86 => "unsupported", zed::Architecture::X8664 => "x86_64", }, extension = match platform { diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index 9d4d3475d6..c172571d7d 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -139,20 +139,20 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre console.log('selectedFunc', selectedFunc) useEffect(() => { - if (isVSCodeWebview) { - setIsConnected(true) - return - } + // if (isVSCodeWebview) { + // setIsConnected(true) + // return + // } const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' const ws = new WebSocket(`${scheme}://${window.location.host}/ws`) ws.onopen = () => { - console.log('WebSocket connected') + console.log('WebSocket Opened') setIsConnected(true) } ws.onmessage = (e) => { - console.log('message!') + console.log('Websocket recieved message!') try { const payload = JSON.parse(e.data) window.postMessage(payload, '*') @@ -161,7 +161,7 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre } } ws.onclose = () => { - console.log('WebSocket disconnected') + console.log('WebSocket Closed') setIsConnected(false) } ws.onerror = () => { From b5154794705095ab13b0fac163554da78c08bcfd Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 10:05:18 -0700 Subject: [PATCH 27/71] disable websocket in vscode --- .../src/baml_wasm_web/EventListener.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index c172571d7d..e1a0a7229d 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -139,10 +139,11 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre console.log('selectedFunc', selectedFunc) useEffect(() => { - // if (isVSCodeWebview) { - // setIsConnected(true) - // return - // } + if (isVSCodeWebview) { + console.log('Websocket disabled in VSCode') + setIsConnected(true) + return + } const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' const ws = new WebSocket(`${scheme}://${window.location.host}/ws`) From fd06736c0812a89e49704a38a478570192d82649 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 10:49:37 -0700 Subject: [PATCH 28/71] automatically find a new port if selected one is being used --- .../src/playground/playground.rs | 7 +- .../src/playground/playground_server.rs | 4 +- engine/language_server/src/server.rs | 73 ++++++++++++------- .../src/baml_wasm_web/EventListener.tsx | 10 +-- 4 files changed, 55 insertions(+), 39 deletions(-) diff --git a/engine/language_server/src/playground/playground.rs b/engine/language_server/src/playground/playground.rs index 08b64d6323..4e26b243d7 100644 --- a/engine/language_server/src/playground/playground.rs +++ b/engine/language_server/src/playground/playground.rs @@ -1,6 +1,5 @@ -/// Script to run the playground server based of a specified directory. -/// Currently uses a custom filewatcher which detects changes to files in -/// the directory and refreshes the web-view. +/// Script that runs the playground server. +/// On the input port use crate::playground::definitions::PlaygroundState; use crate::playground::playground_server::create_routes; use crate::session::Session; @@ -8,7 +7,7 @@ use anyhow::Result; use std::sync::Arc; use tokio::sync::RwLock; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PlaygroundServer { state: Arc>, session: Arc, diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 4a201899fe..e6596e13a6 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -96,8 +96,6 @@ pub fn create_routes( state: Arc>, session: Arc, ) -> impl Filter + Clone { - // tracing::info!("Creating playground routes"); - // WebSocket handler with error handling let ws_route = warp::path("ws") .and(warp::ws()) @@ -159,7 +157,7 @@ pub async fn broadcast_function_change( root_path: &str, function_name: String, ) -> Result<()> { - // tracing::info!("Broadcasting function change for: {}", function_name); + tracing::debug!("Broadcasting function change for: {}", function_name); let select_function_msg = FrontendMessage::select_function { root_path: root_path.to_string(), diff --git a/engine/language_server/src/server.rs b/engine/language_server/src/server.rs index 571408ee49..081aec8225 100644 --- a/engine/language_server/src/server.rs +++ b/engine/language_server/src/server.rs @@ -135,13 +135,9 @@ impl Server { anyhow::anyhow!("Failed to get the current working directory while creating a default workspace.") })?; - // tracing::info!("init params: {:?}", init_params); - - // for some reason tracing logs are not available before this point tracing::info!("Starting server with {} worker threads", worker_threads); tracing::info!("-------- Version: {}", env!("CARGO_PKG_VERSION")); - // Create a new tokio runtime for the playground server let rt = tokio::runtime::Runtime::new()?; let mut session = Session::new( @@ -152,43 +148,25 @@ impl Server { rt.handle().clone(), )?; - // Create a client and notifier to pass to reload let client = client::Client::new(connection.make_sender()); let notifier = client.notifier(); - // Initialize playground state if enabled - // if session.baml_settings.enable_playground { + // Playground state is initialized here, but server startup is now external let playground_state = Arc::new(RwLock::new(PlaygroundState::new())); session.playground_state = Some(playground_state.clone()); - - // Update session_arc with the new session that has playground state let session_arc = Arc::new(session.clone()); - - // Create and start the playground server using the shared playground_state - let playground_server = PlaygroundServer::new(playground_state.clone(), session_arc); - let playground_port = session.baml_settings.playground_port.unwrap_or(3030); - - // Spawn the playground server on the runtime - rt.spawn(playground_server.run(playground_port)); - - tracing::info!( - "Hosted playground at http://localhost:{}...", - playground_port - ); - // } - // Store the runtime in the session session.playground_runtime = Some(rt); - - // Reload the session with the notifier session.reload(Some(notifier))?; - Ok(Self { + let server = Self { connection, worker_threads, session, client_capabilities, - }) + }; + server.start_playground_server(); + Ok(server) } pub fn run(self) -> anyhow::Result<()> { @@ -401,4 +379,45 @@ impl Server { ..Default::default() } } + + fn start_playground_server(&self) { + if let (Some(playground_state), Some(rt)) = ( + self.session.playground_state.clone(), + self.session.playground_runtime.as_ref(), + ) { + let mut playground_port = self.session.baml_settings.playground_port.unwrap_or(3030); + let session_arc = Arc::new(self.session.clone()); + let playground_server = PlaygroundServer::new(playground_state.clone(), session_arc); + rt.spawn(async move { + loop { + // Check if port is available before attempting to bind + let port_available = { + match std::net::TcpListener::bind(("127.0.0.1", playground_port)) { + Ok(_) => true, + Err(_) => false, + } + }; + + if port_available { + // Port is available, start the server + let server = playground_server.clone(); + server.run(playground_port).await.unwrap(); + tracing::info!( + "Hosted playground at http://localhost:{}...", + playground_port + ); + break; + } else { + // Port is already in use, try next port + playground_port += 1; + tracing::info!( + "Port {} is in use, trying port {}...", + playground_port - 1, + playground_port + ); + } + } + }); + } + } } diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index e1a0a7229d..fa6c1f291e 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -139,11 +139,11 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre console.log('selectedFunc', selectedFunc) useEffect(() => { - if (isVSCodeWebview) { - console.log('Websocket disabled in VSCode') - setIsConnected(true) - return - } + // if (isVSCodeWebview) { + // console.log('Websocket disabled in VSCode') + // setIsConnected(true) + // return + // } const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' const ws = new WebSocket(`${scheme}://${window.location.host}/ws`) From 12531ae1a05497a32db072b8b8db4842d83f20ca Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 10:56:29 -0700 Subject: [PATCH 29/71] change git path for extension and set to release mode --- engine/zed/Cargo.toml | 4 ++-- engine/zed/extension.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/zed/Cargo.toml b/engine/zed/Cargo.toml index 917979e0fd..3f5a6c448e 100644 --- a/engine/zed/Cargo.toml +++ b/engine/zed/Cargo.toml @@ -11,9 +11,9 @@ crate-type = ["cdylib"] [features] # This enables the debug mode by default -default = ["debug"] +# default = ["debug"] # Use this for releases -# default = [] +default = [] debug = [] [dependencies] diff --git a/engine/zed/extension.toml b/engine/zed/extension.toml index 7c42ab9207..4fc6bc3e49 100644 --- a/engine/zed/extension.toml +++ b/engine/zed/extension.toml @@ -4,7 +4,7 @@ description = "Baml support." version = "0.0.1" schema_version = 1 authors = ["Boundary "] -repository = "https://github.com/zed-extensions/baml" +repository = "https://github.com/BoundaryML/baml/tree/canary/engine/zed" [language_servers.baml-language-server] name = "Baml Language Server" From dcdd76a2288e81d00a883493b45b3aa78c5f8f9d Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 11:01:02 -0700 Subject: [PATCH 30/71] revert changes to cli --- engine/Cargo.lock | 60 +++---------------------------------------- engine/cli/Cargo.toml | 8 +++--- 2 files changed, 7 insertions(+), 61 deletions(-) diff --git a/engine/Cargo.lock b/engine/Cargo.lock index ff3d3db208..15a8e66f75 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -922,7 +922,6 @@ dependencies = [ "expect-test", "fastrand 2.3.0", "futures", - "futures-util", "http 1.1.0", "http-body 1.0.1", "include_dir", @@ -938,8 +937,6 @@ dependencies = [ "log", "mime", "mime_guess", - "notify 6.1.1", - "notify-debouncer-full 0.5.0", "open", "pathdiff 0.1.0", "pretty_assertions", @@ -965,7 +962,6 @@ dependencies = [ "url", "uuid", "walkdir", - "warp", "wasm-bindgen-test", "wasm-logger", "web-time", @@ -1197,7 +1193,7 @@ dependencies = [ "mime", "mime_guess", "minijinja", - "notify-debouncer-full 0.3.1", + "notify-debouncer-full", "once_cell", "pin-project-lite", "pretty_assertions", @@ -3370,17 +3366,6 @@ dependencies = [ "libc", ] -[[package]] -name = "inotify" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" -dependencies = [ - "bitflags 2.9.0", - "inotify-sys", - "libc", -] - [[package]] name = "inotify-sys" version = "0.1.5" @@ -4120,7 +4105,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -4259,7 +4243,7 @@ dependencies = [ "crossbeam-channel", "filetime", "fsevent-sys", - "inotify 0.9.6", + "inotify", "kqueue", "libc", "log", @@ -4268,25 +4252,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "notify" -version = "8.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" -dependencies = [ - "bitflags 2.9.0", - "filetime", - "fsevent-sys", - "inotify 0.11.0", - "kqueue", - "libc", - "log", - "mio 1.0.3", - "notify-types", - "walkdir", - "windows-sys 0.59.0", -] - [[package]] name = "notify-debouncer-full" version = "0.3.1" @@ -4296,30 +4261,11 @@ dependencies = [ "crossbeam-channel", "file-id", "log", - "notify 6.1.1", + "notify", "parking_lot", "walkdir", ] -[[package]] -name = "notify-debouncer-full" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d88b1a7538054351c8258338df7c931a590513fb3745e8c15eb9ff4199b8d1" -dependencies = [ - "file-id", - "log", - "notify 8.0.0", - "notify-types", - "walkdir", -] - -[[package]] -name = "notify-types" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" - [[package]] name = "nu-ansi-term" version = "0.46.0" diff --git a/engine/cli/Cargo.toml b/engine/cli/Cargo.toml index b6c61fb174..d648cb8932 100644 --- a/engine/cli/Cargo.toml +++ b/engine/cli/Cargo.toml @@ -69,17 +69,15 @@ tokio = { version = "1", default-features = false, features = [ "time", ] } tokio-stream = "0.1.15" +# NOTE(sam): adding this caused a build error, I suspect because tower uses nightly features or something +# tower = "0.5.0" walkdir.workspace = true uuid = { version = "1.8.0", features = ["v4", "serde"] } web-time.workspace = true static_assertions.workspace = true mime_guess = "2.0.4" mime = "0.3.17" -warp = "0.3" -futures-util = "0.3" include_dir = "0.7" -notify = "6.1" -notify-debouncer-full = "0.5.0" # For tracing envy = "0.4.2" @@ -103,6 +101,8 @@ jsonwebtoken = "9.3.0" pretty_assertions = "1.4.0" sha2 = "0.10.8" tracing = "0.1.40" +# Valuable is needed to prevent serializing objects using Debug, and instead use Serialize. +# https://github.com/tokio-rs/tracing/issues/1570 tracing-subscriber = { version = "0.3.18", features = [ "json", "env-filter", From bc834a324cc9f1ee503ae25f8f9809e3eb3671fc Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 12:18:45 -0700 Subject: [PATCH 31/71] force web-view to be built before language server --- engine/language_server/build.rs | 85 +++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 engine/language_server/build.rs diff --git a/engine/language_server/build.rs b/engine/language_server/build.rs new file mode 100644 index 0000000000..6c1a2e52b7 --- /dev/null +++ b/engine/language_server/build.rs @@ -0,0 +1,85 @@ +/// This build script exists as a workaround to guarantee +/// that the web-panel dist directory is built before the +/// language server is built. As the web-panel is a embedded +/// in the language server. +use std::env; +use std::path::PathBuf; +use std::process::Command; +use std::time::Duration; + +fn run_command(cmd: &mut Command, name: &str) -> std::io::Result<()> { + println!("cargo:warning=Running {}...", name); + let output = cmd.output()?; + + // Print stdout and stderr + if !output.stdout.is_empty() { + println!("cargo:warning={} stdout:", name); + println!("cargo:warning={}", String::from_utf8_lossy(&output.stdout)); + } + if !output.stderr.is_empty() { + println!("cargo:warning={} stderr:", name); + println!("cargo:warning={}", String::from_utf8_lossy(&output.stderr)); + } + + if !output.status.success() { + panic!("{} failed with status: {}", name, output.status); + } + Ok(()) +} + +fn main() { + // Get the manifest directory + let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let workspace_root = PathBuf::from(&manifest_dir).join("../.."); + let typescript_dir = workspace_root.join("typescript"); + let web_panel_dir = typescript_dir.join("vscode-ext/packages/web-panel"); + + println!( + "cargo:warning=Typescript directory: {}", + typescript_dir.display() + ); + + // pnpm install + run_command( + Command::new("pnpm") + .current_dir(&typescript_dir) + .arg("install"), + "pnpm install", + ) + .expect("Failed to execute pnpm install command"); + + // Run tsc and vite build in web-panel directory to get the dist directory + // for embedding in the language server + run_command( + Command::new("npx") + .current_dir(&web_panel_dir) + .args(["tsc", "--noEmit"]), + "tsc type check", + ) + .expect("Failed to execute tsc type check"); + + run_command( + Command::new("npx") + .current_dir(&web_panel_dir) + .args(["vite", "build"]), + "vite build", + ) + .expect("Failed to execute vite build"); + + // Try to find the dist directory + let dist_path = web_panel_dir.join("dist"); + + // Check if the directory exists + if !dist_path.exists() { + panic!( + "Web panel dist directory not found at {}. Please ensure the path is correct or set BAML_WEB_PANEL_DIST environment variable.", + dist_path.display() + ); + } + + // Set the environment variable for the build + println!( + "cargo:rustc-env=BAML_WEB_PANEL_DIST={}", + dist_path.display() + ); +} From 4f638f29c5f3527c1bff27b84d1c3276c094fb4d Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 16:29:47 -0700 Subject: [PATCH 32/71] various fixes + code actions for zed --- engine/cli/Cargo.toml | 1 - engine/language_server/src/playground/mod.rs | 2 +- .../src/playground/playground.rs | 8 +- .../src/playground/playground_server.rs | 8 +- engine/language_server/src/server.rs | 15 +++- engine/language_server/src/server/api.rs | 11 +-- .../src/server/api/requests.rs | 4 + .../src/server/api/requests/code_action.rs | 73 +++++++++++++++++ .../server/api/requests/execute_command.rs | 78 +++++++++++++++++++ 9 files changed, 180 insertions(+), 20 deletions(-) create mode 100644 engine/language_server/src/server/api/requests/code_action.rs create mode 100644 engine/language_server/src/server/api/requests/execute_command.rs diff --git a/engine/cli/Cargo.toml b/engine/cli/Cargo.toml index d648cb8932..8783854bea 100644 --- a/engine/cli/Cargo.toml +++ b/engine/cli/Cargo.toml @@ -77,7 +77,6 @@ web-time.workspace = true static_assertions.workspace = true mime_guess = "2.0.4" mime = "0.3.17" -include_dir = "0.7" # For tracing envy = "0.4.2" diff --git a/engine/language_server/src/playground/mod.rs b/engine/language_server/src/playground/mod.rs index 793fd1ba5d..3b18c7b521 100644 --- a/engine/language_server/src/playground/mod.rs +++ b/engine/language_server/src/playground/mod.rs @@ -5,5 +5,5 @@ pub mod playground_server; pub use definitions::{FrontendMessage, PlaygroundState}; pub use playground::PlaygroundServer; pub use playground_server::{ - broadcast_function_change, broadcast_project_update, create_routes, + broadcast_function_change, broadcast_project_update, create_server_routes, }; diff --git a/engine/language_server/src/playground/playground.rs b/engine/language_server/src/playground/playground.rs index 4e26b243d7..12694237cd 100644 --- a/engine/language_server/src/playground/playground.rs +++ b/engine/language_server/src/playground/playground.rs @@ -1,7 +1,7 @@ /// Script that runs the playground server. /// On the input port use crate::playground::definitions::PlaygroundState; -use crate::playground::playground_server::create_routes; +use crate::playground::playground_server::create_server_routes; use crate::session::Session; use anyhow::Result; use std::sync::Arc; @@ -19,8 +19,10 @@ impl PlaygroundServer { } pub async fn run(self, port: u16) -> Result<()> { - let routes = create_routes(self.state, self.session); - warp::serve(routes).run(([127, 0, 0, 1], port)).await; + let routes = create_server_routes(self.state, self.session); + + warp::serve(routes).try_bind(([127, 0, 0, 1], port)).await; + Ok(()) } } diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index e6596e13a6..311852404f 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -46,7 +46,7 @@ pub async fn send_all_projects_to_client( } } -pub async fn client_connection( +pub async fn start_client_connection( ws: warp::ws::WebSocket, state: Arc>, session: Arc, @@ -92,7 +92,9 @@ pub async fn client_connection( }); } -pub fn create_routes( +/// Adds a "/" route which servers the static files of the frontend +/// and a "/ws" route which handles the websocket connection. +pub fn create_server_routes( state: Arc>, session: Arc, ) -> impl Filter + Clone { @@ -103,7 +105,7 @@ pub fn create_routes( let state = state.clone(); let session = session.clone(); ws.on_upgrade(move |socket| async move { - client_connection(socket, state, session).await; + start_client_connection(socket, state, session).await; }) }); diff --git a/engine/language_server/src/server.rs b/engine/language_server/src/server.rs index 081aec8225..13498dd08b 100644 --- a/engine/language_server/src/server.rs +++ b/engine/language_server/src/server.rs @@ -352,7 +352,11 @@ impl Server { code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true), }), - + code_action_provider: Some(lsp_types::CodeActionProviderCapability::Simple(true)), + execute_command_provider: Some(lsp_types::ExecuteCommandOptions { + commands: vec!["openPlayground".to_string()], + work_done_progress_options: Default::default(), + }), definition_provider: Some(lsp_types::OneOf::Left(true)), document_formatting_provider: Some(lsp_types::OneOf::Left(true)), hover_provider: Some(HoverProviderCapability::Simple(true)), @@ -373,7 +377,6 @@ impl Server { supported: Some(true), change_notifications: Some(lsp_types::OneOf::Left(true)), }), - ..Default::default() }), ..Default::default() @@ -401,11 +404,17 @@ impl Server { if port_available { // Port is available, start the server let server = playground_server.clone(); - server.run(playground_port).await.unwrap(); tracing::info!( "Hosted playground at http://localhost:{}...", playground_port ); + // Open the default browser + // if let Err(e) = + // webbrowser::open(&format!("http://localhost:{}", playground_port)) + // { + // tracing::warn!("Failed to open browser: {}", e); + // } + server.run(playground_port).await.unwrap(); break; } else { // Port is already in use, try next port diff --git a/engine/language_server/src/server/api.rs b/engine/language_server/src/server/api.rs index de8d5fafe0..9a1d3170ff 100644 --- a/engine/language_server/src/server/api.rs +++ b/engine/language_server/src/server/api.rs @@ -52,13 +52,7 @@ pub(super) fn request<'a>(req: lsp_server::Request) -> Task<'a> { let id = req.id.clone(); match req.method.as_str() { - // request::CodeActions::METHOD => background_request_task::( - // req, - // BackgroundSchedule::LatencySensitive, - // ), - // request::CodeActionResolve::METHOD => { - // background_request_task::(req, BackgroundSchedule::Worker) - // } + request::CodeActionHandler::METHOD => local_request_task::(req), "bamlCliVersion" => { let version = env!("CARGO_PKG_VERSION"); return Task::local(move |_, _, _, responder| { @@ -164,8 +158,7 @@ pub(super) fn request<'a>(req: lsp_server::Request) -> Task<'a> { }) }); } - - // request::ExecuteCommand::METHOD => local_request_task::(req), + request::ExecuteCommand::METHOD => local_request_task::(req), // request::Format::METHOD => { // background_request_task::(req, BackgroundSchedule::Fmt) // } diff --git a/engine/language_server/src/server/api/requests.rs b/engine/language_server/src/server/api/requests.rs index 815a594acf..ab4a01c295 100644 --- a/engine/language_server/src/server/api/requests.rs +++ b/engine/language_server/src/server/api/requests.rs @@ -1,14 +1,18 @@ +mod code_action; mod code_lens; mod completion; mod diagnostic; +mod execute_command; mod format; mod go_to_definition; mod hover; mod rename; +pub use code_action::CodeActionHandler; pub use code_lens::CodeLens; pub(super) use completion::Completion; pub(super) use diagnostic::DocumentDiagnosticRequestHandler; +pub use execute_command::ExecuteCommand; pub(super) use format::DocumentFormatting; pub use go_to_definition::GotoDefinition; pub(super) use hover::Hover; diff --git a/engine/language_server/src/server/api/requests/code_action.rs b/engine/language_server/src/server/api/requests/code_action.rs new file mode 100644 index 0000000000..1c3d8cf317 --- /dev/null +++ b/engine/language_server/src/server/api/requests/code_action.rs @@ -0,0 +1,73 @@ +use crate::server::api::traits::{RequestHandler, SyncRequestHandler}; +use crate::server::api::ResultExt; +use crate::server::client::Requester; +use crate::server::{client::Notifier, Result}; +use crate::{DocumentKey, Session}; +use lsp_types::{ + request, CodeAction, CodeActionKind, CodeActionOrCommand, CodeActionParams, Command, +}; +use serde_json::Value; +use std::path::PathBuf; + +pub struct CodeActionHandler; + +impl RequestHandler for CodeActionHandler { + type RequestType = request::CodeActionRequest; +} + +impl SyncRequestHandler for CodeActionHandler { + fn run( + session: &mut Session, + _notifier: Notifier, + _requester: &mut Requester, + params: CodeActionParams, + ) -> Result>> { + let mut actions = vec![]; + + let uri = params.text_document.uri.clone(); + if !uri.to_string().contains("baml_src") { + return Ok(None); + } + + let path = uri + .to_file_path() + .internal_error_msg("Could not convert URL to path")?; + let project = session + .get_or_create_project(&path) + .expect("Ensured that a project db exists"); + let document_key = + DocumentKey::from_url(&project.lock().unwrap().root_path(), &uri).internal_error()?; + + // Get the first function from the current file if available + let function_name = project + .lock() + .unwrap() + .list_functions() + .unwrap_or(vec![]) + .into_iter() + .filter(|f| f.span.file_path == document_key.path().to_string_lossy()) + .next() + .map(|f| f.name); + + // Get the playground port from session settings + let port = session.baml_settings.playground_port.unwrap_or(3030); + + let action = CodeActionOrCommand::CodeAction(CodeAction { + title: format!("Open Playground"), + kind: Some(CodeActionKind::EMPTY), + command: Some(Command { + title: format!("Open Playground"), + command: "openPlayground".to_string(), + arguments: function_name.map(|name| vec![Value::String(name)]), + }), + edit: None, + diagnostics: None, + is_preferred: Some(false), + disabled: None, + data: None, + }); + actions.push(action); + + Ok(Some(actions)) + } +} diff --git a/engine/language_server/src/server/api/requests/execute_command.rs b/engine/language_server/src/server/api/requests/execute_command.rs new file mode 100644 index 0000000000..8a5e31e80a --- /dev/null +++ b/engine/language_server/src/server/api/requests/execute_command.rs @@ -0,0 +1,78 @@ +use crate::server::api::traits::{RequestHandler, SyncRequestHandler}; +// use crate::server::api::DocumentKey; +use crate::server::api::ResultExt; +use crate::server::client::Requester; +use crate::server::{client::Notifier, Result}; +use crate::Session; +use lsp_server::ErrorCode; +use lsp_types::{request, ExecuteCommandParams, MessageType}; +use std::time::Duration; +use tokio::time::sleep; +use webbrowser; + +pub struct ExecuteCommand; + +impl RequestHandler for ExecuteCommand { + type RequestType = request::ExecuteCommand; +} + +impl SyncRequestHandler for ExecuteCommand { + fn run( + session: &mut Session, + notifier: Notifier, + _requester: &mut Requester, + params: ExecuteCommandParams, + ) -> Result> { + if params.command == "openPlayground" { + // Get the playground port from session settings + let port = session.baml_settings.playground_port.unwrap_or(3030); + + // Construct the URL + let url = format!("http://localhost:{}", port); + + // Open the browser + if let Err(e) = webbrowser::open(&url) { + notifier + .notify::(lsp_types::ShowMessageParams { + typ: MessageType::WARNING, + message: format!("Failed to open browser: {}", e), + }) + .internal_error()?; + return Err(crate::server::api::Error { + code: ErrorCode::InternalError, + error: anyhow::anyhow!("Failed to open browser: {}", e), + }); + } + + // If we have a function name from the code action, broadcast it + if let Some(state) = &session.playground_state { + if let Some(function_name) = params + .arguments + .first() + .and_then(|arg| arg.as_str().map(|s| s.to_string())) + { + tracing::info!("Broadcasting function change for: {}", function_name); + let state = state.clone(); + if let Some(runtime) = &session.playground_runtime { + runtime.spawn(async move { + // Wait a bit for the server to be ready + sleep(Duration::from_millis(500)).await; + let _ = crate::playground::broadcast_function_change( + &state, + &function_name.to_string(), + function_name, + ) + .await; + }); + } + } + } + } else { + return Err(crate::server::api::Error { + code: ErrorCode::MethodNotFound, + error: anyhow::anyhow!("Unknown command: {}", params.command), + }); + } + Ok(None) + } +} From 898320a5aadf3b981d4b1e963ee8b6d11bc1cd03 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 16:41:01 -0700 Subject: [PATCH 33/71] disable on-hover fn selection and add go to def selection. Fix connection status as well --- engine/language_server/Cargo.toml | 2 ++ .../server/api/requests/go_to_definition.rs | 28 +++++++++++++++++++ .../src/server/api/requests/hover.rs | 28 ------------------- .../src/baml_wasm_web/EventListener.tsx | 8 +++--- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/engine/language_server/Cargo.toml b/engine/language_server/Cargo.toml index f66de25533..0c515fa010 100644 --- a/engine/language_server/Cargo.toml +++ b/engine/language_server/Cargo.toml @@ -77,6 +77,8 @@ futures-util = "0.3" include_dir = "0.7" mime_guess = "2.0.4" +webbrowser = "0.8" + [dev-dependencies] insta = { version = "1.42.1" } diff --git a/engine/language_server/src/server/api/requests/go_to_definition.rs b/engine/language_server/src/server/api/requests/go_to_definition.rs index b0316d82fc..51b29bd9cc 100644 --- a/engine/language_server/src/server/api/requests/go_to_definition.rs +++ b/engine/language_server/src/server/api/requests/go_to_definition.rs @@ -90,6 +90,34 @@ impl SyncRequestHandler for GotoDefinition { uri: target_uri, range, }); + + // Broadcast function change to playground clients + if let Some(state) = &session.playground_state { + // Get the first function from the current file if available + if let Some(function) = guard + .list_functions() + .unwrap_or(vec![]) + .into_iter() + .filter(|f| f.span.file_path == document_key.path().to_string_lossy()) + .next() + { + tracing::info!("Broadcasting function change for: {}", function.name); + let root_path = guard.root_path().to_string_lossy().to_string(); + let state = state.clone(); + let function_name = function.name.clone(); + if let Some(runtime) = &session.playground_runtime { + runtime.spawn(async move { + let _ = crate::playground::broadcast_function_change( + &state, + &root_path, + function_name, + ) + .await; + }); + } + } + } + Ok(Some(goto_definition_response)) } } diff --git a/engine/language_server/src/server/api/requests/hover.rs b/engine/language_server/src/server/api/requests/hover.rs index eac66cc595..46c9af3be3 100644 --- a/engine/language_server/src/server/api/requests/hover.rs +++ b/engine/language_server/src/server/api/requests/hover.rs @@ -70,34 +70,6 @@ impl SyncRequestHandler for Hover { } }; - // Broadcast function change to playground clients - if let Some(state) = &session.playground_state { - let project_lock = project.lock().unwrap(); - // Get the first function from the current file if available - if let Some(function) = project_lock - .list_functions() - .unwrap_or(vec![]) - .into_iter() - .filter(|f| f.span.file_path == document_key.path().to_string_lossy()) - .next() - { - tracing::info!("Broadcasting function change for: {}", function.name); - let root_path = project_lock.root_path().to_string_lossy().to_string(); - let state = state.clone(); - let function_name = function.name.clone(); - if let Some(runtime) = &session.playground_runtime { - runtime.spawn(async move { - let _ = crate::playground::broadcast_function_change( - &state, - &root_path, - function_name, - ) - .await; - }); - } - } - } - Ok(hover) } } diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index fa6c1f291e..677b46e4b5 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -84,7 +84,7 @@ const ConnectionStatus: React.FC = () => { const isConnected = useAtomValue(isConnectedAtom) const isVSCodeWebview = typeof vscode !== 'undefined' - if (isVSCodeWebview || isConnected) return null + if (isConnected) return null return (
@@ -140,9 +140,9 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre useEffect(() => { // if (isVSCodeWebview) { - // console.log('Websocket disabled in VSCode') - // setIsConnected(true) - // return + // console.log('Websocket disabled in VSCode') + // setIsConnected(true) + // return // } const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' From 016718cfcec2eadb0c7dde5df8427dad549a2a58 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 16:59:24 -0700 Subject: [PATCH 34/71] build modification --- engine/language_server/build.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/engine/language_server/build.rs b/engine/language_server/build.rs index 6c1a2e52b7..a5db1d2bc9 100644 --- a/engine/language_server/build.rs +++ b/engine/language_server/build.rs @@ -50,13 +50,13 @@ fn main() { // Run tsc and vite build in web-panel directory to get the dist directory // for embedding in the language server - run_command( - Command::new("npx") - .current_dir(&web_panel_dir) - .args(["tsc", "--noEmit"]), - "tsc type check", - ) - .expect("Failed to execute tsc type check"); + // run_command( + // Command::new("npx") + // .current_dir(&web_panel_dir) + // .args(["tsc", "--noEmit"]), + // "tsc type check", + // ) + // .expect("Failed to execute tsc type check"); run_command( Command::new("npx") From 7afb71286aed2c992eb38564f1ffddd5fa96d189 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 20:12:22 -0700 Subject: [PATCH 35/71] build script adjustments --- engine/language_server/build.rs | 40 ++++++++++++--------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/engine/language_server/build.rs b/engine/language_server/build.rs index a5db1d2bc9..d8c1e52294 100644 --- a/engine/language_server/build.rs +++ b/engine/language_server/build.rs @@ -1,4 +1,4 @@ -/// This build script exists as a workaround to guarantee +/// This build script exists as a fix to guarantee /// that the web-panel dist directory is built before the /// language server is built. As the web-panel is a embedded /// in the language server. @@ -39,7 +39,7 @@ fn main() { typescript_dir.display() ); - // pnpm install + // Install dependencies run_command( Command::new("pnpm") .current_dir(&typescript_dir) @@ -48,38 +48,26 @@ fn main() { ) .expect("Failed to execute pnpm install command"); - // Run tsc and vite build in web-panel directory to get the dist directory - // for embedding in the language server - // run_command( - // Command::new("npx") - // .current_dir(&web_panel_dir) - // .args(["tsc", "--noEmit"]), - // "tsc type check", - // ) - // .expect("Failed to execute tsc type check"); - + // Build frontend run_command( - Command::new("npx") - .current_dir(&web_panel_dir) - .args(["vite", "build"]), - "vite build", + Command::new("npx").current_dir(&typescript_dir).args([ + "turbo", + "build", + "--filter=fiddle-frontend", + ]), + "turbo build", ) - .expect("Failed to execute vite build"); + .expect("Failed to execute turbo build"); - // Try to find the dist directory - let dist_path = web_panel_dir.join("dist"); + // Double check we correctly built the frontend + let dist_path = env::var("BAML_WEB_PANEL_DIST") + .map(PathBuf::from) + .unwrap_or_else(|_| web_panel_dir.join("dist")); - // Check if the directory exists if !dist_path.exists() { panic!( "Web panel dist directory not found at {}. Please ensure the path is correct or set BAML_WEB_PANEL_DIST environment variable.", dist_path.display() ); } - - // Set the environment variable for the build - println!( - "cargo:rustc-env=BAML_WEB_PANEL_DIST={}", - dist_path.display() - ); } From 79a6c00a5a737378bf6368be98ac63873ab5dacc Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 20:45:21 -0700 Subject: [PATCH 36/71] more build script adjustments --- engine/language_server/build.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/engine/language_server/build.rs b/engine/language_server/build.rs index d8c1e52294..df23b6a804 100644 --- a/engine/language_server/build.rs +++ b/engine/language_server/build.rs @@ -48,16 +48,13 @@ fn main() { ) .expect("Failed to execute pnpm install command"); - // Build frontend run_command( - Command::new("npx").current_dir(&typescript_dir).args([ - "turbo", - "build", - "--filter=fiddle-frontend", - ]), - "turbo build", + Command::new("pnpm") + .current_dir(&web_panel_dir) + .arg("build"), + "pnpm build web-panel", ) - .expect("Failed to execute turbo build"); + .expect("Failed to execute pnpm build command"); // Double check we correctly built the frontend let dist_path = env::var("BAML_WEB_PANEL_DIST") From 20b19be17887a4c77a11a003df00e1c55a1e37f0 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 17 Jun 2025 22:13:21 -0700 Subject: [PATCH 37/71] build script runs after macro in rust, remove macro for embed --- engine/language_server/build.rs | 19 +++++++++++++++++-- .../src/playground/playground_server.rs | 19 +++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/engine/language_server/build.rs b/engine/language_server/build.rs index df23b6a804..8899b992b6 100644 --- a/engine/language_server/build.rs +++ b/engine/language_server/build.rs @@ -48,11 +48,23 @@ fn main() { ) .expect("Failed to execute pnpm install command"); + // pnpm run build:playground + // Builds the dependencies for the web-view dist + run_command( + Command::new("pnpm") + .current_dir(&typescript_dir) + .args(["run", "build:playground"]), + "pnpm build", + ) + .expect("Failed to execute pnpm build command"); + + // pnpm run build + // in web-panel, builds dist run_command( Command::new("pnpm") .current_dir(&web_panel_dir) - .arg("build"), - "pnpm build web-panel", + .args(["run", "build"]), + "pnpm build", ) .expect("Failed to execute pnpm build command"); @@ -67,4 +79,7 @@ fn main() { dist_path.display() ); } + + // Tell cargo to rerun if the dist directory changes + println!("cargo:rerun-if-changed={}", dist_path.display()); } diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 311852404f..9e0eac0047 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -2,17 +2,15 @@ use crate::playground::definitions::{FrontendMessage, PlaygroundState}; use crate::session::Session; use anyhow::Result; use futures_util::{SinkExt, StreamExt}; -use include_dir::{include_dir, Dir}; use mime_guess::from_path; use std::collections::HashMap; +use std::path::PathBuf; use std::sync::Arc; use tokio::sync::RwLock; use warp::{http::Response, ws::Message, Filter}; -/// Embed at compile time everything in dist/ -// WARNING: this is a relative path, will easily break if file structure changes -static STATIC_DIR: Dir<'_> = - include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); +/// Path to the static files directory +const STATIC_DIR: &str = "../../typescript/vscode-ext/packages/web-panel/dist"; /// Helper to send all projects/files to a websocket client pub async fn send_all_projects_to_client( @@ -116,17 +114,18 @@ pub fn create_server_routes( .and_then(|full: warp::path::FullPath| async move { let path = full.as_str().trim_start_matches('/'); let file = if path.is_empty() { "index.html" } else { path }; - match STATIC_DIR.get_file(file) { - Some(f) => { - let body = f.contents(); + let file_path = PathBuf::from(STATIC_DIR).join(file); + + match tokio::fs::read(&file_path).await { + Ok(contents) => { let mime = from_path(file).first_or_octet_stream(); Ok::<_, warp::Rejection>( Response::builder() .header("content-type", mime.as_ref()) - .body(body.to_vec()), + .body(contents), ) } - None => Ok::<_, warp::Rejection>( + Err(_) => Ok::<_, warp::Rejection>( Response::builder().status(404).body(b"Not Found".to_vec()), ), } From 8f6367609401ae1d052129d5cde0ca0d5f5c86b3 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 18 Jun 2025 10:02:23 -0700 Subject: [PATCH 38/71] try changing workflow file order --- .github/workflows/primary.yml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/primary.yml b/.github/workflows/primary.yml index f666f7d5b2..31e1161e9e 100644 --- a/.github/workflows/primary.yml +++ b/.github/workflows/primary.yml @@ -50,6 +50,21 @@ jobs: - name: Check TS Lint run: pnpm biome ci . --organize-imports-enabled=false working-directory: typescript + build-wasm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: jdx/mise-action@v2 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - run: rustup target add wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 + with: + workspaces: engine + - name: Build rust for wasm32 + run: cargo build --target=wasm32-unknown-unknown + working-directory: engine/baml-schema-wasm test_node_generator: runs-on: ubuntu-latest steps: @@ -123,21 +138,6 @@ jobs: # skip doctests & integration tests (the latter require OPENAI_API_KEY and ANTHROPIC_API_KEY to be set) run: cargo test --lib working-directory: engine - build-wasm: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: jdx/mise-action@v2 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - - run: rustup target add wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 - with: - workspaces: engine - - name: Build rust for wasm32 - run: cargo build --target=wasm32-unknown-unknown - working-directory: engine/baml-schema-wasm integ-tests: runs-on: ubuntu-latest steps: From 00f61630ec12848e688ee61f6f396f77cc5fb6fd Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 18 Jun 2025 10:25:28 -0700 Subject: [PATCH 39/71] more workflow modification --- .github/workflows/primary.yml | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/.github/workflows/primary.yml b/.github/workflows/primary.yml index 31e1161e9e..69af3c4367 100644 --- a/.github/workflows/primary.yml +++ b/.github/workflows/primary.yml @@ -50,21 +50,6 @@ jobs: - name: Check TS Lint run: pnpm biome ci . --organize-imports-enabled=false working-directory: typescript - build-wasm: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: jdx/mise-action@v2 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - - run: rustup target add wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 - with: - workspaces: engine - - name: Build rust for wasm32 - run: cargo build --target=wasm32-unknown-unknown - working-directory: engine/baml-schema-wasm test_node_generator: runs-on: ubuntu-latest steps: @@ -83,12 +68,16 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: toolchain: stable + - run: rustup target add wasm32-unknown-unknown - uses: Swatinem/rust-cache@v2 with: workspaces: engine - name: Install Node run: pnpm install --frozen-lockfile working-directory: engine/language_client_typescript + - name: Build Wasm (for language server) + run: cargo build --target=wasm32-unknown-unknown + working-directory: engine/baml-schema-wasm - name: Build Node run: pnpm build:debug working-directory: engine/language_client_typescript @@ -123,6 +112,21 @@ jobs: - name: Ensure No Changes (3 of 3) run: | git diff --exit-code || (echo "::error:: merge canary and run codegen again" && exit 1) + build-wasm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: jdx/mise-action@v2 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - run: rustup target add wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 + with: + workspaces: engine + - name: Build rust for wasm32 + run: cargo build --target=wasm32-unknown-unknown + working-directory: engine/baml-schema-wasm build: runs-on: ubuntu-latest steps: From 476e640cda05a4ec52619865e3a51c81e7e501e1 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 18 Jun 2025 10:48:45 -0700 Subject: [PATCH 40/71] fix missing wasm-bindgen when building language-server --- .github/workflows/primary.yml | 8 ++++++++ engine/baml-schema-wasm/scripts/install.sh | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/.github/workflows/primary.yml b/.github/workflows/primary.yml index 69af3c4367..342c6cb5f8 100644 --- a/.github/workflows/primary.yml +++ b/.github/workflows/primary.yml @@ -135,9 +135,13 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: toolchain: stable + - run: rustup target add wasm32-unknown-unknown - uses: Swatinem/rust-cache@v2 with: workspaces: engine + - name: Build Wasm (for language server) + run: cargo build --target=wasm32-unknown-unknown + working-directory: engine/baml-schema-wasm - name: Test Rust # skip doctests & integration tests (the latter require OPENAI_API_KEY and ANTHROPIC_API_KEY to be set) run: cargo test --lib @@ -154,9 +158,13 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: toolchain: stable + - run: rustup target add wasm32-unknown-unknown - uses: Swatinem/rust-cache@v2 with: workspaces: engine + - name: Build Wasm (for language server) + run: cargo build --target=wasm32-unknown-unknown + working-directory: engine/baml-schema-wasm - name: run python tests run: | cd integ-tests/python diff --git a/engine/baml-schema-wasm/scripts/install.sh b/engine/baml-schema-wasm/scripts/install.sh index dddbee7d75..fc17825ccf 100755 --- a/engine/baml-schema-wasm/scripts/install.sh +++ b/engine/baml-schema-wasm/scripts/install.sh @@ -8,6 +8,12 @@ printf '%s\n' " -> Creating out dir..." # shellcheck disable=SC2154 mkdir -p "$out"/src +# Check if wasm-bindgen is installed, install if not +if ! command -v wasm-bindgen &> /dev/null; then + printf '%s\n' " -> Installing wasm-bindgen-cli..." + cargo install wasm-bindgen-cli +fi + printf '%s\n' " -> Generating $target package" wasm-bindgen \ --target "$target" \ From c86c77e08312841afdd0c0ca980da9015c9c7f35 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 18 Jun 2025 11:09:09 -0700 Subject: [PATCH 41/71] download specfic wasm-bindgen version in install script --- engine/baml-schema-wasm/scripts/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/baml-schema-wasm/scripts/install.sh b/engine/baml-schema-wasm/scripts/install.sh index fc17825ccf..0a1b3de806 100755 --- a/engine/baml-schema-wasm/scripts/install.sh +++ b/engine/baml-schema-wasm/scripts/install.sh @@ -11,7 +11,7 @@ mkdir -p "$out"/src # Check if wasm-bindgen is installed, install if not if ! command -v wasm-bindgen &> /dev/null; then printf '%s\n' " -> Installing wasm-bindgen-cli..." - cargo install wasm-bindgen-cli + cargo install -f wasm-bindgen-cli@0.2.92 fi printf '%s\n' " -> Generating $target package" From 3bcdb44326b788a2f1fe97da12b5f53db33c1c0d Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 18 Jun 2025 11:49:52 -0700 Subject: [PATCH 42/71] fix test for lsp and git diff check --- engine/Cargo.lock | 165 ++++++++- engine/language_server/src/session.rs | 4 +- typescript/pnpm-lock.yaml | 494 -------------------------- 3 files changed, 161 insertions(+), 502 deletions(-) diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 6bf8d056ce..9fc8688655 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -924,7 +924,6 @@ dependencies = [ "futures", "http 1.1.0", "http-body 1.0.1", - "include_dir", "indexmap", "indicatif", "indicatif-log-bridge", @@ -1557,6 +1556,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47de7e88bbbd467951ae7f5a6f34f70d1b4d9cfce53d5fd70f74ebe118b3db56" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.6.0" @@ -1755,6 +1760,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -3678,6 +3693,28 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.62", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jod-thread" version = "0.1.2" @@ -3829,6 +3866,7 @@ dependencies = [ "tracing-subscriber", "url", "warp", + "webbrowser", ] [[package]] @@ -3989,6 +4027,15 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -4195,6 +4242,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + [[package]] name = "nix" version = "0.29.0" @@ -4345,6 +4398,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + [[package]] name = "object" version = "0.36.1" @@ -4986,6 +5048,12 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + [[package]] name = "rayon" version = "1.10.0" @@ -6989,7 +7057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2" dependencies = [ "anyhow", - "indexmap 2.8.0", + "indexmap", "serde", "serde_derive", "serde_json", @@ -7018,7 +7086,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708" dependencies = [ "bitflags 2.9.0", - "indexmap 2.8.0", + "indexmap", "semver", ] @@ -7056,6 +7124,23 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webbrowser" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" +dependencies = [ + "core-foundation", + "home", + "jni", + "log", + "ndk-context", + "objc", + "raw-window-handle", + "url", + "web-sys", +] + [[package]] name = "which" version = "6.0.3" @@ -7155,6 +7240,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -7182,6 +7276,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -7213,6 +7322,12 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -7225,6 +7340,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -7237,6 +7358,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -7255,6 +7382,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -7267,6 +7400,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -7279,6 +7418,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -7291,6 +7436,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -7362,7 +7513,7 @@ checksum = "d8a39a15d1ae2077688213611209849cad40e9e5cccf6e61951a425850677ff3" dependencies = [ "anyhow", "heck 0.4.1", - "indexmap 2.8.0", + "indexmap", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -7390,7 +7541,7 @@ checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825" dependencies = [ "anyhow", "bitflags 2.9.0", - "indexmap 2.8.0", + "indexmap", "log", "serde", "serde_derive", @@ -7409,7 +7560,7 @@ checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6" dependencies = [ "anyhow", "id-arena", - "indexmap 2.8.0", + "indexmap", "log", "semver", "serde", @@ -7469,7 +7620,7 @@ dependencies = [ [[package]] name = "zed" -version = "0.89.0" +version = "0.90.1" dependencies = [ "zed_extension_api", ] diff --git a/engine/language_server/src/session.rs b/engine/language_server/src/session.rs index a44f4f2b21..6031415880 100644 --- a/engine/language_server/src/session.rs +++ b/engine/language_server/src/session.rs @@ -442,12 +442,14 @@ mod tests { let global_settings = ClientSettings::default(); let workspace_folders = vec![]; // Start with empty workspace + let rt = tokio::runtime::Runtime::new().unwrap(); + Session::new( &client_capabilities, position_encoding, global_settings, &workspace_folders, - tokio::runtime::Handle::current(), + rt.handle().clone(), ) .unwrap() } diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml index 0532861f62..2689b2da7b 100644 --- a/typescript/pnpm-lock.yaml +++ b/typescript/pnpm-lock.yaml @@ -831,73 +831,6 @@ importers: specifier: 5.7.2 version: 5.7.2 - vscode-ext/packages/language-server: - dependencies: - '@baml/common': - specifier: workspace:* - version: link:../../../common - '@gloo-ai/baml-schema-wasm-node': - specifier: workspace:* - version: link:../../../baml-schema-wasm-node - '@types/js-levenshtein': - specifier: 1.1.2 - version: 1.1.2 - js-levenshtein: - specifier: 1.1.6 - version: 1.1.6 - klona: - specifier: 2.0.6 - version: 2.0.6 - lodash: - specifier: ^4.17.21 - version: 4.17.21 - nyc: - specifier: 15.1.0 - version: 15.1.0 - semver: - specifier: ^7.6.2 - version: 7.6.3 - vscode-languageserver: - specifier: ^9.0.1 - version: 9.0.1 - vscode-languageserver-textdocument: - specifier: 1.0.11 - version: 1.0.11 - vscode-uri: - specifier: ^3.0.8 - version: 3.0.8 - zod: - specifier: ^3.22.4 - version: 3.24.1 - devDependencies: - '@types/lodash': - specifier: ^4.14.200 - version: 4.17.14 - '@types/mocha': - specifier: 10.0.3 - version: 10.0.3 - '@types/node': - specifier: 14.18.63 - version: 14.18.63 - '@types/semver': - specifier: ^7.5.8 - version: 7.5.8 - esbuild: - specifier: ^0.19.4 - version: 0.19.12 - esbuild-plugin-copy: - specifier: ^2.1.1 - version: 2.1.1(esbuild@0.19.12) - rimraf: - specifier: ^5.0.5 - version: 5.0.10 - ts-dedent: - specifier: 2.2.0 - version: 2.2.0 - typescript: - specifier: 5.2.2 - version: 5.2.2 - vscode-ext/packages/syntaxes: devDependencies: vscode-tmgrammar-test: @@ -4913,9 +4846,6 @@ packages: '@types/jest@29.5.14': resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} - '@types/js-levenshtein@1.1.2': - resolution: {integrity: sha512-/NCbMABw2uacuyE16Iwka1EzREDD50/W2ggRBad0y1WHBvAkvR9OEINxModVY7D428gXBe0igeVX7bUc9GaslQ==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -4943,9 +4873,6 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@14.18.63': - resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} - '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} @@ -5401,10 +5328,6 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -5492,13 +5415,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - append-transform@2.0.0: - resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} - engines: {node: '>=8'} - - archy@1.0.0: - resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} - are-shallow-equal@1.1.1: resolution: {integrity: sha512-Y0MC/7IP+WZSo0NgYDwww7euKssEodUJxjby3fmNurEDcbq8htqSgyI7a7HELJzkzNv26dOH5vKQFlzCt1H9Ag==} @@ -5946,10 +5862,6 @@ packages: resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} engines: {node: '>=0.10.0'} - caching-transform@4.0.0: - resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} - engines: {node: '>=8'} - call-bind-apply-helpers@1.0.1: resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} engines: {node: '>= 0.4'} @@ -6094,16 +6006,9 @@ packages: classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -6206,9 +6111,6 @@ packages: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} - commondir@1.0.1: - resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - compatfactory@3.0.0: resolution: {integrity: sha512-WD5kF7koPwVoyKL8p0LlrmIZtilrD46sQStyzzxzTFinMKN2Dxk1hN+sddLSQU1mGIZvQfU8c+ONSghvvM40jg==} engines: {node: '>=14.9.0'} @@ -6235,9 +6137,6 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -6418,10 +6317,6 @@ packages: supports-color: optional: true - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - decamelize@4.0.0: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} @@ -6471,10 +6366,6 @@ packages: resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} engines: {node: '>=18'} - default-require-extensions@3.0.1: - resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} - engines: {node: '>=8'} - define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -6701,20 +6592,12 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es6-error@4.1.1: - resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} esast-util-from-js@2.0.1: resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} - esbuild-plugin-copy@2.1.1: - resolution: {integrity: sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw==} - peerDependencies: - esbuild: '>= 0.14.0' - esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: @@ -7057,10 +6940,6 @@ packages: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} - find-cache-dir@3.3.2: - resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} - engines: {node: '>=8'} - find-index@0.1.1: resolution: {integrity: sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==} @@ -7103,10 +6982,6 @@ packages: resolution: {integrity: sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==} engines: {node: '>=0.10.0'} - foreground-child@2.0.0: - resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} - engines: {node: '>=8.0.0'} - foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -7155,16 +7030,9 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} - fromentries@1.3.2: - resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} - fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -7383,10 +7251,6 @@ packages: resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} engines: {node: '>=0.10.0'} - hasha@5.2.2: - resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} - engines: {node: '>=8'} - hashish@0.0.4: resolution: {integrity: sha512-xyD4XgslstNAs72ENaoFvgMwtv8xhiDtC2AtzCG+8yF7W/Knxxm9BX+e2s25mm+HxMKh0rBmXVOEGF3zNImXvA==} @@ -7813,9 +7677,6 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} - is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -7876,14 +7737,6 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - istanbul-lib-hook@3.0.0: - resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} - engines: {node: '>=8'} - - istanbul-lib-instrument@4.0.3: - resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} - engines: {node: '>=8'} - istanbul-lib-instrument@5.2.1: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} @@ -7892,10 +7745,6 @@ packages: resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} - istanbul-lib-processinfo@2.0.3: - resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==} - engines: {node: '>=8'} - istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} @@ -8099,10 +7948,6 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} - js-levenshtein@1.1.6: - resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} - engines: {node: '>=0.10.0'} - js-tiktoken@1.0.16: resolution: {integrity: sha512-nUVdO5k/M9llWpiaZlBBDdtmr6qWXwSD6fgaDu2zM8UP+OXxx9V37lFkI6w0/1IuaDx7WffZ37oYd9KvcWKElg==} @@ -8199,9 +8044,6 @@ packages: hasBin: true bundledDependencies: [] - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - jsonpath-plus@10.2.0: resolution: {integrity: sha512-T9V+8iNYKFL2n2rF+w02LBOT2JjDnTjioaNFrxRy0Bv1y/hNsqR/EBK7Ojy2ythRHwmz2cRIls+9JitQGZC/sw==} engines: {node: '>=18.0.0'} @@ -8256,10 +8098,6 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - klona@2.0.6: - resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} - engines: {node: '>= 8'} - language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -8387,9 +8225,6 @@ packages: lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.flattendeep@4.4.0: - resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} - lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -8483,10 +8318,6 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} - make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} @@ -8931,10 +8762,6 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-preload@0.2.1: - resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} - engines: {node: '>=8'} - node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} @@ -8960,11 +8787,6 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nyc@15.1.0: - resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} - engines: {node: '>=8.9'} - hasBin: true - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -9075,18 +8897,10 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-map@3.0.0: - resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} - engines: {node: '>=8'} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - package-hash@4.0.0: - resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} - engines: {node: '>=8'} - package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -9322,10 +9136,6 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - process-on-spawn@1.1.0: - resolution: {integrity: sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==} - engines: {node: '>=8'} - process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} @@ -9733,10 +9543,6 @@ packages: rehype-stringify@10.0.1: resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} - release-zalgo@1.0.0: - resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} - engines: {node: '>=4'} - remark-mdx@3.1.0: resolution: {integrity: sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==} @@ -9768,9 +9574,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -9973,9 +9776,6 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -10124,10 +9924,6 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - spawn-wrap@2.0.0: - resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} - engines: {node: '>=8'} - split-string@3.1.0: resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} engines: {node: '>=0.10.0'} @@ -10654,10 +10450,6 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - type-fest@2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} @@ -10689,9 +10481,6 @@ packages: typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} - typedarray-to-buffer@3.1.5: - resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typedarray.prototype.slice@1.0.5: resolution: {integrity: sha512-q7QNVDGTdl702bVFiI5eY4l/HkgCM6at9KhcFbgUAzezHFbOVy4+0O/lCjsABEQwbZPravVfBIiBVGo89yzHFg==} engines: {node: '>= 0.4'} @@ -10788,10 +10577,6 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -11034,10 +10819,6 @@ packages: resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} engines: {node: '>=8.0.0 || >=10.0.0'} - vscode-jsonrpc@8.2.0: - resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} - engines: {node: '>=14.0.0'} - vscode-jsonrpc@8.2.1: resolution: {integrity: sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==} engines: {node: '>=14.0.0'} @@ -11049,22 +10830,9 @@ packages: vscode-languageserver-protocol@3.16.0: resolution: {integrity: sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==} - vscode-languageserver-protocol@3.17.5: - resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} - - vscode-languageserver-textdocument@1.0.11: - resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==} - vscode-languageserver-types@3.16.0: resolution: {integrity: sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==} - vscode-languageserver-types@3.17.5: - resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} - - vscode-languageserver@9.0.1: - resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} - hasBin: true - vscode-oniguruma@1.7.0: resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} @@ -11151,9 +10919,6 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - which-typed-array@1.1.18: resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} engines: {node: '>= 0.4'} @@ -11170,10 +10935,6 @@ packages: workerpool@6.2.0: resolution: {integrity: sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==} - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -11185,9 +10946,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@3.0.3: - resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} - write-file-atomic@4.0.2: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -11216,9 +10974,6 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -11242,10 +10997,6 @@ packages: engines: {node: '>= 14'} hasBin: true - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - yargs-parser@20.2.4: resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} engines: {node: '>=10'} @@ -11258,10 +11009,6 @@ packages: resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} engines: {node: '>=10'} - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -15609,8 +15356,6 @@ snapshots: expect: 29.7.0 pretty-format: 29.7.0 - '@types/js-levenshtein@1.1.2': {} - '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -15631,8 +15376,6 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node@14.18.63': {} - '@types/node@17.0.45': {} '@types/node@20.17.12': @@ -16338,11 +16081,6 @@ snapshots: agent-base@7.1.3: {} - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -16423,12 +16161,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - append-transform@2.0.0: - dependencies: - default-require-extensions: 3.0.1 - - archy@1.0.0: {} - are-shallow-equal@1.1.1: dependencies: is-primitive: 3.0.1 @@ -17139,13 +16871,6 @@ snapshots: union-value: 1.0.1 unset-value: 1.0.0 - caching-transform@4.0.0: - dependencies: - hasha: 5.2.2 - make-dir: 3.1.0 - package-hash: 4.0.0 - write-file-atomic: 3.0.3 - call-bind-apply-helpers@1.0.1: dependencies: es-errors: 1.3.0 @@ -17323,16 +17048,8 @@ snapshots: classnames@2.5.1: {} - clean-stack@2.2.0: {} - client-only@0.0.1: {} - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -17441,8 +17158,6 @@ snapshots: commander@9.5.0: {} - commondir@1.0.1: {} - compatfactory@3.0.0(typescript@4.9.5): dependencies: helpertypes: 0.0.19 @@ -17471,8 +17186,6 @@ snapshots: content-type@1.0.5: {} - convert-source-map@1.9.0: {} - convert-source-map@2.0.0: {} cookie-signature@1.0.6: {} @@ -17686,8 +17399,6 @@ snapshots: dependencies: ms: 2.1.3 - decamelize@1.2.0: {} - decamelize@4.0.0: {} decode-named-character-reference@1.0.2: @@ -17721,10 +17432,6 @@ snapshots: bundle-name: 4.1.0 default-browser-id: 5.0.0 - default-require-extensions@3.0.1: - dependencies: - strip-bom: 4.0.0 - define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -17990,8 +17697,6 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es6-error@4.1.1: {} - esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -18006,14 +17711,6 @@ snapshots: esast-util-from-estree: 2.0.0 vfile-message: 4.0.2 - esbuild-plugin-copy@2.1.1(esbuild@0.19.12): - dependencies: - chalk: 4.1.2 - chokidar: 3.6.0 - esbuild: 0.19.12 - fs-extra: 10.1.0 - globby: 11.1.0 - esbuild-register@3.6.0(esbuild@0.19.12): dependencies: debug: 4.4.0 @@ -18597,12 +18294,6 @@ snapshots: transitivePeerDependencies: - supports-color - find-cache-dir@3.3.2: - dependencies: - commondir: 1.0.1 - make-dir: 3.1.0 - pkg-dir: 4.2.0 - find-index@0.1.1: {} find-up@4.1.0: @@ -18639,11 +18330,6 @@ snapshots: dependencies: for-in: 1.0.2 - foreground-child@2.0.0: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 3.0.7 - foreground-child@3.3.0: dependencies: cross-spawn: 7.0.6 @@ -18683,17 +18369,9 @@ snapshots: fresh@0.5.2: {} - fromentries@1.3.2: {} - fs-constants@1.0.0: optional: true - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - fs.realpath@1.0.0: {} fsevents@1.2.13: @@ -18955,11 +18633,6 @@ snapshots: is-number: 3.0.0 kind-of: 4.0.0 - hasha@5.2.2: - dependencies: - is-stream: 2.0.1 - type-fest: 0.8.1 - hashish@0.0.4: dependencies: traverse: 0.6.10 @@ -19421,8 +19094,6 @@ snapshots: dependencies: which-typed-array: 1.1.18 - is-typedarray@1.0.0: {} - is-unicode-supported@0.1.0: {} is-weakmap@2.0.2: {} @@ -19466,19 +19137,6 @@ snapshots: istanbul-lib-coverage@3.2.2: {} - istanbul-lib-hook@3.0.0: - dependencies: - append-transform: 2.0.0 - - istanbul-lib-instrument@4.0.3: - dependencies: - '@babel/core': 7.26.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.26.0 @@ -19499,15 +19157,6 @@ snapshots: transitivePeerDependencies: - supports-color - istanbul-lib-processinfo@2.0.3: - dependencies: - archy: 1.0.0 - cross-spawn: 7.0.6 - istanbul-lib-coverage: 3.2.2 - p-map: 3.0.0 - rimraf: 3.0.2 - uuid: 8.3.2 - istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 @@ -20053,8 +19702,6 @@ snapshots: joycon@3.1.1: {} - js-levenshtein@1.1.6: {} - js-tiktoken@1.0.16: dependencies: base64-js: 1.5.1 @@ -20142,12 +19789,6 @@ snapshots: chalk: 3.0.0 diff-match-patch: 1.0.5 - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - jsonpath-plus@10.2.0: dependencies: '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) @@ -20227,8 +19868,6 @@ snapshots: kleur@3.0.3: {} - klona@2.0.6: {} - language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -20326,8 +19965,6 @@ snapshots: lodash.debounce@4.0.8: {} - lodash.flattendeep@4.4.0: {} - lodash.includes@4.3.0: {} lodash.isboolean@3.0.3: {} @@ -20404,10 +20041,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 - make-dir@3.1.0: - dependencies: - semver: 6.3.1 - make-dir@4.0.0: dependencies: semver: 7.6.3 @@ -21063,10 +20696,6 @@ snapshots: node-int64@0.4.0: {} - node-preload@0.2.1: - dependencies: - process-on-spawn: 1.1.0 - node-releases@2.0.19: {} noms@0.0.0: @@ -21090,38 +20719,6 @@ snapshots: dependencies: boolbase: 1.0.0 - nyc@15.1.0: - dependencies: - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - caching-transform: 4.0.0 - convert-source-map: 1.9.0 - decamelize: 1.2.0 - find-cache-dir: 3.3.2 - find-up: 4.1.0 - foreground-child: 2.0.0 - get-package-type: 0.1.0 - glob: 7.2.3 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-hook: 3.0.0 - istanbul-lib-instrument: 4.0.3 - istanbul-lib-processinfo: 2.0.3 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.7 - make-dir: 3.1.0 - node-preload: 0.2.1 - p-map: 3.0.0 - process-on-spawn: 1.1.0 - resolve-from: 5.0.0 - rimraf: 3.0.2 - signal-exit: 3.0.7 - spawn-wrap: 2.0.0 - test-exclude: 6.0.0 - yargs: 15.4.1 - transitivePeerDependencies: - - supports-color - object-assign@4.1.1: {} object-copy@0.1.0: @@ -21264,19 +20861,8 @@ snapshots: dependencies: p-limit: 3.1.0 - p-map@3.0.0: - dependencies: - aggregate-error: 3.1.0 - p-try@2.2.0: {} - package-hash@4.0.0: - dependencies: - graceful-fs: 4.2.11 - hasha: 5.2.2 - lodash.flattendeep: 4.4.0 - release-zalgo: 1.0.0 - package-json-from-dist@1.0.1: {} pako@1.0.11: {} @@ -21507,10 +21093,6 @@ snapshots: process-nextick-args@2.0.1: {} - process-on-spawn@1.1.0: - dependencies: - fromentries: 1.3.2 - process@0.11.10: {} promise-concurrency-limiter@1.0.0: {} @@ -22118,10 +21700,6 @@ snapshots: hast-util-to-html: 9.0.4 unified: 11.0.5 - release-zalgo@1.0.0: - dependencies: - es6-error: 4.1.1 - remark-mdx@3.1.0: dependencies: mdast-util-mdx: 3.0.0 @@ -22160,8 +21738,6 @@ snapshots: require-from-string@2.0.2: {} - require-main-filename@2.0.0: {} - requires-port@1.0.0: {} resize-observer-polyfill@1.5.1: {} @@ -22384,8 +21960,6 @@ snapshots: transitivePeerDependencies: - supports-color - set-blocking@2.0.0: {} - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -22585,15 +22159,6 @@ snapshots: space-separated-tokens@2.0.2: {} - spawn-wrap@2.0.0: - dependencies: - foreground-child: 2.0.0 - is-windows: 1.0.2 - make-dir: 3.1.0 - rimraf: 3.0.2 - signal-exit: 3.0.7 - which: 2.0.2 - split-string@3.1.0: dependencies: extend-shallow: 3.0.2 @@ -23233,8 +22798,6 @@ snapshots: type-fest@0.21.3: {} - type-fest@0.8.1: {} - type-fest@2.19.0: {} type-fest@4.31.0: {} @@ -23283,10 +22846,6 @@ snapshots: tunnel: 0.0.6 underscore: 1.13.7 - typedarray-to-buffer@3.1.5: - dependencies: - is-typedarray: 1.0.0 - typedarray.prototype.slice@1.0.5: dependencies: call-bind: 1.0.8 @@ -23388,8 +22947,6 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 - universalify@2.0.1: {} - unpipe@1.0.0: {} unplugin@1.16.1: @@ -23609,8 +23166,6 @@ snapshots: vscode-jsonrpc@6.0.0: {} - vscode-jsonrpc@8.2.0: {} - vscode-jsonrpc@8.2.1: {} vscode-languageclient@7.0.0: @@ -23624,21 +23179,8 @@ snapshots: vscode-jsonrpc: 6.0.0 vscode-languageserver-types: 3.16.0 - vscode-languageserver-protocol@3.17.5: - dependencies: - vscode-jsonrpc: 8.2.0 - vscode-languageserver-types: 3.17.5 - - vscode-languageserver-textdocument@1.0.11: {} - vscode-languageserver-types@3.16.0: {} - vscode-languageserver-types@3.17.5: {} - - vscode-languageserver@9.0.1: - dependencies: - vscode-languageserver-protocol: 3.17.5 - vscode-oniguruma@1.7.0: {} vscode-textmate@7.0.4: {} @@ -23917,8 +23459,6 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 - which-module@2.0.1: {} - which-typed-array@1.1.18: dependencies: available-typed-arrays: 1.0.7 @@ -23936,12 +23476,6 @@ snapshots: workerpool@6.2.0: {} - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -23956,13 +23490,6 @@ snapshots: wrappy@1.0.2: {} - write-file-atomic@3.0.3: - dependencies: - imurmurhash: 0.1.4 - is-typedarray: 1.0.0 - signal-exit: 3.0.7 - typedarray-to-buffer: 3.1.5 - write-file-atomic@4.0.2: dependencies: imurmurhash: 0.1.4 @@ -23979,8 +23506,6 @@ snapshots: xtend@4.0.2: {} - y18n@4.0.3: {} - y18n@5.0.8: {} yallist@3.1.1: {} @@ -23993,11 +23518,6 @@ snapshots: yaml@2.7.0: {} - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - yargs-parser@20.2.4: {} yargs-parser@21.1.1: {} @@ -24009,20 +23529,6 @@ snapshots: flat: 5.0.2 is-plain-obj: 2.1.0 - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - yargs@16.2.0: dependencies: cliui: 7.0.4 From 5ae0967db762b456c634359f3c62cff04fefc244 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 18 Jun 2025 14:44:31 -0700 Subject: [PATCH 43/71] remove build.rs script and replace with install.sh, fix connection status --- .github/workflows/primary.yml | 9 ++ engine/baml-schema-wasm/scripts/install.sh | 6 -- engine/language_server/build.rs | 85 ------------------- engine/language_server/scripts/install.sh | 41 +++++++++ .../src/playground/playground_server.rs | 18 ++-- engine/language_server/src/session.rs | 2 +- .../src/baml_wasm_web/EventListener.tsx | 15 ++-- 7 files changed, 68 insertions(+), 108 deletions(-) delete mode 100644 engine/language_server/build.rs create mode 100755 engine/language_server/scripts/install.sh diff --git a/.github/workflows/primary.yml b/.github/workflows/primary.yml index 342c6cb5f8..bc59349aa7 100644 --- a/.github/workflows/primary.yml +++ b/.github/workflows/primary.yml @@ -75,6 +75,9 @@ jobs: - name: Install Node run: pnpm install --frozen-lockfile working-directory: engine/language_client_typescript + - name: Run language server install script + run: bash ./scripts/install.sh + working-directory: engine/language_server - name: Build Wasm (for language server) run: cargo build --target=wasm32-unknown-unknown working-directory: engine/baml-schema-wasm @@ -139,6 +142,9 @@ jobs: - uses: Swatinem/rust-cache@v2 with: workspaces: engine + - name: Run language server install script + run: bash ./scripts/install.sh + working-directory: engine/language_server - name: Build Wasm (for language server) run: cargo build --target=wasm32-unknown-unknown working-directory: engine/baml-schema-wasm @@ -162,6 +168,9 @@ jobs: - uses: Swatinem/rust-cache@v2 with: workspaces: engine + - name: Run language server install script + run: bash ./scripts/install.sh + working-directory: engine/language_server - name: Build Wasm (for language server) run: cargo build --target=wasm32-unknown-unknown working-directory: engine/baml-schema-wasm diff --git a/engine/baml-schema-wasm/scripts/install.sh b/engine/baml-schema-wasm/scripts/install.sh index 0a1b3de806..dddbee7d75 100755 --- a/engine/baml-schema-wasm/scripts/install.sh +++ b/engine/baml-schema-wasm/scripts/install.sh @@ -8,12 +8,6 @@ printf '%s\n' " -> Creating out dir..." # shellcheck disable=SC2154 mkdir -p "$out"/src -# Check if wasm-bindgen is installed, install if not -if ! command -v wasm-bindgen &> /dev/null; then - printf '%s\n' " -> Installing wasm-bindgen-cli..." - cargo install -f wasm-bindgen-cli@0.2.92 -fi - printf '%s\n' " -> Generating $target package" wasm-bindgen \ --target "$target" \ diff --git a/engine/language_server/build.rs b/engine/language_server/build.rs deleted file mode 100644 index 8899b992b6..0000000000 --- a/engine/language_server/build.rs +++ /dev/null @@ -1,85 +0,0 @@ -/// This build script exists as a fix to guarantee -/// that the web-panel dist directory is built before the -/// language server is built. As the web-panel is a embedded -/// in the language server. -use std::env; -use std::path::PathBuf; -use std::process::Command; -use std::time::Duration; - -fn run_command(cmd: &mut Command, name: &str) -> std::io::Result<()> { - println!("cargo:warning=Running {}...", name); - let output = cmd.output()?; - - // Print stdout and stderr - if !output.stdout.is_empty() { - println!("cargo:warning={} stdout:", name); - println!("cargo:warning={}", String::from_utf8_lossy(&output.stdout)); - } - if !output.stderr.is_empty() { - println!("cargo:warning={} stderr:", name); - println!("cargo:warning={}", String::from_utf8_lossy(&output.stderr)); - } - - if !output.status.success() { - panic!("{} failed with status: {}", name, output.status); - } - Ok(()) -} - -fn main() { - // Get the manifest directory - let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let workspace_root = PathBuf::from(&manifest_dir).join("../.."); - let typescript_dir = workspace_root.join("typescript"); - let web_panel_dir = typescript_dir.join("vscode-ext/packages/web-panel"); - - println!( - "cargo:warning=Typescript directory: {}", - typescript_dir.display() - ); - - // Install dependencies - run_command( - Command::new("pnpm") - .current_dir(&typescript_dir) - .arg("install"), - "pnpm install", - ) - .expect("Failed to execute pnpm install command"); - - // pnpm run build:playground - // Builds the dependencies for the web-view dist - run_command( - Command::new("pnpm") - .current_dir(&typescript_dir) - .args(["run", "build:playground"]), - "pnpm build", - ) - .expect("Failed to execute pnpm build command"); - - // pnpm run build - // in web-panel, builds dist - run_command( - Command::new("pnpm") - .current_dir(&web_panel_dir) - .args(["run", "build"]), - "pnpm build", - ) - .expect("Failed to execute pnpm build command"); - - // Double check we correctly built the frontend - let dist_path = env::var("BAML_WEB_PANEL_DIST") - .map(PathBuf::from) - .unwrap_or_else(|_| web_panel_dir.join("dist")); - - if !dist_path.exists() { - panic!( - "Web panel dist directory not found at {}. Please ensure the path is correct or set BAML_WEB_PANEL_DIST environment variable.", - dist_path.display() - ); - } - - // Tell cargo to rerun if the dist directory changes - println!("cargo:rerun-if-changed={}", dist_path.display()); -} diff --git a/engine/language_server/scripts/install.sh b/engine/language_server/scripts/install.sh new file mode 100755 index 0000000000..24e25d0495 --- /dev/null +++ b/engine/language_server/scripts/install.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Exit on error +set -e + +# Get the workspace root directory +WORKSPACE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +TYPESCRIPT_DIR="$WORKSPACE_ROOT/typescript" +WEB_PANEL_DIR="$TYPESCRIPT_DIR/vscode-ext/packages/web-panel" + +echo "Typescript directory: $TYPESCRIPT_DIR" + +# Install dependencies +echo "Running pnpm install..." +cd "$TYPESCRIPT_DIR" +pnpm install + +# Build playground dependencies +echo "Building playground dependencies..." +pnpm run build:playground + +# Check if wasm-bindgen is installed, install if not +if ! command -v wasm-bindgen &> /dev/null; then + printf '%s\n' " -> Installing wasm-bindgen-cli..." + cargo install -f wasm-bindgen-cli@0.2.92 +fi + +# Build web panel +echo "Building web panel..." +cd "$WEB_PANEL_DIR" +pnpm run build + +# Check if dist directory exists +DIST_PATH="${BAML_WEB_PANEL_DIST:-$WEB_PANEL_DIR/dist}" +if [ ! -d "$DIST_PATH" ]; then + echo "Error: Web panel dist directory not found at $DIST_PATH" + echo "Please ensure the path is correct or set BAML_WEB_PANEL_DIST environment variable." + exit 1 +fi + +echo "Frontend build completed successfully!" \ No newline at end of file diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 9e0eac0047..8af4dce20f 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -2,6 +2,7 @@ use crate::playground::definitions::{FrontendMessage, PlaygroundState}; use crate::session::Session; use anyhow::Result; use futures_util::{SinkExt, StreamExt}; +use include_dir::{include_dir, Dir}; use mime_guess::from_path; use std::collections::HashMap; use std::path::PathBuf; @@ -9,8 +10,10 @@ use std::sync::Arc; use tokio::sync::RwLock; use warp::{http::Response, ws::Message, Filter}; -/// Path to the static files directory -const STATIC_DIR: &str = "../../typescript/vscode-ext/packages/web-panel/dist"; +/// Embed at compile time everything in dist/ +// WARNING: this is a relative path, will easily break if file structure changes +static STATIC_DIR: Dir<'_> = + include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); /// Helper to send all projects/files to a websocket client pub async fn send_all_projects_to_client( @@ -114,18 +117,17 @@ pub fn create_server_routes( .and_then(|full: warp::path::FullPath| async move { let path = full.as_str().trim_start_matches('/'); let file = if path.is_empty() { "index.html" } else { path }; - let file_path = PathBuf::from(STATIC_DIR).join(file); - - match tokio::fs::read(&file_path).await { - Ok(contents) => { + match STATIC_DIR.get_file(file) { + Some(f) => { + let body = f.contents(); let mime = from_path(file).first_or_octet_stream(); Ok::<_, warp::Rejection>( Response::builder() .header("content-type", mime.as_ref()) - .body(contents), + .body(body.to_vec()), ) } - Err(_) => Ok::<_, warp::Rejection>( + None => Ok::<_, warp::Rejection>( Response::builder().status(404).body(b"Not Found".to_vec()), ), } diff --git a/engine/language_server/src/session.rs b/engine/language_server/src/session.rs index 6031415880..5d2e342029 100644 --- a/engine/language_server/src/session.rs +++ b/engine/language_server/src/session.rs @@ -458,7 +458,7 @@ mod tests { fn test_get_or_create_project() { init_logging(LogLevel::Info, None); - let mut session = create_test_session(); + let session = create_test_session(); // Using paths similar to the logs let path_str1 = "/Users/aaronvillalpando/Projects/baml-examples/ruby-starter/baml_src"; diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index 677b46e4b5..59e1750f38 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -82,9 +82,8 @@ export const isConnectedAtom = atom(true) const ConnectionStatus: React.FC = () => { const isConnected = useAtomValue(isConnectedAtom) - const isVSCodeWebview = typeof vscode !== 'undefined' - if (isConnected) return null + if (isConnected || vscode.isVscode()) return null return (
@@ -109,7 +108,7 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre const debouncedSetFiles = useDebounceCallback(setFiles, 50, true) const setFlashRanges = useSetAtom(flashRangesAtom) const setIsConnected = useSetAtom(isConnectedAtom) - const isVSCodeWebview = typeof vscode !== 'undefined' + const isVSCodeWebview = vscode.isVscode() const [selectedFunc, setSelectedFunction] = useAtom(selectedFunctionAtom) const setSelectedTestcase = useSetAtom(selectedTestcaseAtom) @@ -139,11 +138,11 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre console.log('selectedFunc', selectedFunc) useEffect(() => { - // if (isVSCodeWebview) { - // console.log('Websocket disabled in VSCode') - // setIsConnected(true) - // return - // } + // Only open websocket if not in VSCode webview + if (isVSCodeWebview) { + setIsConnected(true) + // return + } const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' const ws = new WebSocket(`${scheme}://${window.location.host}/ws`) From 3dbc75f08f2fa3ce1be9f0973eedb3729b9c9140 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 18 Jun 2025 14:52:57 -0700 Subject: [PATCH 44/71] fix order of install script --- engine/language_server/scripts/install.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/language_server/scripts/install.sh b/engine/language_server/scripts/install.sh index 24e25d0495..f54775ecf6 100755 --- a/engine/language_server/scripts/install.sh +++ b/engine/language_server/scripts/install.sh @@ -15,16 +15,16 @@ echo "Running pnpm install..." cd "$TYPESCRIPT_DIR" pnpm install -# Build playground dependencies -echo "Building playground dependencies..." -pnpm run build:playground - # Check if wasm-bindgen is installed, install if not if ! command -v wasm-bindgen &> /dev/null; then printf '%s\n' " -> Installing wasm-bindgen-cli..." cargo install -f wasm-bindgen-cli@0.2.92 fi +# Build playground dependencies +echo "Building playground dependencies..." +pnpm run build:playground + # Build web panel echo "Building web panel..." cd "$WEB_PANEL_DIR" From 7cc5efbac3cf6e3ef7761bf2a95c63b65b038d19 Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 19 Jun 2025 09:39:58 -0700 Subject: [PATCH 45/71] add comments and rename script --- .github/workflows/primary.yml | 24 +++++++------------ .../scripts/{install.sh => build.sh} | 5 +++- 2 files changed, 13 insertions(+), 16 deletions(-) rename engine/language_server/scripts/{install.sh => build.sh} (83%) diff --git a/.github/workflows/primary.yml b/.github/workflows/primary.yml index bc59349aa7..4cac7f73a7 100644 --- a/.github/workflows/primary.yml +++ b/.github/workflows/primary.yml @@ -75,12 +75,12 @@ jobs: - name: Install Node run: pnpm install --frozen-lockfile working-directory: engine/language_client_typescript - - name: Run language server install script - run: bash ./scripts/install.sh + # This step is necessary to guarantee that the language server has a frontend to embed. + # Is also included in build and integ-tests steps. + - name: Build web-panel for language server + run: bash ./scripts/build.sh working-directory: engine/language_server - - name: Build Wasm (for language server) - run: cargo build --target=wasm32-unknown-unknown - working-directory: engine/baml-schema-wasm + # ------------------------------------------------------------ - name: Build Node run: pnpm build:debug working-directory: engine/language_client_typescript @@ -142,12 +142,9 @@ jobs: - uses: Swatinem/rust-cache@v2 with: workspaces: engine - - name: Run language server install script - run: bash ./scripts/install.sh + - name: Build web-panel for language server + run: bash ./scripts/build.sh working-directory: engine/language_server - - name: Build Wasm (for language server) - run: cargo build --target=wasm32-unknown-unknown - working-directory: engine/baml-schema-wasm - name: Test Rust # skip doctests & integration tests (the latter require OPENAI_API_KEY and ANTHROPIC_API_KEY to be set) run: cargo test --lib @@ -168,12 +165,9 @@ jobs: - uses: Swatinem/rust-cache@v2 with: workspaces: engine - - name: Run language server install script - run: bash ./scripts/install.sh + - name: Build web-panel for language server + run: bash ./scripts/build.sh working-directory: engine/language_server - - name: Build Wasm (for language server) - run: cargo build --target=wasm32-unknown-unknown - working-directory: engine/baml-schema-wasm - name: run python tests run: | cd integ-tests/python diff --git a/engine/language_server/scripts/install.sh b/engine/language_server/scripts/build.sh similarity index 83% rename from engine/language_server/scripts/install.sh rename to engine/language_server/scripts/build.sh index f54775ecf6..52d874b319 100755 --- a/engine/language_server/scripts/install.sh +++ b/engine/language_server/scripts/build.sh @@ -1,5 +1,9 @@ #!/bin/bash +# This script is needed as the language_server embeds the web-panel dist +# directory in the playground_server.rs file. It builds all of the dependencies +# for it as well as the web-panel itself. + # Exit on error set -e @@ -34,7 +38,6 @@ pnpm run build DIST_PATH="${BAML_WEB_PANEL_DIST:-$WEB_PANEL_DIR/dist}" if [ ! -d "$DIST_PATH" ]; then echo "Error: Web panel dist directory not found at $DIST_PATH" - echo "Please ensure the path is correct or set BAML_WEB_PANEL_DIST environment variable." exit 1 fi From c3cb181d486df9f167e58cd52c9131dc129cbd90 Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 19 Jun 2025 13:33:51 -0700 Subject: [PATCH 46/71] testing panel view --- .../com/boundaryml/jetbrains_ext/BamlLanguageServer.kt | 3 ++- .../com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt index c678e316ed..2d76fc7d7a 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt @@ -7,7 +7,8 @@ import java.nio.file.Path class BamlLanguageServer : OSProcessStreamConnectionProvider() { init { - val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), ".baml/jetbrains", "baml-cli-0.89.0-aarch64-apple-darwin", "baml-cli").toString(), "lsp") + // val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), ".baml/jetbrains", "baml-cli-0.89.0-aarch64-apple-darwin", "baml-cli").toString(), "lsp") + val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") super.setCommandLine(commandLine) } } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt index efb59abd38..630e9e1a40 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt @@ -28,7 +28,10 @@ class BamlToolWindowFactory : ToolWindowFactory { private val browser = JBCefBrowser() + + init { + // TODO: Have a launching playground status here var htmlContent = """ @@ -38,11 +41,11 @@ class BamlToolWindowFactory : ToolWindowFactory { Hello World -
TODO: render the BAML playground here and wire up the vscode provider bridge
+
TODO: Have a launching playground status here
""".trimIndent() - browser.loadHTML(htmlContent) +// browser.loadURL("localhost:3030/") } fun getContent(): JPanel { From 23810d9c143c9e58dda75a4a570f114d88569d3f Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 19 Jun 2025 16:02:24 -0700 Subject: [PATCH 47/71] LSP communicates port to jetbrains automatically with baml/port --- engine/language_server/src/server.rs | 32 ++++++++++--- .../jetbrains_ext/BamlCustomServerAPI.kt | 12 +++++ .../boundaryml/jetbrains_ext/BamlLanguage.kt | 2 +- .../jetbrains_ext/BamlLanguageClient.kt | 19 ++++++++ .../jetbrains_ext/BamlLanguageServer.kt | 8 +++- .../BamlLanguageServerFactory.kt | 12 ++--- .../jetbrains_ext/BamlPortService.kt | 30 ++++++++++++ .../jetbrains_ext/BamlProjectService.kt | 21 --------- .../jetbrains_ext/BamlToolWindowFactory.kt | 47 +++++++++++-------- 9 files changed, 126 insertions(+), 57 deletions(-) create mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlCustomServerAPI.kt create mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageClient.kt create mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlPortService.kt delete mode 100644 jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlProjectService.kt diff --git a/engine/language_server/src/server.rs b/engine/language_server/src/server.rs index 13498dd08b..c4bb16b374 100644 --- a/engine/language_server/src/server.rs +++ b/engine/language_server/src/server.rs @@ -39,6 +39,8 @@ pub(crate) use connection::ClientSender; use crate::playground::{PlaygroundServer, PlaygroundState}; +use serde::{Deserialize, Serialize}; + pub type Result = std::result::Result; pub(crate) struct Server { @@ -48,6 +50,17 @@ pub(crate) struct Server { pub session: Session, } +#[derive(Serialize, Deserialize)] +struct PortNotificationParams { + port: u16, +} + +impl PortNotificationParams { + fn new(port: u16) -> Self { + PortNotificationParams { port } + } +} + impl Server { pub fn new(worker_threads: NonZeroUsize) -> anyhow::Result { let connection = ConnectionInitializer::stdio(); @@ -391,6 +404,8 @@ impl Server { let mut playground_port = self.session.baml_settings.playground_port.unwrap_or(3030); let session_arc = Arc::new(self.session.clone()); let playground_server = PlaygroundServer::new(playground_state.clone(), session_arc); + let sender = self.connection.make_sender(); + rt.spawn(async move { loop { // Check if port is available before attempting to bind @@ -408,12 +423,17 @@ impl Server { "Hosted playground at http://localhost:{}...", playground_port ); - // Open the default browser - // if let Err(e) = - // webbrowser::open(&format!("http://localhost:{}", playground_port)) - // { - // tracing::warn!("Failed to open browser: {}", e); - // } + + // Send LSP notification about the port + let params = PortNotificationParams::new(playground_port); + let notification = lsp_server::Notification::new( + "baml/port".to_string(), + serde_json::to_value(params).unwrap(), + ); + if let Err(e) = sender.send(Message::Notification(notification)) { + tracing::error!("Failed to send port notification: {}", e); + } + server.run(playground_port).await.unwrap(); break; } else { diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlCustomServerAPI.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlCustomServerAPI.kt new file mode 100644 index 0000000000..7ccb36090d --- /dev/null +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlCustomServerAPI.kt @@ -0,0 +1,12 @@ +import com.intellij.openapi.application.Application +import org.eclipse.lsp4j.jsonrpc.services.JsonNotification +import org.eclipse.lsp4j.services.LanguageClient +import org.eclipse.lsp4j.services.LanguageServer +import java.util.concurrent.CompletableFuture; + +data class PortParams(val port: Int) + +interface BamlCustomServerAPI : LanguageClient { + @JsonNotification("baml/port") + fun onPort(params: PortParams) +} \ No newline at end of file diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguage.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguage.kt index 904b8f2d75..e3ede605bf 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguage.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguage.kt @@ -1,5 +1,5 @@ package com.boundaryml.jetbrains_ext - +import com.redhat.devtools.lsp4ij.client.LanguageClientImpl import com.intellij.lang.Language object BamlLanguage : Language("baml") { diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageClient.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageClient.kt new file mode 100644 index 0000000000..a7e7373563 --- /dev/null +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageClient.kt @@ -0,0 +1,19 @@ +package com.boundaryml.jetbrains_ext + +import BamlCustomServerAPI +import PortParams +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project +import com.redhat.devtools.lsp4ij.client.LanguageClientImpl + +class BamlLanguageClient(project: Project) : + LanguageClientImpl(project), BamlCustomServerAPI { + + private val log = Logger.getInstance(BamlLanguageClient::class.java) + + override fun onPort(params: PortParams) { + Logger.getInstance(javaClass).warn("Port params: ${params.port}") + project.getService(BamlPortService::class.java) + .setPort(params.port) + } +} diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt index 2d76fc7d7a..8954450440 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt @@ -1,14 +1,18 @@ package com.boundaryml.jetbrains_ext import com.intellij.execution.configurations.GeneralCommandLine +import com.intellij.openapi.project.Project import com.redhat.devtools.lsp4ij.server.OSProcessStreamConnectionProvider import java.nio.file.Path -class BamlLanguageServer : OSProcessStreamConnectionProvider() { +class BamlLanguageServer(private val project: Project) : OSProcessStreamConnectionProvider() { init { // val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), ".baml/jetbrains", "baml-cli-0.89.0-aarch64-apple-darwin", "baml-cli").toString(), "lsp") - val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") + val commandLine = GeneralCommandLine( + Path.of(System.getProperty("user.home"), + "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") super.setCommandLine(commandLine) } + } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt index 2aa368e03f..a5a1ad76c3 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt @@ -8,7 +8,7 @@ import com.redhat.devtools.lsp4ij.server.StreamConnectionProvider class BamlLanguageServerFactory : LanguageServerFactory { override fun createConnectionProvider(project: Project): StreamConnectionProvider { - return BamlLanguageServer() + return BamlLanguageServer(project) } override fun createClientFeatures(): LSPClientFeatures { @@ -17,13 +17,11 @@ class BamlLanguageServerFactory : LanguageServerFactory { return features } -// // If you need to provide client specific features -// override fun createLanguageClient(project: Project): LanguageClientImpl { -// return BamlLanguageServerFactory(project) -// } + override fun createLanguageClient(project: Project) = + BamlLanguageClient(project) // our custom client -// // If you need to expose a custom server API + // If you need to expose a custom server API // override fun getServerInterface(): Class { -// return MyCustomServerAPI::class.java +// return BamlCustomServerAPI::class.java // } } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlPortService.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlPortService.kt new file mode 100644 index 0000000000..324db367f8 --- /dev/null +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlPortService.kt @@ -0,0 +1,30 @@ +import com.intellij.openapi.components.Service +import com.intellij.openapi.project.Project +import com.intellij.util.messages.Topic + + +@Service(Service.Level.PROJECT) +class BamlPortService(private val project: Project) { + + companion object { + val TOPIC = Topic.create( + "BAML-port", + Listener::class.java, + Topic.BroadcastDirection.NONE + ) + } + + @Volatile + var port: Int? = null + private set + + fun setPort(newPort: Int) { + port = newPort + project.messageBus + .syncPublisher(TOPIC) + .onPort(newPort) + } + + fun interface Listener { fun onPort(port: Int) } +} + diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlProjectService.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlProjectService.kt deleted file mode 100644 index bb63190917..0000000000 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlProjectService.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.boundaryml.jetbrains_ext - -import com.intellij.openapi.components.Service -import com.intellij.openapi.diagnostic.thisLogger -import com.intellij.openapi.project.Project - -// This service runs in the background -@Service(Service.Level.PROJECT) -class BamlProjectService(project: Project) { - - init { - thisLogger().info(BamlBundle.message("projectService", project.name)) - thisLogger().info("BAML Jetbrains extension service has started") - } - - fun getRandomNumber() = (1..100).random() - - fun downloadCli(cliVersion: String) { - println("Downloading CLI version={cliVersion}") - } -} \ No newline at end of file diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt index 630e9e1a40..0e5326c77b 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt @@ -17,8 +17,23 @@ class BamlToolWindowFactory : ToolWindowFactory { } override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { - val myToolWindow = BamlToolWindow(toolWindow) - val content = ContentFactory.getInstance().createContent(myToolWindow.getContent(), null, false) + val browser = JBCefBrowser() + val panel = JPanel(BorderLayout()).apply { + add(browser.component, BorderLayout.CENTER) + } + + //-- subscribe once per tool-window instance + val connection = project.messageBus.connect(toolWindow.disposable) + connection.subscribe(BamlPortService.TOPIC, BamlPortService.Listener { port -> + browser.loadURL("http://localhost:$port/") + }) + + // if LS started before the tool window was opened + project.getService(BamlPortService::class.java).port?.let { port -> + browser.loadURL("http://localhost:$port/") + } + + val content = ContentFactory.getInstance().createContent(panel, null, false) toolWindow.contentManager.addContent(content) } @@ -28,24 +43,17 @@ class BamlToolWindowFactory : ToolWindowFactory { private val browser = JBCefBrowser() - - init { - // TODO: Have a launching playground status here - var htmlContent = """ - - - - - - Hello World - - -
TODO: Have a launching playground status here
- - - """.trimIndent() -// browser.loadURL("localhost:3030/") + browser.loadHTML( + """ + + + Loading… +
Loading BAML applications…
+ + """.trimIndent() + ) + } fun getContent(): JPanel { @@ -54,7 +62,6 @@ class BamlToolWindowFactory : ToolWindowFactory { } } - // This approach doesn't work. // We need to follow instructions here and implement resource loaders // https://plugins.jetbrains.com/docs/intellij/embedded-browser-jcef.html#loading-resources-from-plugin-distribution From 6360a5bdc3adbdad95c27282eb90a5b8cefb0ffe Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 19 Jun 2025 16:59:29 -0700 Subject: [PATCH 48/71] playground codelens button correctly selects function but no longer opens playground panel --- engine/language_server/src/server.rs | 5 +++- .../server/api/requests/execute_command.rs | 23 +++++++++++++++++++ ...mlPortService.kt => BamlGetPortService.kt} | 2 +- .../jetbrains_ext/BamlLanguageClient.kt | 2 +- .../jetbrains_ext/BamlToolWindowFactory.kt | 5 ++-- 5 files changed, 31 insertions(+), 6 deletions(-) rename jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/{BamlPortService.kt => BamlGetPortService.kt} (91%) diff --git a/engine/language_server/src/server.rs b/engine/language_server/src/server.rs index c4bb16b374..3736000594 100644 --- a/engine/language_server/src/server.rs +++ b/engine/language_server/src/server.rs @@ -367,7 +367,10 @@ impl Server { }), code_action_provider: Some(lsp_types::CodeActionProviderCapability::Simple(true)), execute_command_provider: Some(lsp_types::ExecuteCommandOptions { - commands: vec!["openPlayground".to_string()], + commands: vec![ + "openPlayground".to_string(), + "baml.openBamlPanel".to_string(), + ], work_done_progress_options: Default::default(), }), definition_provider: Some(lsp_types::OneOf::Left(true)), diff --git a/engine/language_server/src/server/api/requests/execute_command.rs b/engine/language_server/src/server/api/requests/execute_command.rs index 8a5e31e80a..4d7f4f7616 100644 --- a/engine/language_server/src/server/api/requests/execute_command.rs +++ b/engine/language_server/src/server/api/requests/execute_command.rs @@ -67,6 +67,29 @@ impl SyncRequestHandler for ExecuteCommand { } } } + } else if params.command == "baml.openBamlPanel" { + // First (and only) argument is the JSON object you put in the lens + if let Some(state) = &session.playground_state { + if let Some(function_name) = params + .arguments + .first() + .and_then(|arg| arg.get("functionName")) + .and_then(|v| v.as_str().map(|s| s.to_string())) + { + tracing::info!("Broadcasting function change for: {}", function_name); + let state = state.clone(); + if let Some(runtime) = &session.playground_runtime { + runtime.spawn(async move { + let _ = crate::playground::broadcast_function_change( + &state, + &function_name.to_string(), + function_name, + ) + .await; + }); + } + } + } } else { return Err(crate::server::api::Error { code: ErrorCode::MethodNotFound, diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlPortService.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlGetPortService.kt similarity index 91% rename from jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlPortService.kt rename to jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlGetPortService.kt index 324db367f8..a63267149c 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlPortService.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlGetPortService.kt @@ -4,7 +4,7 @@ import com.intellij.util.messages.Topic @Service(Service.Level.PROJECT) -class BamlPortService(private val project: Project) { +class BamlGetPortService(private val project: Project) { companion object { val TOPIC = Topic.create( diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageClient.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageClient.kt index a7e7373563..6df4977570 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageClient.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageClient.kt @@ -13,7 +13,7 @@ class BamlLanguageClient(project: Project) : override fun onPort(params: PortParams) { Logger.getInstance(javaClass).warn("Port params: ${params.port}") - project.getService(BamlPortService::class.java) + project.getService(BamlGetPortService::class.java) .setPort(params.port) } } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt index 0e5326c77b..c541b031b3 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt @@ -7,7 +7,6 @@ import com.intellij.openapi.wm.ToolWindowFactory import com.intellij.ui.content.ContentFactory import com.intellij.ui.jcef.JBCefBrowser import java.awt.BorderLayout -import java.awt.Container import javax.swing.JPanel class BamlToolWindowFactory : ToolWindowFactory { @@ -24,12 +23,12 @@ class BamlToolWindowFactory : ToolWindowFactory { //-- subscribe once per tool-window instance val connection = project.messageBus.connect(toolWindow.disposable) - connection.subscribe(BamlPortService.TOPIC, BamlPortService.Listener { port -> + connection.subscribe(BamlGetPortService.TOPIC, BamlGetPortService.Listener { port -> browser.loadURL("http://localhost:$port/") }) // if LS started before the tool window was opened - project.getService(BamlPortService::class.java).port?.let { port -> + project.getService(BamlGetPortService::class.java).port?.let { port -> browser.loadURL("http://localhost:$port/") } From c489da0a6d5073c2d3ae2d631bdc86eb7f1d7ea3 Mon Sep 17 00:00:00 2001 From: egol Date: Mon, 23 Jun 2025 18:02:45 -0700 Subject: [PATCH 49/71] add persistent functions on frontend server-side + execute command --- .../src/playground/definitions.rs | 20 +++++++++++++- .../src/playground/playground_server.rs | 26 +++++++++++++++++++ engine/language_server/src/server.rs | 2 +- .../src/server/api/requests/code_lens.rs | 1 - .../server/api/requests/execute_command.rs | 4 +-- .../jetbrains_ext/BamlToolWindowFactory.kt | 2 +- .../jetbrains_ext/OpenBamlPlaygroundAction.kt | 23 +++++++++++----- 7 files changed, 66 insertions(+), 12 deletions(-) diff --git a/engine/language_server/src/playground/definitions.rs b/engine/language_server/src/playground/definitions.rs index 5f49246c76..e574d8421a 100644 --- a/engine/language_server/src/playground/definitions.rs +++ b/engine/language_server/src/playground/definitions.rs @@ -32,12 +32,18 @@ pub struct PlaygroundState { pub tx: broadcast::Sender, // Keep a reference to the receiver to prevent the channel from being closed _rx: broadcast::Receiver, + /// Key = root_path, value = last selected function for that project + last_function: tokio::sync::RwLock>, } impl PlaygroundState { pub fn new() -> Self { let (tx, rx) = broadcast::channel(100); - Self { tx, _rx: rx } + Self { + tx, + _rx: rx, + last_function: tokio::sync::RwLock::new(HashMap::new()), + } } pub fn broadcast_update(&self, msg: String) -> anyhow::Result<()> { @@ -45,4 +51,16 @@ impl PlaygroundState { tracing::debug!("broadcast sent to {n} receivers"); Ok(()) } + + pub async fn set_last_function(&self, root: String, func: String) { + self.last_function.write().await.insert(root, func); + } + + pub async fn get_last_function(&self, root: &str) -> Option { + self.last_function.read().await.get(root).cloned() + } + + pub async fn get_all_root_paths_with_functions(&self) -> Vec { + self.last_function.read().await.keys().cloned().collect() + } } diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 8af4dce20f..4519d2b4e6 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -61,6 +61,24 @@ pub async fn start_client_connection( // Send initial project state using the helper send_all_projects_to_client(&mut ws_tx, &session).await; + // Send last-selected function for each project + { + let st = state.read().await; + let root_paths = st.get_all_root_paths_with_functions().await; + + for root_path in root_paths { + if let Some(func) = st.get_last_function(&root_path).await { + let msg = FrontendMessage::select_function { + root_path: root_path.clone(), + function_name: func, + }; + if let Ok(json) = serde_json::to_string(&msg) { + let _ = ws_tx.send(Message::text(json)).await; + } + } + } + } + // Handle incoming messages and broadcast updates tokio::spawn(async move { loop { @@ -162,6 +180,14 @@ pub async fn broadcast_function_change( ) -> Result<()> { tracing::debug!("Broadcasting function change for: {}", function_name); + // remember it + { + let st = state.read().await; + st.set_last_function(root_path.to_string(), function_name.clone()) + .await; + } + + // broadcast to all connected clients let select_function_msg = FrontendMessage::select_function { root_path: root_path.to_string(), function_name, diff --git a/engine/language_server/src/server.rs b/engine/language_server/src/server.rs index 3736000594..d808f43eef 100644 --- a/engine/language_server/src/server.rs +++ b/engine/language_server/src/server.rs @@ -369,7 +369,7 @@ impl Server { execute_command_provider: Some(lsp_types::ExecuteCommandOptions { commands: vec![ "openPlayground".to_string(), - "baml.openBamlPanel".to_string(), + "baml.changeFunction".to_string(), ], work_done_progress_options: Default::default(), }), diff --git a/engine/language_server/src/server/api/requests/code_lens.rs b/engine/language_server/src/server/api/requests/code_lens.rs index 18a9e5a2f0..5d7bec467d 100644 --- a/engine/language_server/src/server/api/requests/code_lens.rs +++ b/engine/language_server/src/server/api/requests/code_lens.rs @@ -121,7 +121,6 @@ impl SyncRequestHandler for CodeLens { // &state, // &root_path, // function_name, - // HashMap::new(), // We don't need the files map anymore // ) // .await; // }); diff --git a/engine/language_server/src/server/api/requests/execute_command.rs b/engine/language_server/src/server/api/requests/execute_command.rs index 4d7f4f7616..591172b9ab 100644 --- a/engine/language_server/src/server/api/requests/execute_command.rs +++ b/engine/language_server/src/server/api/requests/execute_command.rs @@ -67,8 +67,8 @@ impl SyncRequestHandler for ExecuteCommand { } } } - } else if params.command == "baml.openBamlPanel" { - // First (and only) argument is the JSON object you put in the lens + } else if params.command == "baml.changeFunction" { + // Logic for getting the function can be improved if let Some(state) = &session.playground_state { if let Some(function_name) = params .arguments diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt index c541b031b3..e57758b1b5 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt @@ -48,7 +48,7 @@ class BamlToolWindowFactory : ToolWindowFactory { Loading… -
Loading BAML applications…
+
Loading BAML application…
""".trimIndent() ) diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt index 6414633f68..2e9d6dd2e2 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt @@ -1,14 +1,25 @@ package com.boundaryml.jetbrains_ext -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.wm.ToolWindowManager +import com.redhat.devtools.lsp4ij.commands.LSPCommandAction +import org.eclipse.lsp4j.ExecuteCommandParams +import com.redhat.devtools.lsp4ij.commands.LSPCommand +import com.intellij.openapi.actionSystem.AnActionEvent +class OpenBamlPlaygroundAction : LSPCommandAction() { -class OpenBamlPlaygroundAction : AnAction() { - - override fun actionPerformed(e: AnActionEvent) { + override fun commandPerformed(command: LSPCommand, e: AnActionEvent) { val project = e.project ?: return - ToolWindowManager.getInstance(project).getToolWindow("BAML Playground")?.show() + val toolWindow = ToolWindowManager.getInstance(project) + .getToolWindow("BAML Playground") + + val args: List = command.arguments + + val ls = getLanguageServer(e)?.server ?: return + toolWindow?.show { + ls.workspaceService.executeCommand( + ExecuteCommandParams("baml.changeFunction", args) + ) + } } } \ No newline at end of file From 9b11f9982c81307c548000045908a0180324433a Mon Sep 17 00:00:00 2001 From: egol Date: Mon, 23 Jun 2025 18:37:31 -0700 Subject: [PATCH 50/71] add support for test code lens --- engine/language_server/src/playground/mod.rs | 2 +- .../src/playground/playground_server.rs | 17 +++++++ .../server/api/requests/execute_command.rs | 45 +++++++++++++++++++ .../jetbrains_ext/RunBamlTestAction.kt | 25 ++++++++--- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/engine/language_server/src/playground/mod.rs b/engine/language_server/src/playground/mod.rs index 3b18c7b521..1beba88886 100644 --- a/engine/language_server/src/playground/mod.rs +++ b/engine/language_server/src/playground/mod.rs @@ -5,5 +5,5 @@ pub mod playground_server; pub use definitions::{FrontendMessage, PlaygroundState}; pub use playground::PlaygroundServer; pub use playground_server::{ - broadcast_function_change, broadcast_project_update, create_server_routes, + broadcast_function_change, broadcast_project_update, broadcast_test_run, create_server_routes, }; diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 4519d2b4e6..2b9f58ec9f 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -199,3 +199,20 @@ pub async fn broadcast_function_change( } Ok(()) } + +// Helper function to broadcast test runs +pub async fn broadcast_test_run( + state: &Arc>, + test_name: String, +) -> Result<()> { + tracing::debug!("Broadcasting test run for: {}", test_name); + + // broadcast to all connected clients + let run_test_msg = FrontendMessage::run_test { test_name }; + + let msg_str = serde_json::to_string(&run_test_msg)?; + if let Err(e) = state.read().await.broadcast_update(msg_str) { + tracing::error!("Failed to broadcast test run: {}", e); + } + Ok(()) +} diff --git a/engine/language_server/src/server/api/requests/execute_command.rs b/engine/language_server/src/server/api/requests/execute_command.rs index 591172b9ab..8badbb7b14 100644 --- a/engine/language_server/src/server/api/requests/execute_command.rs +++ b/engine/language_server/src/server/api/requests/execute_command.rs @@ -90,6 +90,51 @@ impl SyncRequestHandler for ExecuteCommand { } } } + } else if params.command == "baml.runTest" { + // Logic for running a test + if let Some(state) = &session.playground_state { + if let Some(args) = params.arguments.first().and_then(|arg| arg.as_object()) { + if let (Some(test_case_name), Some(function_name), Some(project_id)) = ( + args.get("testCaseName").and_then(|v| v.as_str()), + args.get("functionName").and_then(|v| v.as_str()), + args.get("projectId").and_then(|v| v.as_str()), + ) { + tracing::info!( + "Broadcasting test run for: {} in function: {}", + test_case_name, + function_name + ); + + // First, set the selected function + let state_clone = state.clone(); + let func_name = function_name.to_string(); + let project_path = project_id.to_string(); + if let Some(runtime) = &session.playground_runtime { + runtime.spawn(async move { + let _ = crate::playground::broadcast_function_change( + &state_clone, + &project_path, + func_name, + ) + .await; + }); + } + + // Then, broadcast the test run + let state_clone = state.clone(); + let test_name = test_case_name.to_string(); + if let Some(runtime) = &session.playground_runtime { + runtime.spawn(async move { + // Wait a bit for the function change to be processed + sleep(Duration::from_millis(100)).await; + let _ = + crate::playground::broadcast_test_run(&state_clone, test_name) + .await; + }); + } + } + } + } } else { return Err(crate::server::api::Error { code: ErrorCode::MethodNotFound, diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt index 806995e73d..bd881bd800 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt @@ -1,14 +1,25 @@ package com.boundaryml.jetbrains_ext -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.wm.ToolWindowManager +import com.redhat.devtools.lsp4ij.commands.LSPCommandAction +import com.redhat.devtools.lsp4ij.commands.LSPCommand +import org.eclipse.lsp4j.ExecuteCommandParams +import com.intellij.openapi.actionSystem.AnActionEvent +class RunBamlTestAction : LSPCommandAction() { -class RunBamlTestAction : AnAction() { - - override fun actionPerformed(e: AnActionEvent) { + override fun commandPerformed(command: LSPCommand, e: AnActionEvent) { val project = e.project ?: return - ToolWindowManager.getInstance(project).getToolWindow("BAML Playground")?.show() + val toolWindow = ToolWindowManager.getInstance(project) + .getToolWindow("BAML Playground") + + val args: List = command.arguments // e.g. ["myTestName"] + val ls = getLanguageServer(e)?.server ?: return + + toolWindow?.show { + ls.workspaceService.executeCommand( + ExecuteCommandParams("baml.runTest", args) + ) + } } -} +} \ No newline at end of file From 9649c58189eae5b1e58b07fc4e9bd9c57b25caf9 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 10:46:12 -0700 Subject: [PATCH 51/71] add a queue to playground server so it can wait for websocket connection --- .../src/playground/definitions.rs | 23 ++++++++++++++++ .../src/playground/playground_server.rs | 27 ++++++++++++++++--- .../server/api/requests/execute_command.rs | 7 +++-- .../src/baml_wasm_web/EventListener.tsx | 4 +-- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/engine/language_server/src/playground/definitions.rs b/engine/language_server/src/playground/definitions.rs index e574d8421a..b76e197166 100644 --- a/engine/language_server/src/playground/definitions.rs +++ b/engine/language_server/src/playground/definitions.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::collections::VecDeque; use tokio::sync::broadcast; // Note: the name add_project should match exactly to the @@ -34,6 +35,9 @@ pub struct PlaygroundState { _rx: broadcast::Receiver, /// Key = root_path, value = last selected function for that project last_function: tokio::sync::RwLock>, + /// Buffer for events that occur before the first client connects. + pub event_buffer: VecDeque, + pub first_client_connected: bool, } impl PlaygroundState { @@ -43,6 +47,8 @@ impl PlaygroundState { tx, _rx: rx, last_function: tokio::sync::RwLock::new(HashMap::new()), + event_buffer: VecDeque::new(), + first_client_connected: false, } } @@ -63,4 +69,21 @@ impl PlaygroundState { pub async fn get_all_root_paths_with_functions(&self) -> Vec { self.last_function.read().await.keys().cloned().collect() } + + /// Push an event to the buffer if the first client hasn't connected yet. + pub fn buffer_event(&mut self, event: String) { + if !self.first_client_connected { + self.event_buffer.push_back(event); + } + } + + /// Drain the buffer, returning all buffered events. + pub fn drain_event_buffer(&mut self) -> Vec { + self.event_buffer.drain(..).collect() + } + + /// Mark that the first client has connected. + pub fn mark_first_client_connected(&mut self) { + self.first_client_connected = true; + } } diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 2b9f58ec9f..59c6e79e2b 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -79,6 +79,18 @@ pub async fn start_client_connection( } } + // --- SEND BUFFERED EVENTS (if any) --- + { + let mut st = state.write().await; + let buffered_events = st.drain_event_buffer(); + for event in buffered_events.clone() { + let _ = ws_tx.send(Message::text(event)).await; + } + tracing::info!("Sent {} buffered events", buffered_events.len()); + st.mark_first_client_connected(); + } + // --- END BUFFERED EVENTS --- + // Handle incoming messages and broadcast updates tokio::spawn(async move { loop { @@ -166,7 +178,10 @@ pub async fn broadcast_project_update( }; let msg_str = serde_json::to_string(&add_project_msg)?; - if let Err(e) = state.read().await.broadcast_update(msg_str) { + let mut st = state.write().await; + if !st.first_client_connected { + st.buffer_event(msg_str); + } else if let Err(e) = st.broadcast_update(msg_str) { tracing::error!("Failed to broadcast project update: {}", e); } Ok(()) @@ -194,7 +209,10 @@ pub async fn broadcast_function_change( }; let msg_str = serde_json::to_string(&select_function_msg)?; - if let Err(e) = state.read().await.broadcast_update(msg_str) { + let mut st = state.write().await; + if !st.first_client_connected { + st.buffer_event(msg_str); + } else if let Err(e) = st.broadcast_update(msg_str) { tracing::error!("Failed to broadcast function change: {}", e); } Ok(()) @@ -211,7 +229,10 @@ pub async fn broadcast_test_run( let run_test_msg = FrontendMessage::run_test { test_name }; let msg_str = serde_json::to_string(&run_test_msg)?; - if let Err(e) = state.read().await.broadcast_update(msg_str) { + let mut st = state.write().await; + if !st.first_client_connected { + st.buffer_event(msg_str); + } else if let Err(e) = st.broadcast_update(msg_str) { tracing::error!("Failed to broadcast test run: {}", e); } Ok(()) diff --git a/engine/language_server/src/server/api/requests/execute_command.rs b/engine/language_server/src/server/api/requests/execute_command.rs index 8badbb7b14..385b54c6ae 100644 --- a/engine/language_server/src/server/api/requests/execute_command.rs +++ b/engine/language_server/src/server/api/requests/execute_command.rs @@ -55,8 +55,6 @@ impl SyncRequestHandler for ExecuteCommand { let state = state.clone(); if let Some(runtime) = &session.playground_runtime { runtime.spawn(async move { - // Wait a bit for the server to be ready - sleep(Duration::from_millis(500)).await; let _ = crate::playground::broadcast_function_change( &state, &function_name.to_string(), @@ -106,6 +104,7 @@ impl SyncRequestHandler for ExecuteCommand { ); // First, set the selected function + // TODO: test run should handle this in the future let state_clone = state.clone(); let func_name = function_name.to_string(); let project_path = project_id.to_string(); @@ -125,8 +124,8 @@ impl SyncRequestHandler for ExecuteCommand { let test_name = test_case_name.to_string(); if let Some(runtime) = &session.playground_runtime { runtime.spawn(async move { - // Wait a bit for the function change to be processed - sleep(Duration::from_millis(100)).await; + // TODO: temoporary fix to wait for function change to process + sleep(Duration::from_millis(1200)).await; let _ = crate::playground::broadcast_test_run(&state_clone, test_name) .await; diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index 59e1750f38..4049aa16c7 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -135,7 +135,7 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre setOrchestratorIndex(0) } }, [selectedFunc]) - console.log('selectedFunc', selectedFunc) + // console.log('selectedFunc', selectedFunc) useEffect(() => { // Only open websocket if not in VSCode webview @@ -172,8 +172,6 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre return () => ws.close() }, [setIsConnected, isVSCodeWebview]) - console.log('Websocket execution finished') - useEffect(() => { console.log('adding event listener') const fn = ( From 0dfd5d7c9ebf55264f8d6c26603b747050a17bcc Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 10:48:18 -0700 Subject: [PATCH 52/71] remove logic for storing last selected function server side --- .../src/playground/definitions.rs | 15 ----------- .../src/playground/playground_server.rs | 25 ------------------- 2 files changed, 40 deletions(-) diff --git a/engine/language_server/src/playground/definitions.rs b/engine/language_server/src/playground/definitions.rs index b76e197166..c50a5b4f2a 100644 --- a/engine/language_server/src/playground/definitions.rs +++ b/engine/language_server/src/playground/definitions.rs @@ -33,8 +33,6 @@ pub struct PlaygroundState { pub tx: broadcast::Sender, // Keep a reference to the receiver to prevent the channel from being closed _rx: broadcast::Receiver, - /// Key = root_path, value = last selected function for that project - last_function: tokio::sync::RwLock>, /// Buffer for events that occur before the first client connects. pub event_buffer: VecDeque, pub first_client_connected: bool, @@ -46,7 +44,6 @@ impl PlaygroundState { Self { tx, _rx: rx, - last_function: tokio::sync::RwLock::new(HashMap::new()), event_buffer: VecDeque::new(), first_client_connected: false, } @@ -58,18 +55,6 @@ impl PlaygroundState { Ok(()) } - pub async fn set_last_function(&self, root: String, func: String) { - self.last_function.write().await.insert(root, func); - } - - pub async fn get_last_function(&self, root: &str) -> Option { - self.last_function.read().await.get(root).cloned() - } - - pub async fn get_all_root_paths_with_functions(&self) -> Vec { - self.last_function.read().await.keys().cloned().collect() - } - /// Push an event to the buffer if the first client hasn't connected yet. pub fn buffer_event(&mut self, event: String) { if !self.first_client_connected { diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 59c6e79e2b..bc98ced6f2 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -61,24 +61,6 @@ pub async fn start_client_connection( // Send initial project state using the helper send_all_projects_to_client(&mut ws_tx, &session).await; - // Send last-selected function for each project - { - let st = state.read().await; - let root_paths = st.get_all_root_paths_with_functions().await; - - for root_path in root_paths { - if let Some(func) = st.get_last_function(&root_path).await { - let msg = FrontendMessage::select_function { - root_path: root_path.clone(), - function_name: func, - }; - if let Ok(json) = serde_json::to_string(&msg) { - let _ = ws_tx.send(Message::text(json)).await; - } - } - } - } - // --- SEND BUFFERED EVENTS (if any) --- { let mut st = state.write().await; @@ -195,13 +177,6 @@ pub async fn broadcast_function_change( ) -> Result<()> { tracing::debug!("Broadcasting function change for: {}", function_name); - // remember it - { - let st = state.read().await; - st.set_last_function(root_path.to_string(), function_name.clone()) - .await; - } - // broadcast to all connected clients let select_function_msg = FrontendMessage::select_function { root_path: root_path.to_string(), From f6fa631ad3281a4c9dd02480c348a33b58256c95 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 11:38:31 -0700 Subject: [PATCH 53/71] adding back in github LSP downloading --- .../src/playground/playground_server.rs | 1 + .../jetbrains_ext/BamlLanguageServer.kt | 19 ++++- .../BamlLanguageServerFactory.kt | 2 +- .../BamlLanguageServerInstaller.kt | 48 ++++++----- .../jetbrains_ext/BamlToolWindowFactory.kt | 79 ++++++++++++++----- .../jetbrains_ext/OpenBamlPlaygroundAction.kt | 2 +- .../jetbrains_ext/RunBamlTestAction.kt | 4 +- 7 files changed, 103 insertions(+), 52 deletions(-) diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index bc98ced6f2..a830dd6874 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -12,6 +12,7 @@ use warp::{http::Response, ws::Message, Filter}; /// Embed at compile time everything in dist/ // WARNING: this is a relative path, will easily break if file structure changes +// WARNING: works as a macro so any build script executes after this is evaluated static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt index 8954450440..bdd627b62b 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt @@ -3,16 +3,27 @@ package com.boundaryml.jetbrains_ext import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.openapi.project.Project import com.redhat.devtools.lsp4ij.server.OSProcessStreamConnectionProvider +import java.nio.file.Files import java.nio.file.Path class BamlLanguageServer(private val project: Project) : OSProcessStreamConnectionProvider() { init { // val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), ".baml/jetbrains", "baml-cli-0.89.0-aarch64-apple-darwin", "baml-cli").toString(), "lsp") - val commandLine = GeneralCommandLine( - Path.of(System.getProperty("user.home"), - "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") - super.setCommandLine(commandLine) +// val commandLine = GeneralCommandLine( +// Path.of(System.getProperty("user.home"), +// "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") +// super.setCommandLine(commandLine) + + val cacheDir = Path.of(System.getProperty("user.home"), ".baml/jetbrains") + val version = Files.readString(cacheDir.resolve("baml-cli-installed.txt")).trim() + + val (arch, platform, _) = BamlLanguageServerInstaller.getPlatformTriple() + val exe = if (platform == "pc-windows-msvc") "baml-cli.exe" else "baml-cli" + val cli = cacheDir.resolve("baml-cli-$version-$arch-$platform").resolve(exe) + + super.setCommandLine(GeneralCommandLine(cli.toString(), "lsp")) + } } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt index a5a1ad76c3..b203206be7 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerFactory.kt @@ -22,6 +22,6 @@ class BamlLanguageServerFactory : LanguageServerFactory { // If you need to expose a custom server API // override fun getServerInterface(): Class { -// return BamlCustomServerAPI::class.java +// return BamlCustomServerAPI.kt::class.java // } } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt index bfd9a20890..86ecd40089 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt @@ -25,6 +25,29 @@ class BamlLanguageServerInstaller : LanguageServerInstallerBase() { private val bamlCacheDir: Path = Path.of(System.getProperty("user.home"), ".baml/jetbrains") private val breadcrumbFile: Path = bamlCacheDir.resolve("baml-cli-installed.txt") + companion object { + /** arch, platform, extension (zip|tar.gz) */ + @JvmStatic + fun getPlatformTriple(): Triple { + val os = System.getProperty("os.name").lowercase() + val arch = System.getProperty("os.arch").lowercase() + + val releaseArch = when { + arch.contains("aarch64") || arch.contains("arm64") -> "aarch64" + arch.contains("x86_64") || arch.contains("amd64") -> "x86_64" + else -> error("Unsupported arch: $arch") + } + val releasePlatform = when { + os.contains("mac") -> "apple-darwin" + os.contains("win") -> "pc-windows-msvc" + os.contains("linux") -> "unknown-linux-gnu" + else -> error("Unsupported OS: $os") + } + val ext = if (releasePlatform == "pc-windows-msvc") "zip" else "tar.gz" + return Triple(releaseArch, releasePlatform, ext) + } + } + override fun checkServerInstalled(indicator: ProgressIndicator): Boolean { super.progress("Checking if BAML CLI is installed...", indicator) ProgressManager.checkCanceled() @@ -90,31 +113,6 @@ class BamlLanguageServerInstaller : LanguageServerInstallerBase() { } } - private fun getPlatformTriple(): Triple { - val os = System.getProperty("os.name").lowercase() - val arch = System.getProperty("os.arch").lowercase() - - val releaseArch = when { - arch.contains("aarch64") || arch.contains("arm64") -> "aarch64" - arch.contains("x86_64") || arch.contains("amd64") -> "x86_64" - else -> throw IllegalArgumentException("Unsupported architecture: $arch") - } - - val releasePlatform = when { - os.contains("mac") -> "apple-darwin" - os.contains("win") -> "pc-windows-msvc" - os.contains("linux") -> "unknown-linux-gnu" - else -> throw IllegalArgumentException("Unsupported platform: $os") - } - - val extension = when (releasePlatform) { - "pc-windows-msvc" -> "zip" - else -> "tar.gz" - } - - return Triple(releaseArch, releasePlatform, extension) - } - private fun downloadFile(artifactName: String, extension: String, version: String, indicator: ProgressIndicator): Path { val url = "$GH_RELEASES_BASE/$version/$artifactName.$extension" val tempFile = Files.createTempFile("baml-cli", ".$extension") diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt index e57758b1b5..6de232a25e 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt @@ -2,6 +2,7 @@ package com.boundaryml.jetbrains_ext import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory import com.intellij.ui.content.ContentFactory @@ -9,6 +10,44 @@ import com.intellij.ui.jcef.JBCefBrowser import java.awt.BorderLayout import javax.swing.JPanel +private const val PLACEHOLDER_HTML = """ + + + + + Loading BAML Playground… + + + +
+

Starting BAML Playground…

+ + +""" + class BamlToolWindowFactory : ToolWindowFactory { init { @@ -16,24 +55,32 @@ class BamlToolWindowFactory : ToolWindowFactory { } override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { - val browser = JBCefBrowser() - val panel = JPanel(BorderLayout()).apply { - add(browser.component, BorderLayout.CENTER) + val browser = JBCefBrowser().apply { + loadHTML(PLACEHOLDER_HTML.trimIndent()) } - //-- subscribe once per tool-window instance - val connection = project.messageBus.connect(toolWindow.disposable) - connection.subscribe(BamlGetPortService.TOPIC, BamlGetPortService.Listener { port -> - browser.loadURL("http://localhost:$port/") - }) - - // if LS started before the tool window was opened - project.getService(BamlGetPortService::class.java).port?.let { port -> - browser.loadURL("http://localhost:$port/") + val savedPort = project.getService(BamlGetPortService::class.java).port + if (savedPort != null) { + // LS was up before the tool-window opened + browser.loadURL("http://localhost:$savedPort/") + } else { + // LS not ready yet wait for a port message + val busConnection = project.messageBus.connect(toolWindow.disposable) + busConnection.subscribe( + BamlGetPortService.TOPIC, + BamlGetPortService.Listener { port -> + browser.loadURL("http://localhost:$port/") + busConnection.disconnect() // one-shot, avoid duplicates + } + ) } + // show browser in a tool window + val panel = JPanel(BorderLayout()).apply { add(browser.component, BorderLayout.CENTER) } val content = ContentFactory.getInstance().createContent(panel, null, false) toolWindow.contentManager.addContent(content) + + Disposer.register(toolWindow.disposable, browser) } override fun shouldBeAvailable(project: Project) = true @@ -44,13 +91,7 @@ class BamlToolWindowFactory : ToolWindowFactory { init { browser.loadHTML( - """ - - - Loading… -
Loading BAML application…
- - """.trimIndent() + PLACEHOLDER_HTML.trimIndent() ) } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt index 2e9d6dd2e2..b48895c813 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/OpenBamlPlaygroundAction.kt @@ -15,8 +15,8 @@ class OpenBamlPlaygroundAction : LSPCommandAction() { val args: List = command.arguments - val ls = getLanguageServer(e)?.server ?: return toolWindow?.show { + val ls = getLanguageServer(e)?.server ?: return@show ls.workspaceService.executeCommand( ExecuteCommandParams("baml.changeFunction", args) ) diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt index bd881bd800..6054cd74da 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/RunBamlTestAction.kt @@ -13,10 +13,10 @@ class RunBamlTestAction : LSPCommandAction() { val toolWindow = ToolWindowManager.getInstance(project) .getToolWindow("BAML Playground") - val args: List = command.arguments // e.g. ["myTestName"] - val ls = getLanguageServer(e)?.server ?: return + val args: List = command.arguments toolWindow?.show { + val ls = getLanguageServer(e)?.server ?: return@show ls.workspaceService.executeCommand( ExecuteCommandParams("baml.runTest", args) ) From 57ed8273a210d1b161b0c8f48ee6ea281dabbc41 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 12:58:04 -0700 Subject: [PATCH 54/71] add kotlinSerialization for github release parsing --- jetbrains/build.gradle.kts | 1 + jetbrains/gradle/libs.versions.toml | 11 ++++++----- .../boundaryml/jetbrains_ext/BamlLanguageServer.kt | 1 + .../jetbrains_ext/BamlLanguageServerInstaller.kt | 2 +- .../com/boundaryml/jetbrains_ext/BamlPluginTest.kt | 6 +++--- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/jetbrains/build.gradle.kts b/jetbrains/build.gradle.kts index 45f01edb94..e1d690fbf6 100644 --- a/jetbrains/build.gradle.kts +++ b/jetbrains/build.gradle.kts @@ -5,6 +5,7 @@ import org.jetbrains.intellij.platform.gradle.TestFrameworkType plugins { id("java") // Java support alias(libs.plugins.kotlin) // Kotlin support + alias(libs.plugins.kotlinSerialization) alias(libs.plugins.intelliJPlatform) // IntelliJ Platform Gradle Plugin alias(libs.plugins.changelog) // Gradle Changelog Plugin alias(libs.plugins.qodana) // Gradle Qodana Plugin diff --git a/jetbrains/gradle/libs.versions.toml b/jetbrains/gradle/libs.versions.toml index bead92d5b6..478264e43a 100644 --- a/jetbrains/gradle/libs.versions.toml +++ b/jetbrains/gradle/libs.versions.toml @@ -15,8 +15,9 @@ junit = { group = "junit", name = "junit", version.ref = "junit" } opentest4j = { group = "org.opentest4j", name = "opentest4j", version.ref = "opentest4j" } [plugins] -changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } -intelliJPlatform = { id = "org.jetbrains.intellij.platform", version.ref = "intelliJPlatform" } -kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } -kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } -qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" } +changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } +intelliJPlatform = { id = "org.jetbrains.intellij.platform", version.ref = "intelliJPlatform" } +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } +qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" } \ No newline at end of file diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt index bdd627b62b..eddd8b5f9e 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt @@ -10,6 +10,7 @@ class BamlLanguageServer(private val project: Project) : OSProcessStreamConnecti init { // val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), ".baml/jetbrains", "baml-cli-0.89.0-aarch64-apple-darwin", "baml-cli").toString(), "lsp") + // UNCOMMENT FOR DEBUGGING LOCALLY // val commandLine = GeneralCommandLine( // Path.of(System.getProperty("user.home"), // "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt index 86ecd40089..ef16269561 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt @@ -13,7 +13,6 @@ import java.nio.file.attribute.PosixFilePermission import java.security.MessageDigest import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonNamingStrategy import java.util.zip.ZipInputStream class BamlLanguageServerInstaller : LanguageServerInstallerBase() { @@ -104,6 +103,7 @@ class BamlLanguageServerInstaller : LanguageServerInstallerBase() { ignoreUnknownKeys = true } val release = jsonParser.decodeFromString(jsonText) + release.tagName.removePrefix("v") } catch (e: Exception) { super.progress("GitHub fetch failed, falling back to local cache...", indicator) diff --git a/jetbrains/src/test/kotlin/com/boundaryml/jetbrains_ext/BamlPluginTest.kt b/jetbrains/src/test/kotlin/com/boundaryml/jetbrains_ext/BamlPluginTest.kt index ec6bf5a7d8..711b4e87ee 100644 --- a/jetbrains/src/test/kotlin/com/boundaryml/jetbrains_ext/BamlPluginTest.kt +++ b/jetbrains/src/test/kotlin/com/boundaryml/jetbrains_ext/BamlPluginTest.kt @@ -29,9 +29,9 @@ class BamlPluginTest : BasePlatformTestCase() { } fun testProjectService() { - val projectService = project.service() - - assertNotSame(projectService.getRandomNumber(), projectService.getRandomNumber()) +// val projectService = project.service() +// +// assertNotSame(projectService.getRandomNumber(), projectService.getRandomNumber()) } override fun getTestDataPath() = "src/test/testData/rename" From 5a63181d5ab4c5c357c458a30b3644821f3f993f Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 16:17:10 -0700 Subject: [PATCH 55/71] change gradle properties to use stable lsp4ij version --- engine/language_server/src/playground/mod.rs | 6 +- .../src/playground/playground.rs | 28 --- .../src/playground/playground_server.rs | 213 ++--------------- .../playground/playground_server_helpers.rs | 215 ++++++++++++++++++ jetbrains/gradle.properties | 3 +- .../jetbrains_ext/BamlLanguageServer.kt | 26 +-- .../jetbrains_ext/BamlToolWindowFactory.kt | 10 +- 7 files changed, 251 insertions(+), 250 deletions(-) delete mode 100644 engine/language_server/src/playground/playground.rs create mode 100644 engine/language_server/src/playground/playground_server_helpers.rs diff --git a/engine/language_server/src/playground/mod.rs b/engine/language_server/src/playground/mod.rs index 1beba88886..df48ad8a75 100644 --- a/engine/language_server/src/playground/mod.rs +++ b/engine/language_server/src/playground/mod.rs @@ -1,9 +1,9 @@ pub mod definitions; -pub mod playground; pub mod playground_server; +pub mod playground_server_helpers; pub use definitions::{FrontendMessage, PlaygroundState}; -pub use playground::PlaygroundServer; -pub use playground_server::{ +pub use playground_server::PlaygroundServer; +pub use playground_server_helpers::{ broadcast_function_change, broadcast_project_update, broadcast_test_run, create_server_routes, }; diff --git a/engine/language_server/src/playground/playground.rs b/engine/language_server/src/playground/playground.rs deleted file mode 100644 index 12694237cd..0000000000 --- a/engine/language_server/src/playground/playground.rs +++ /dev/null @@ -1,28 +0,0 @@ -/// Script that runs the playground server. -/// On the input port -use crate::playground::definitions::PlaygroundState; -use crate::playground::playground_server::create_server_routes; -use crate::session::Session; -use anyhow::Result; -use std::sync::Arc; -use tokio::sync::RwLock; - -#[derive(Debug, Clone)] -pub struct PlaygroundServer { - state: Arc>, - session: Arc, -} - -impl PlaygroundServer { - pub fn new(state: Arc>, session: Arc) -> Self { - Self { state, session } - } - - pub async fn run(self, port: u16) -> Result<()> { - let routes = create_server_routes(self.state, self.session); - - warp::serve(routes).try_bind(([127, 0, 0, 1], port)).await; - - Ok(()) - } -} diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index a830dd6874..12b8880601 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -1,215 +1,28 @@ -use crate::playground::definitions::{FrontendMessage, PlaygroundState}; +/// Script that runs the playground server. +/// On the input port +use crate::playground::definitions::PlaygroundState; +use crate::playground::playground_server_helpers::create_server_routes; use crate::session::Session; use anyhow::Result; -use futures_util::{SinkExt, StreamExt}; -use include_dir::{include_dir, Dir}; -use mime_guess::from_path; -use std::collections::HashMap; -use std::path::PathBuf; use std::sync::Arc; use tokio::sync::RwLock; -use warp::{http::Response, ws::Message, Filter}; -/// Embed at compile time everything in dist/ -// WARNING: this is a relative path, will easily break if file structure changes -// WARNING: works as a macro so any build script executes after this is evaluated -static STATIC_DIR: Dir<'_> = - include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); - -/// Helper to send all projects/files to a websocket client -pub async fn send_all_projects_to_client( - ws_tx: &mut (impl SinkExt + Unpin), - session: &Arc, -) { - let projects = { - let projects = session.baml_src_projects.lock().unwrap(); - projects - .iter() - .map(|(root_path, project)| { - let project = project.lock().unwrap(); - let files = project.baml_project.files.clone(); - let root_path = root_path.to_string_lossy().to_string(); - let files_map: HashMap = files - .into_iter() - .map(|(path, doc)| (path.path().to_string_lossy().to_string(), doc.contents)) - .collect(); - (root_path, files_map) - }) - .collect::>() - }; - for (root_path, files_map) in projects { - let add_project_msg = FrontendMessage::add_project { - root_path, - files: files_map, - }; - if let Ok(msg_str) = serde_json::to_string(&add_project_msg) { - let _ = ws_tx.send(Message::text(msg_str)).await; - } - } -} - -pub async fn start_client_connection( - ws: warp::ws::WebSocket, +#[derive(Debug, Clone)] +pub struct PlaygroundServer { state: Arc>, session: Arc, -) { - let (mut ws_tx, mut ws_rx) = ws.split(); - let mut rx = { - let state = state.read().await; - state.tx.subscribe() - }; - - // Send initial project state using the helper - send_all_projects_to_client(&mut ws_tx, &session).await; - - // --- SEND BUFFERED EVENTS (if any) --- - { - let mut st = state.write().await; - let buffered_events = st.drain_event_buffer(); - for event in buffered_events.clone() { - let _ = ws_tx.send(Message::text(event)).await; - } - tracing::info!("Sent {} buffered events", buffered_events.len()); - st.mark_first_client_connected(); - } - // --- END BUFFERED EVENTS --- - - // Handle incoming messages and broadcast updates - tokio::spawn(async move { - loop { - tokio::select! { - // Handle incoming messages from the client - Some(result) = ws_rx.next() => { - match result { - Ok(msg) => { - if msg.is_close() { - tracing::info!("Client disconnected"); - break; - } - } - Err(e) => { - tracing::error!("WebSocket error: {}", e); - break; - } - } - } - // Handle broadcast messages - Ok(msg) = rx.recv() => { - if let Err(e) = ws_tx.send(Message::text(msg)).await { - tracing::error!("Failed to send broadcast message: {}", e); - break; - } - } - else => break, - } - } - }); } -/// Adds a "/" route which servers the static files of the frontend -/// and a "/ws" route which handles the websocket connection. -pub fn create_server_routes( - state: Arc>, - session: Arc, -) -> impl Filter + Clone { - // WebSocket handler with error handling - let ws_route = warp::path("ws") - .and(warp::ws()) - .map(move |ws: warp::ws::Ws| { - let state = state.clone(); - let session = session.clone(); - ws.on_upgrade(move |socket| async move { - start_client_connection(socket, state, session).await; - }) - }); - - // Static file serving needed to serve the frontend files - let spa = - warp::path::full() - .and(warp::get()) - .and_then(|full: warp::path::FullPath| async move { - let path = full.as_str().trim_start_matches('/'); - let file = if path.is_empty() { "index.html" } else { path }; - match STATIC_DIR.get_file(file) { - Some(f) => { - let body = f.contents(); - let mime = from_path(file).first_or_octet_stream(); - Ok::<_, warp::Rejection>( - Response::builder() - .header("content-type", mime.as_ref()) - .body(body.to_vec()), - ) - } - None => Ok::<_, warp::Rejection>( - Response::builder().status(404).body(b"Not Found".to_vec()), - ), - } - }); - - ws_route.or(spa).with(warp::log("playground-server")) -} - -// Helper function to broadcast project updates with better error handling -pub async fn broadcast_project_update( - state: &Arc>, - root_path: &str, - files: HashMap, -) -> Result<()> { - let add_project_msg = FrontendMessage::add_project { - root_path: root_path.to_string(), - files, - }; - - let msg_str = serde_json::to_string(&add_project_msg)?; - let mut st = state.write().await; - if !st.first_client_connected { - st.buffer_event(msg_str); - } else if let Err(e) = st.broadcast_update(msg_str) { - tracing::error!("Failed to broadcast project update: {}", e); - } - Ok(()) -} - -// Helper function to broadcast function changes -pub async fn broadcast_function_change( - state: &Arc>, - root_path: &str, - function_name: String, -) -> Result<()> { - tracing::debug!("Broadcasting function change for: {}", function_name); - - // broadcast to all connected clients - let select_function_msg = FrontendMessage::select_function { - root_path: root_path.to_string(), - function_name, - }; - - let msg_str = serde_json::to_string(&select_function_msg)?; - let mut st = state.write().await; - if !st.first_client_connected { - st.buffer_event(msg_str); - } else if let Err(e) = st.broadcast_update(msg_str) { - tracing::error!("Failed to broadcast function change: {}", e); +impl PlaygroundServer { + pub fn new(state: Arc>, session: Arc) -> Self { + Self { state, session } } - Ok(()) -} -// Helper function to broadcast test runs -pub async fn broadcast_test_run( - state: &Arc>, - test_name: String, -) -> Result<()> { - tracing::debug!("Broadcasting test run for: {}", test_name); + pub async fn run(self, port: u16) -> Result<()> { + let routes = create_server_routes(self.state, self.session); - // broadcast to all connected clients - let run_test_msg = FrontendMessage::run_test { test_name }; + warp::serve(routes).try_bind(([127, 0, 0, 1], port)).await; - let msg_str = serde_json::to_string(&run_test_msg)?; - let mut st = state.write().await; - if !st.first_client_connected { - st.buffer_event(msg_str); - } else if let Err(e) = st.broadcast_update(msg_str) { - tracing::error!("Failed to broadcast test run: {}", e); + Ok(()) } - Ok(()) } diff --git a/engine/language_server/src/playground/playground_server_helpers.rs b/engine/language_server/src/playground/playground_server_helpers.rs new file mode 100644 index 0000000000..a830dd6874 --- /dev/null +++ b/engine/language_server/src/playground/playground_server_helpers.rs @@ -0,0 +1,215 @@ +use crate::playground::definitions::{FrontendMessage, PlaygroundState}; +use crate::session::Session; +use anyhow::Result; +use futures_util::{SinkExt, StreamExt}; +use include_dir::{include_dir, Dir}; +use mime_guess::from_path; +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::Arc; +use tokio::sync::RwLock; +use warp::{http::Response, ws::Message, Filter}; + +/// Embed at compile time everything in dist/ +// WARNING: this is a relative path, will easily break if file structure changes +// WARNING: works as a macro so any build script executes after this is evaluated +static STATIC_DIR: Dir<'_> = + include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); + +/// Helper to send all projects/files to a websocket client +pub async fn send_all_projects_to_client( + ws_tx: &mut (impl SinkExt + Unpin), + session: &Arc, +) { + let projects = { + let projects = session.baml_src_projects.lock().unwrap(); + projects + .iter() + .map(|(root_path, project)| { + let project = project.lock().unwrap(); + let files = project.baml_project.files.clone(); + let root_path = root_path.to_string_lossy().to_string(); + let files_map: HashMap = files + .into_iter() + .map(|(path, doc)| (path.path().to_string_lossy().to_string(), doc.contents)) + .collect(); + (root_path, files_map) + }) + .collect::>() + }; + for (root_path, files_map) in projects { + let add_project_msg = FrontendMessage::add_project { + root_path, + files: files_map, + }; + if let Ok(msg_str) = serde_json::to_string(&add_project_msg) { + let _ = ws_tx.send(Message::text(msg_str)).await; + } + } +} + +pub async fn start_client_connection( + ws: warp::ws::WebSocket, + state: Arc>, + session: Arc, +) { + let (mut ws_tx, mut ws_rx) = ws.split(); + let mut rx = { + let state = state.read().await; + state.tx.subscribe() + }; + + // Send initial project state using the helper + send_all_projects_to_client(&mut ws_tx, &session).await; + + // --- SEND BUFFERED EVENTS (if any) --- + { + let mut st = state.write().await; + let buffered_events = st.drain_event_buffer(); + for event in buffered_events.clone() { + let _ = ws_tx.send(Message::text(event)).await; + } + tracing::info!("Sent {} buffered events", buffered_events.len()); + st.mark_first_client_connected(); + } + // --- END BUFFERED EVENTS --- + + // Handle incoming messages and broadcast updates + tokio::spawn(async move { + loop { + tokio::select! { + // Handle incoming messages from the client + Some(result) = ws_rx.next() => { + match result { + Ok(msg) => { + if msg.is_close() { + tracing::info!("Client disconnected"); + break; + } + } + Err(e) => { + tracing::error!("WebSocket error: {}", e); + break; + } + } + } + // Handle broadcast messages + Ok(msg) = rx.recv() => { + if let Err(e) = ws_tx.send(Message::text(msg)).await { + tracing::error!("Failed to send broadcast message: {}", e); + break; + } + } + else => break, + } + } + }); +} + +/// Adds a "/" route which servers the static files of the frontend +/// and a "/ws" route which handles the websocket connection. +pub fn create_server_routes( + state: Arc>, + session: Arc, +) -> impl Filter + Clone { + // WebSocket handler with error handling + let ws_route = warp::path("ws") + .and(warp::ws()) + .map(move |ws: warp::ws::Ws| { + let state = state.clone(); + let session = session.clone(); + ws.on_upgrade(move |socket| async move { + start_client_connection(socket, state, session).await; + }) + }); + + // Static file serving needed to serve the frontend files + let spa = + warp::path::full() + .and(warp::get()) + .and_then(|full: warp::path::FullPath| async move { + let path = full.as_str().trim_start_matches('/'); + let file = if path.is_empty() { "index.html" } else { path }; + match STATIC_DIR.get_file(file) { + Some(f) => { + let body = f.contents(); + let mime = from_path(file).first_or_octet_stream(); + Ok::<_, warp::Rejection>( + Response::builder() + .header("content-type", mime.as_ref()) + .body(body.to_vec()), + ) + } + None => Ok::<_, warp::Rejection>( + Response::builder().status(404).body(b"Not Found".to_vec()), + ), + } + }); + + ws_route.or(spa).with(warp::log("playground-server")) +} + +// Helper function to broadcast project updates with better error handling +pub async fn broadcast_project_update( + state: &Arc>, + root_path: &str, + files: HashMap, +) -> Result<()> { + let add_project_msg = FrontendMessage::add_project { + root_path: root_path.to_string(), + files, + }; + + let msg_str = serde_json::to_string(&add_project_msg)?; + let mut st = state.write().await; + if !st.first_client_connected { + st.buffer_event(msg_str); + } else if let Err(e) = st.broadcast_update(msg_str) { + tracing::error!("Failed to broadcast project update: {}", e); + } + Ok(()) +} + +// Helper function to broadcast function changes +pub async fn broadcast_function_change( + state: &Arc>, + root_path: &str, + function_name: String, +) -> Result<()> { + tracing::debug!("Broadcasting function change for: {}", function_name); + + // broadcast to all connected clients + let select_function_msg = FrontendMessage::select_function { + root_path: root_path.to_string(), + function_name, + }; + + let msg_str = serde_json::to_string(&select_function_msg)?; + let mut st = state.write().await; + if !st.first_client_connected { + st.buffer_event(msg_str); + } else if let Err(e) = st.broadcast_update(msg_str) { + tracing::error!("Failed to broadcast function change: {}", e); + } + Ok(()) +} + +// Helper function to broadcast test runs +pub async fn broadcast_test_run( + state: &Arc>, + test_name: String, +) -> Result<()> { + tracing::debug!("Broadcasting test run for: {}", test_name); + + // broadcast to all connected clients + let run_test_msg = FrontendMessage::run_test { test_name }; + + let msg_str = serde_json::to_string(&run_test_msg)?; + let mut st = state.write().await; + if !st.first_client_connected { + st.buffer_event(msg_str); + } else if let Err(e) = st.broadcast_update(msg_str) { + tracing::error!("Failed to broadcast test run: {}", e); + } + Ok(()) +} diff --git a/jetbrains/gradle.properties b/jetbrains/gradle.properties index fe2a779013..8047bcd459 100644 --- a/jetbrains/gradle.properties +++ b/jetbrains/gradle.properties @@ -23,7 +23,8 @@ platformVersion = 2024.2.5 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.jetbrains.php:203.4449.22, org.intellij.scala:2023.3.27@EAP #platformPlugins = com.redhat.devtools.lsp4ij:0.13.0 -platformPlugins = com.redhat.devtools.lsp4ij:0.13.1-20250530-194419@nightly +# platformPlugins = com.redhat.devtools.lsp4ij:0.13.1-20250530-194419@nightly +platformPlugins = com.redhat.devtools.lsp4ij:0.14.0 # Example: platformBundledPlugins = com.intellij.java platformBundledPlugins = org.jetbrains.plugins.textmate diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt index eddd8b5f9e..34583c6bd8 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt @@ -11,19 +11,19 @@ class BamlLanguageServer(private val project: Project) : OSProcessStreamConnecti init { // val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), ".baml/jetbrains", "baml-cli-0.89.0-aarch64-apple-darwin", "baml-cli").toString(), "lsp") // UNCOMMENT FOR DEBUGGING LOCALLY -// val commandLine = GeneralCommandLine( -// Path.of(System.getProperty("user.home"), -// "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") -// super.setCommandLine(commandLine) - - val cacheDir = Path.of(System.getProperty("user.home"), ".baml/jetbrains") - val version = Files.readString(cacheDir.resolve("baml-cli-installed.txt")).trim() - - val (arch, platform, _) = BamlLanguageServerInstaller.getPlatformTriple() - val exe = if (platform == "pc-windows-msvc") "baml-cli.exe" else "baml-cli" - val cli = cacheDir.resolve("baml-cli-$version-$arch-$platform").resolve(exe) - - super.setCommandLine(GeneralCommandLine(cli.toString(), "lsp")) + val commandLine = GeneralCommandLine( + Path.of(System.getProperty("user.home"), + "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") + super.setCommandLine(commandLine) + +// val cacheDir = Path.of(System.getProperty("user.home"), ".baml/jetbrains") +// val version = Files.readString(cacheDir.resolve("baml-cli-installed.txt")).trim() +// +// val (arch, platform, _) = BamlLanguageServerInstaller.getPlatformTriple() +// val exe = if (platform == "pc-windows-msvc") "baml-cli.exe" else "baml-cli" +// val cli = cacheDir.resolve("baml-cli-$version-$arch-$platform").resolve(exe) +// +// super.setCommandLine(GeneralCommandLine(cli.toString(), "lsp")) } diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt index 6de232a25e..bf2cd5edaa 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlToolWindowFactory.kt @@ -59,6 +59,11 @@ class BamlToolWindowFactory : ToolWindowFactory { loadHTML(PLACEHOLDER_HTML.trimIndent()) } + // show browser in a tool window + val panel = JPanel(BorderLayout()).apply { add(browser.component, BorderLayout.CENTER) } + val content = ContentFactory.getInstance().createContent(panel, null, false) + toolWindow.contentManager.addContent(content) + val savedPort = project.getService(BamlGetPortService::class.java).port if (savedPort != null) { // LS was up before the tool-window opened @@ -75,11 +80,6 @@ class BamlToolWindowFactory : ToolWindowFactory { ) } - // show browser in a tool window - val panel = JPanel(BorderLayout()).apply { add(browser.component, BorderLayout.CENTER) } - val content = ContentFactory.getInstance().createContent(panel, null, false) - toolWindow.contentManager.addContent(content) - Disposer.register(toolWindow.disposable, browser) } From 8e4a18388906367e91d6605916f625990c7f65a2 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 16:54:23 -0700 Subject: [PATCH 56/71] formatting pass --- .../src/playground/playground_server.rs | 11 +++++----- .../playground/playground_server_helpers.rs | 12 ++++++----- engine/language_server/src/server.rs | 5 ++--- .../server/api/notifications/did_change.rs | 1 - .../server/api/requests/execute_command.rs | 20 ++++++++++++------- .../src/server/api/requests/hover.rs | 1 - 6 files changed, 28 insertions(+), 22 deletions(-) diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 12b8880601..70fbfd3e9e 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -1,11 +1,12 @@ +use std::sync::Arc; + +use anyhow::Result; +use tokio::sync::RwLock; + /// Script that runs the playground server. /// On the input port use crate::playground::definitions::PlaygroundState; -use crate::playground::playground_server_helpers::create_server_routes; -use crate::session::Session; -use anyhow::Result; -use std::sync::Arc; -use tokio::sync::RwLock; +use crate::{playground::playground_server_helpers::create_server_routes, session::Session}; #[derive(Debug, Clone)] pub struct PlaygroundServer { diff --git a/engine/language_server/src/playground/playground_server_helpers.rs b/engine/language_server/src/playground/playground_server_helpers.rs index a830dd6874..98a835cfcf 100644 --- a/engine/language_server/src/playground/playground_server_helpers.rs +++ b/engine/language_server/src/playground/playground_server_helpers.rs @@ -1,15 +1,17 @@ -use crate::playground::definitions::{FrontendMessage, PlaygroundState}; -use crate::session::Session; +use std::{collections::HashMap, path::PathBuf, sync::Arc}; + use anyhow::Result; use futures_util::{SinkExt, StreamExt}; use include_dir::{include_dir, Dir}; use mime_guess::from_path; -use std::collections::HashMap; -use std::path::PathBuf; -use std::sync::Arc; use tokio::sync::RwLock; use warp::{http::Response, ws::Message, Filter}; +use crate::{ + playground::definitions::{FrontendMessage, PlaygroundState}, + session::Session, +}; + /// Embed at compile time everything in dist/ // WARNING: this is a relative path, will easily break if file structure changes // WARNING: works as a macro so any build script executes after this is evaluated diff --git a/engine/language_server/src/server.rs b/engine/language_server/src/server.rs index 309e926031..05f03f7927 100644 --- a/engine/language_server/src/server.rs +++ b/engine/language_server/src/server.rs @@ -9,8 +9,6 @@ use std::{ sync::Arc, time::{Duration, Instant}, }; -use tokio::sync::RwLock; -use serde::{Deserialize, Serialize}; use log::info; use lsp_server::Message; @@ -22,6 +20,7 @@ use lsp_types::{ WorkspaceClientCapabilities, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities, }; use schedule::Task; +use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; use self::{ @@ -418,7 +417,7 @@ impl Server { loop { // Check if port is available before attempting to bind let port_available = - { std::net::TcpListener::bind(("127.0.0.1", playground_port)).is_ok() }; + { std::net::TcpListener::bind(("127.0.0.1", playground_port)).is_ok() }; if port_available { // Port is available, start the server diff --git a/engine/language_server/src/server/api/notifications/did_change.rs b/engine/language_server/src/server/api/notifications/did_change.rs index ec076f3716..c488539309 100644 --- a/engine/language_server/src/server/api/notifications/did_change.rs +++ b/engine/language_server/src/server/api/notifications/did_change.rs @@ -3,7 +3,6 @@ use std::{collections::HashMap, time::Instant}; use lsp_types::{ notification::DidChangeTextDocument, DidChangeTextDocumentParams, PublishDiagnosticsParams, }; -use std::collections::HashMap; use crate::{ playground::broadcast_project_update, diff --git a/engine/language_server/src/server/api/requests/execute_command.rs b/engine/language_server/src/server/api/requests/execute_command.rs index 385b54c6ae..7136a66e0c 100644 --- a/engine/language_server/src/server/api/requests/execute_command.rs +++ b/engine/language_server/src/server/api/requests/execute_command.rs @@ -1,15 +1,21 @@ -use crate::server::api::traits::{RequestHandler, SyncRequestHandler}; -// use crate::server::api::DocumentKey; -use crate::server::api::ResultExt; -use crate::server::client::Requester; -use crate::server::{client::Notifier, Result}; -use crate::Session; +use std::time::Duration; + use lsp_server::ErrorCode; use lsp_types::{request, ExecuteCommandParams, MessageType}; -use std::time::Duration; use tokio::time::sleep; use webbrowser; +// use crate::server::api::DocumentKey; +use crate::server::api::ResultExt; +use crate::{ + server::{ + api::traits::{RequestHandler, SyncRequestHandler}, + client::{Notifier, Requester}, + Result, + }, + Session, +}; + pub struct ExecuteCommand; impl RequestHandler for ExecuteCommand { diff --git a/engine/language_server/src/server/api/requests/hover.rs b/engine/language_server/src/server/api/requests/hover.rs index 9d03a82afd..37b60da854 100644 --- a/engine/language_server/src/server/api/requests/hover.rs +++ b/engine/language_server/src/server/api/requests/hover.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use lsp_types::{self as types, request as req, HoverParams, TextDocumentItem}; -use std::collections::HashMap; use crate::{ server::{ From 8da4663b31aa3073b8a01427ecd823988b88c610 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 16:56:46 -0700 Subject: [PATCH 57/71] more fixes for clippy --- engine/language_server/src/playground/definitions.rs | 6 ++++++ .../src/server/api/requests/code_action.rs | 11 +++++------ .../src/server/api/requests/go_to_definition.rs | 5 ++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/engine/language_server/src/playground/definitions.rs b/engine/language_server/src/playground/definitions.rs index 55e1b8ff7c..967b63ed80 100644 --- a/engine/language_server/src/playground/definitions.rs +++ b/engine/language_server/src/playground/definitions.rs @@ -38,6 +38,12 @@ pub struct PlaygroundState { pub first_client_connected: bool, } +impl Default for PlaygroundState { + fn default() -> Self { + Self::new() + } +} + impl PlaygroundState { pub fn new() -> Self { let (tx, rx) = broadcast::channel(100); diff --git a/engine/language_server/src/server/api/requests/code_action.rs b/engine/language_server/src/server/api/requests/code_action.rs index 5aff747bfb..834f3e3f5a 100644 --- a/engine/language_server/src/server/api/requests/code_action.rs +++ b/engine/language_server/src/server/api/requests/code_action.rs @@ -44,27 +44,26 @@ impl SyncRequestHandler for CodeActionHandler { .get_or_create_project(&path) .expect("Ensured that a project db exists"); let document_key = - DocumentKey::from_url(&project.lock().unwrap().root_path(), &uri).internal_error()?; + DocumentKey::from_url(project.lock().unwrap().root_path(), &uri).internal_error()?; // Get the first function from the current file if available let function_name = project .lock() .unwrap() .list_functions() - .unwrap_or(vec![]) + .unwrap_or_default() .into_iter() - .filter(|f| f.span.file_path == document_key.path().to_string_lossy()) - .next() + .find(|f| f.span.file_path == document_key.path().to_string_lossy()) .map(|f| f.name); // Get the playground port from session settings let port = session.baml_settings.playground_port.unwrap_or(3030); let action = CodeActionOrCommand::CodeAction(CodeAction { - title: format!("Open Playground"), + title: "Open Playground".to_string(), kind: Some(CodeActionKind::EMPTY), command: Some(Command { - title: format!("Open Playground"), + title: "Open Playground".to_string(), command: "openPlayground".to_string(), arguments: function_name.map(|name| vec![Value::String(name)]), }), diff --git a/engine/language_server/src/server/api/requests/go_to_definition.rs b/engine/language_server/src/server/api/requests/go_to_definition.rs index 2b85ccbcdd..518eef8458 100644 --- a/engine/language_server/src/server/api/requests/go_to_definition.rs +++ b/engine/language_server/src/server/api/requests/go_to_definition.rs @@ -103,10 +103,9 @@ impl SyncRequestHandler for GotoDefinition { // Get the first function from the current file if available if let Some(function) = guard .list_functions() - .unwrap_or(vec![]) + .unwrap_or_default() .into_iter() - .filter(|f| f.span.file_path == document_key.path().to_string_lossy()) - .next() + .find(|f| f.span.file_path == document_key.path().to_string_lossy()) { tracing::info!("Broadcasting function change for: {}", function.name); let root_path = guard.root_path().to_string_lossy().to_string(); From bd4c9c69f906898bb7ca3d58fbd01bb7d4ced69b Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 17:04:04 -0700 Subject: [PATCH 58/71] turn of debug mode --- .../jetbrains_ext/BamlLanguageServer.kt | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt index 34583c6bd8..eddd8b5f9e 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServer.kt @@ -11,19 +11,19 @@ class BamlLanguageServer(private val project: Project) : OSProcessStreamConnecti init { // val commandLine = GeneralCommandLine(Path.of(System.getProperty("user.home"), ".baml/jetbrains", "baml-cli-0.89.0-aarch64-apple-darwin", "baml-cli").toString(), "lsp") // UNCOMMENT FOR DEBUGGING LOCALLY - val commandLine = GeneralCommandLine( - Path.of(System.getProperty("user.home"), - "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") - super.setCommandLine(commandLine) - -// val cacheDir = Path.of(System.getProperty("user.home"), ".baml/jetbrains") -// val version = Files.readString(cacheDir.resolve("baml-cli-installed.txt")).trim() -// -// val (arch, platform, _) = BamlLanguageServerInstaller.getPlatformTriple() -// val exe = if (platform == "pc-windows-msvc") "baml-cli.exe" else "baml-cli" -// val cli = cacheDir.resolve("baml-cli-$version-$arch-$platform").resolve(exe) -// -// super.setCommandLine(GeneralCommandLine(cli.toString(), "lsp")) +// val commandLine = GeneralCommandLine( +// Path.of(System.getProperty("user.home"), +// "/Documents/baml/engine/target/debug", "baml-cli").toString(), "lsp") +// super.setCommandLine(commandLine) + + val cacheDir = Path.of(System.getProperty("user.home"), ".baml/jetbrains") + val version = Files.readString(cacheDir.resolve("baml-cli-installed.txt")).trim() + + val (arch, platform, _) = BamlLanguageServerInstaller.getPlatformTriple() + val exe = if (platform == "pc-windows-msvc") "baml-cli.exe" else "baml-cli" + val cli = cacheDir.resolve("baml-cli-$version-$arch-$platform").resolve(exe) + + super.setCommandLine(GeneralCommandLine(cli.toString(), "lsp")) } From 1835beab22311a512e49a2ccb0ccbb9bbfcceadb Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 18:18:09 -0700 Subject: [PATCH 59/71] fix formatting --- engine/zed/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/zed/src/lib.rs b/engine/zed/src/lib.rs index 6783ad586a..278b54df6f 100644 --- a/engine/zed/src/lib.rs +++ b/engine/zed/src/lib.rs @@ -1,6 +1,6 @@ use std::fs; -use zed_extension_api::{self as zed, settings::LspSettings, LanguageServerId, Result}; +use zed_extension_api::{self as zed, LanguageServerId, Result, settings::LspSettings}; // Follows csharp extension as a template: // https://github.com/zed-extensions/csharp/blob/main/src/csharp.rs From ac15c8a8c1ec01a3ee01594557963128dbffbe09 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 18:20:06 -0700 Subject: [PATCH 60/71] clippy fixes --- engine/zed/src/lib.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/engine/zed/src/lib.rs b/engine/zed/src/lib.rs index 278b54df6f..06b7f9f10f 100644 --- a/engine/zed/src/lib.rs +++ b/engine/zed/src/lib.rs @@ -41,11 +41,13 @@ impl BamlExtension { } if let Some(path) = &self.cached_binary_path { - if fs::metadata(path).map_or(false, |stat| stat.is_file()) { - return Ok(BamlBinary { - path: path.clone(), - args: binary_args, - }); + if let Ok(stat) = fs::metadata(path) { + if stat.is_file() { + return Ok(BamlBinary { + path: path.clone(), + args: binary_args, + }); + } } } @@ -106,7 +108,7 @@ impl BamlExtension { let version_dir = format!("baml-cli-{}", release.version); let binary_path = format!("{version_dir}/baml-cli"); - if !fs::metadata(&binary_path).map_or(false, |stat| stat.is_file()) { + if !fs::metadata(&binary_path).is_ok_and(|stat| stat.is_file()) { zed::set_language_server_installation_status( language_server_id, &zed::LanguageServerInstallationStatus::Downloading, From f2cc6796b9775a0935d3f028a743ae05264b746f Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 18:34:47 -0700 Subject: [PATCH 61/71] check for temp directory to avoid error --- .../jetbrains_ext/BamlTextMateBundleProvider.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlTextMateBundleProvider.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlTextMateBundleProvider.kt index 4668e9cd74..f480d03a8c 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlTextMateBundleProvider.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlTextMateBundleProvider.kt @@ -38,7 +38,13 @@ class BamlTextMateBundleProvider : TextMateBundleProvider { // and (2) build system shenanigans in jetbrains-plugin-fss for packaging the tmbundle. override fun getBundles(): List { try { - val tmpDir: Path = Files.createTempDirectory(Path.of(PathManager.getTempPath()), "textmate-baml") + val tempPath = Path.of(PathManager.getTempPath()) + // Ensure the temp directory exists + if (!Files.exists(tempPath)) { + Files.createDirectories(tempPath) + } + + val tmpDir: Path = Files.createTempDirectory(tempPath, "textmate-baml") files.forEach { fileToCopy -> val resource: URL? = javaClass.classLoader.getResource("textmate/$fileToCopy") From 095caac3670f787969eb42b3f0c08351107e7dc8 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 19:18:45 -0700 Subject: [PATCH 62/71] try forcing more memory --- jetbrains/gradle.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jetbrains/gradle.properties b/jetbrains/gradle.properties index 8047bcd459..63e4026349 100644 --- a/jetbrains/gradle.properties +++ b/jetbrains/gradle.properties @@ -39,3 +39,6 @@ org.gradle.configuration-cache = true # Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html org.gradle.caching = true + +# Kotlin daemon memory configuration to prevent OutOfMemoryError +kotlin.daemon.jvmargs=-Xmx2g From 8555e607e4c6df15152425c729bef378d2c3b500 Mon Sep 17 00:00:00 2001 From: egol Date: Tue, 24 Jun 2025 19:36:32 -0700 Subject: [PATCH 63/71] add checks to file extraction --- .../BamlLanguageServerInstaller.kt | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt index ef16269561..0967763681 100644 --- a/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt +++ b/jetbrains/src/main/kotlin/com/boundaryml/jetbrains_ext/BamlLanguageServerInstaller.kt @@ -162,7 +162,14 @@ class BamlLanguageServerInstaller : LanguageServerInstallerBase() { TarArchiveInputStream(gzipIn).use { tarIn -> var entry: TarArchiveEntry? = tarIn.nextTarEntry while (entry != null) { - val outPath = destDir.resolve(entry.name) + val sanitizedName = sanitizePath(entry.name) + val outPath = destDir.resolve(sanitizedName) + + // Ensure the resolved path is within the destination directory + if (!outPath.startsWith(destDir)) { + throw SecurityException("Archive entry path would escape destination directory: ${entry.name}") + } + if (entry.isDirectory) { Files.createDirectories(outPath) } else { @@ -178,7 +185,14 @@ class BamlLanguageServerInstaller : LanguageServerInstallerBase() { ZipInputStream(Files.newInputStream(archivePath)).use { zipIn -> var entry = zipIn.nextEntry while (entry != null) { - val outPath = destDir.resolve(entry.name) + val sanitizedName = sanitizePath(entry.name) + val outPath = destDir.resolve(sanitizedName) + + // Ensure the resolved path is within the destination directory + if (!outPath.startsWith(destDir)) { + throw SecurityException("Archive entry path would escape destination directory: ${entry.name}") + } + if (entry.isDirectory) { Files.createDirectories(outPath) } else { @@ -193,6 +207,11 @@ class BamlLanguageServerInstaller : LanguageServerInstallerBase() { } } + private fun sanitizePath(path: String): String { + // Normalize the path and remove any ".." components + return Path.of(path).normalize().toString().replace("..", "") + } + private fun setExecutable(file: Path) { if (!Files.exists(file)) return try { From 5e3fd6f6e90108ed00250187e9a16bf28abfa568 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 25 Jun 2025 15:02:46 -0700 Subject: [PATCH 64/71] basic hook up of lsp playground to vscode + codelens --- .../src/playground/definitions.rs | 27 ++- .../playground/playground_server_helpers.rs | 25 ++- .../server/api/requests/execute_command.rs | 43 ++--- .../packages/vscode/src/extension.ts | 34 +++- .../vscode/src/panels/WebviewPanelHost.ts | 161 +++++++++++++++++- .../plugins/language-server-client/index.ts | 55 ++++++ 6 files changed, 309 insertions(+), 36 deletions(-) diff --git a/engine/language_server/src/playground/definitions.rs b/engine/language_server/src/playground/definitions.rs index 967b63ed80..a3f0c7e392 100644 --- a/engine/language_server/src/playground/definitions.rs +++ b/engine/language_server/src/playground/definitions.rs @@ -36,6 +36,8 @@ pub struct PlaygroundState { /// Buffer for events that occur before the first client connects. pub event_buffer: VecDeque, pub first_client_connected: bool, + /// Track the number of active connections + pub active_connections: usize, } impl Default for PlaygroundState { @@ -52,6 +54,7 @@ impl PlaygroundState { _rx: rx, event_buffer: VecDeque::new(), first_client_connected: false, + active_connections: 0, } } @@ -61,9 +64,9 @@ impl PlaygroundState { Ok(()) } - /// Push an event to the buffer if the first client hasn't connected yet. + /// Push an event to the buffer if no clients are connected. pub fn buffer_event(&mut self, event: String) { - if !self.first_client_connected { + if self.active_connections == 0 { self.event_buffer.push_back(event); } } @@ -73,8 +76,22 @@ impl PlaygroundState { self.event_buffer.drain(..).collect() } - /// Mark that the first client has connected. - pub fn mark_first_client_connected(&mut self) { - self.first_client_connected = true; + /// Mark that a client has connected. + pub fn mark_client_connected(&mut self) { + self.active_connections += 1; + if self.active_connections == 1 { + self.first_client_connected = true; + } + } + + /// Mark that a client has disconnected. + pub fn mark_client_disconnected(&mut self) { + if self.active_connections > 0 { + self.active_connections -= 1; + if self.active_connections == 0 { + self.first_client_connected = false; + tracing::info!("All clients disconnected, resetting connection state"); + } + } } } diff --git a/engine/language_server/src/playground/playground_server_helpers.rs b/engine/language_server/src/playground/playground_server_helpers.rs index 98a835cfcf..d26769b7d1 100644 --- a/engine/language_server/src/playground/playground_server_helpers.rs +++ b/engine/language_server/src/playground/playground_server_helpers.rs @@ -61,6 +61,12 @@ pub async fn start_client_connection( state.tx.subscribe() }; + // Mark client as connected + { + let mut st = state.write().await; + st.mark_client_connected(); + } + // Send initial project state using the helper send_all_projects_to_client(&mut ws_tx, &session).await; @@ -70,9 +76,10 @@ pub async fn start_client_connection( let buffered_events = st.drain_event_buffer(); for event in buffered_events.clone() { let _ = ws_tx.send(Message::text(event)).await; + // Add configurable delay between buffered events + tokio::time::sleep(tokio::time::Duration::from_millis(400)).await; } tracing::info!("Sent {} buffered events", buffered_events.len()); - st.mark_first_client_connected(); } // --- END BUFFERED EVENTS --- @@ -86,11 +93,17 @@ pub async fn start_client_connection( Ok(msg) => { if msg.is_close() { tracing::info!("Client disconnected"); + // Mark client as disconnected + let mut st = state.write().await; + st.mark_client_disconnected(); break; } } Err(e) => { tracing::error!("WebSocket error: {}", e); + // Mark client as disconnected on error + let mut st = state.write().await; + st.mark_client_disconnected(); break; } } @@ -99,10 +112,18 @@ pub async fn start_client_connection( Ok(msg) = rx.recv() => { if let Err(e) = ws_tx.send(Message::text(msg)).await { tracing::error!("Failed to send broadcast message: {}", e); + // Mark client as disconnected on send error + let mut st = state.write().await; + st.mark_client_disconnected(); break; } } - else => break, + else => { + // Mark client as disconnected when loop ends + let mut st = state.write().await; + st.mark_client_disconnected(); + break; + } } } }); diff --git a/engine/language_server/src/server/api/requests/execute_command.rs b/engine/language_server/src/server/api/requests/execute_command.rs index 7136a66e0c..434b57adc3 100644 --- a/engine/language_server/src/server/api/requests/execute_command.rs +++ b/engine/language_server/src/server/api/requests/execute_command.rs @@ -74,23 +74,30 @@ impl SyncRequestHandler for ExecuteCommand { } else if params.command == "baml.changeFunction" { // Logic for getting the function can be improved if let Some(state) = &session.playground_state { - if let Some(function_name) = params - .arguments - .first() - .and_then(|arg| arg.get("functionName")) - .and_then(|v| v.as_str().map(|s| s.to_string())) - { - tracing::info!("Broadcasting function change for: {}", function_name); - let state = state.clone(); - if let Some(runtime) = &session.playground_runtime { - runtime.spawn(async move { - let _ = crate::playground::broadcast_function_change( - &state, - &function_name.to_string(), - function_name, - ) - .await; - }); + if let Some(args) = params.arguments.first().and_then(|arg| arg.as_object()) { + if let (Some(function_name), Some(project_id)) = ( + args.get("functionName").and_then(|v| v.as_str()), + args.get("projectId").and_then(|v| v.as_str()), + ) { + tracing::info!( + "Broadcasting test run for function: {}", + function_name + ); + + // Set the selected function + let state_clone = state.clone(); + let func_name = function_name.to_string(); + let project_path = project_id.to_string(); + if let Some(runtime) = &session.playground_runtime { + runtime.spawn(async move { + let _ = crate::playground::broadcast_function_change( + &state_clone, + &project_path, + func_name, + ) + .await; + }); + } } } } @@ -130,8 +137,6 @@ impl SyncRequestHandler for ExecuteCommand { let test_name = test_case_name.to_string(); if let Some(runtime) = &session.playground_runtime { runtime.spawn(async move { - // TODO: temoporary fix to wait for function change to process - sleep(Duration::from_millis(1200)).await; let _ = crate::playground::broadcast_test_run(&state_clone, test_name) .await; diff --git a/typescript/vscode-ext/packages/vscode/src/extension.ts b/typescript/vscode-ext/packages/vscode/src/extension.ts index 547bc2360b..f1b1bf72ff 100644 --- a/typescript/vscode-ext/packages/vscode/src/extension.ts +++ b/typescript/vscode-ext/packages/vscode/src/extension.ts @@ -4,8 +4,8 @@ import axios from 'axios' import glooLens from './LanguageToBamlCodeLensProvider' import { WebviewPanelHost, openPlaygroundConfig } from './panels/WebviewPanelHost' import plugins from './plugins' -import { requestBamlCLIVersion, requestDiagnostics } from './plugins/language-server-client' -import { telemetry } from './plugins/language-server-client' +import { requestBamlCLIVersion, requestDiagnostics, getPlaygroundPort } from './plugins/language-server-client' +import { telemetry, viewFunctionInPlayground, runTestInPlayground } from './plugins/language-server-client' import cors from 'cors' import { createProxyMiddleware } from 'http-proxy-middleware' @@ -137,21 +137,31 @@ export function activate(context: vscode.ExtensionContext) { const bamlPlaygroundCommand = vscode.commands.registerCommand( 'baml.openBamlPanel', - (args?: { projectId?: string; functionName?: string; implName?: string; showTests?: boolean }) => { + async (args?: { projectId?: string; functionName?: string; implName?: string; showTests?: boolean }) => { const config = vscode.workspace.getConfiguration() config.update('baml.bamlPanelOpen', true, vscode.ConfigurationTarget.Global) - WebviewPanelHost.render(context.extensionUri, getPort, telemetry) + if (telemetry) { telemetry.sendTelemetryEvent({ event: 'baml.openBamlPanel', properties: {}, }) } - // sends project files as well to webview - requestDiagnostics() openPlaygroundConfig.lastOpenedFunction = args?.functionName ?? 'default' + + // Call the LSP to change function if a function name is provided + if (args?.functionName) { + try { + await viewFunctionInPlayground(args) + } catch (error) { + console.error('Failed to notify LSP of function change:', error) + // Continue execution even if LSP notification fails + } + } + + // Still send to the webview for immediate UI update WebviewPanelHost.currentPanel?.postMessage('select_function', { root_path: 'default', function_name: args?.functionName ?? 'default', @@ -163,7 +173,7 @@ export function activate(context: vscode.ExtensionContext) { const bamlTestcaseCommand = vscode.commands.registerCommand( 'baml.runBamlTest', - (args?: { + async (args?: { projectId: string functionName?: string implName?: string @@ -178,6 +188,16 @@ export function activate(context: vscode.ExtensionContext) { }) } + // Call the LSP to run test if test case name is provided + if (args?.testCaseName && args?.functionName && args?.projectId) { + try { + await runTestInPlayground(args) + } catch (error) { + console.error('Failed to notify LSP of test run:', error) + // Continue execution even if LSP notification fails + } + } + // sends project files as well to webview requestDiagnostics() diff --git a/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts b/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts index 8c72c4651b..c7427afb8f 100644 --- a/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts +++ b/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts @@ -19,7 +19,7 @@ import { import { type Config, adjectives, animals, colors, uniqueNamesGenerator } from 'unique-names-generator' import { URI } from 'vscode-uri' import { getCurrentOpenedFile } from '../helpers/get-open-file' -import { bamlConfig, requestDiagnostics } from '../plugins/language-server-client' +import { bamlConfig, requestDiagnostics, getPlaygroundPort } from '../plugins/language-server-client' import TelemetryReporter from '../telemetryReporter' import { exec, fork } from 'child_process' import { promisify } from 'util' @@ -78,8 +78,163 @@ export class WebviewPanelHost { // the panel or when the panel is closed programmatically) this._panel.onDidDispose(() => this.dispose(), null, this._disposables) - // Set the HTML content for the webview panel - this._panel.webview.html = this._getWebviewContent(this._panel.webview, extensionUri) + const playgroundPort = 3030 + if (playgroundPort) { + // Add 3 second delay for debugging + setTimeout(() => { + // Use the same CSP approach as SimpleBrowser + const nonce = getNonce() + + this._panel.webview.html = ` + + + + + + + + + +
+
+
+ BAML Playground (LSP Mode) +
+
Port: ${playgroundPort}
+
+
+
+

Connecting to Language Server Playground...

+

http://localhost:${playgroundPort}

+
+ +
+ + + + ` + }, 3000) // 3 second delay for debugging + + // Show loading message immediately + this._panel.webview.html = ` + + + + + +
+

🔧 LSP-Based BAML Playground

+

Starting Language Server Protocol connection...

+

Waiting 3 seconds for server to initialize (debug delay)

+

Target port: ${playgroundPort}

+
+ + ` + } else { + this._panel.webview.html = this._getWebviewContent(this._panel.webview, extensionUri) + } // Set an event listener to listen for messages passed from the webview context this._setWebviewMessageListener(this._panel.webview) diff --git a/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts b/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts index ec532dbbe7..36d3f6f467 100644 --- a/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts +++ b/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts @@ -38,6 +38,8 @@ let bamlOutputChannel: OutputChannel // Variable to store the path of the currently executing CLI let currentExecutingCliPath: string | null = null +let playgroundPort: number | null = null + const isDebugMode = () => process.env.VSCODE_DEBUG_MODE === 'true' const isE2ETestOnPullRequest = () => process.env.PRISMA_USE_LOCAL_LS === 'true' @@ -98,6 +100,50 @@ export const requestBamlCLIVersion = async (): Promise => { } } +export const viewFunctionInPlayground = async (args?: { + projectId?: string + functionName?: string + implName?: string + showTests?: boolean +}): Promise => { + if (!clientReady) { + console.warn('Client not ready for viewFunctionInPlayground request') + return + } + try { + console.log('Sending changeFunction command to LSP:', args) + await client.sendRequest('workspace/executeCommand', { + command: 'baml.changeFunction', + arguments: [args], + }) + } catch (e) { + console.error('Failed to change function in playground:', e) + throw e // Re-throw to let caller handle + } +} + +export const runTestInPlayground = async (args?: { + projectId?: string + functionName?: string + testCaseName?: string + [key: string]: any +}): Promise => { + if (!clientReady) { + console.warn('Client not ready for runTestInPlayground request') + return + } + try { + console.log('Sending runTest command to LSP:', args) + await client.sendRequest('workspace/executeCommand', { + command: 'baml.runTest', + arguments: [args], + }) + } catch (e) { + console.error('Failed to run test in playground:', e) + throw e // Re-throw to let caller handle + } +} + export const getBAMLFunctions = async (): Promise< { name: string @@ -166,6 +212,10 @@ const sleep = (time: number) => { }) } +export function getPlaygroundPort(): number | null { + return playgroundPort +} + export const registerClientEventHandlers = (client: LanguageClient, context: ExtensionContext) => { client.onNotification('baml/showLanguageServerOutput', () => { // need to append line for the show to work for some reason. @@ -293,6 +343,11 @@ export const registerClientEventHandlers = (client: LanguageClient, context: Ext client.onRequest('runtime_updated', handleRuntimeUpdated) client.onNotification('runtime_updated', handleRuntimeUpdated) + client.onNotification('baml/port', (params: { port: number }) => { + playgroundPort = params.port + console.log('Received playground port from LSP:', playgroundPort) + }) + // eslint-disable-next-line @typescript-eslint/no-misused-promises client.onNotification('baml_src_generator_version', async (payload: { version: string; root_path: string }) => { try { From d0c4ba3eed8cada51bbb11ef4f5494f7894ab4c7 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 25 Jun 2025 16:34:53 -0700 Subject: [PATCH 65/71] automatically wait and retrieve port + loading screen --- .../vscode/src/panels/WebviewPanelHost.ts | 456 ++++++++++++------ .../plugins/language-server-client/index.ts | 8 + 2 files changed, 307 insertions(+), 157 deletions(-) diff --git a/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts b/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts index c7427afb8f..3dd5e1af96 100644 --- a/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts +++ b/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts @@ -30,6 +30,12 @@ import { AwsCredentialIdentity } from '@smithy/types' import { refreshBamlConfigSingleton } from '../plugins/language-server-client/bamlConfig' import { GoogleAuth } from 'google-auth-library' // import { CredentialsProviderError } from '@aws-sdk/credential-providers' + +const packageJson = require('../../../package.json') // eslint-disable-line + +// Manual debug toggle - set to true for debug mode, false for production +const DEBUG_MODE = false + const customConfig: Config = { dictionaries: [adjectives, colors, animals], separator: '_', @@ -58,6 +64,14 @@ export class WebviewPanelHost { private readonly _panel: WebviewPanel private _disposables: Disposable[] = [] private _port: () => number + private _playgroundPort: number | null = null + + /** + * Gets the current playground port + */ + public get playgroundPort(): number | null { + return this._playgroundPort + } /** * The WebPanelView class private constructor (called only from the render method). @@ -78,168 +92,284 @@ export class WebviewPanelHost { // the panel or when the panel is closed programmatically) this._panel.onDidDispose(() => this.dispose(), null, this._disposables) - const playgroundPort = 3030 - if (playgroundPort) { - // Add 3 second delay for debugging - setTimeout(() => { - // Use the same CSP approach as SimpleBrowser - const nonce = getNonce() - - this._panel.webview.html = ` - - - - - - - - - -
-
-
- BAML Playground (LSP Mode) -
-
Port: ${playgroundPort}
-
-
-
-

Connecting to Language Server Playground...

-

http://localhost:${playgroundPort}

-
- -
- - - - ` - }, 3000) // 3 second delay for debugging - - // Show loading message immediately - this._panel.webview.html = ` - - - - - -
-

🔧 LSP-Based BAML Playground

-

Starting Language Server Protocol connection...

-

Waiting 3 seconds for server to initialize (debug delay)

-

Target port: ${playgroundPort}

-
- - ` - } else { - this._panel.webview.html = this._getWebviewContent(this._panel.webview, extensionUri) - } + // Show initial loading state + this._showLoadingState() // Set an event listener to listen for messages passed from the webview context this._setWebviewMessageListener(this._panel.webview) } + /** + * Updates the playground port and refreshes the webview + */ + public updatePlaygroundPort(port: number) { + console.log(`WebviewPanelHost: Updating playground port to ${port}`) + this._playgroundPort = port + this._updateWebviewContent() + } + + /** + * Shows the loading state while waiting for the LSP port + */ + private _showLoadingState() { + this._panel.webview.html = ` + + + + + +
+
+
BAML Playground
+
Waiting on Baml language server...
+ ${ + DEBUG_MODE + ? ` +
+
Debug Mode: Active
+
Waiting for LSP port notification
+
Extension Version: ${packageJson.version}
+
+ ` + : '' + } +
+ + ` + } + + /** + * Updates the webview content with the playground iframe + */ + private _updateWebviewContent() { + if (!this._playgroundPort) { + // Still waiting for port from LSP + return + } + + const nonce = getNonce() + + this._panel.webview.html = ` + + + + + + + + + +
+
+
+ BAML Playground (LSP Mode) +
+
Port: ${this._playgroundPort}
+
+
+
+

Connecting to playground...

+ ${ + DEBUG_MODE + ? ` +

http://localhost:${this._playgroundPort}

+
+
Debug Mode: Active
+
Connected to port: ${this._playgroundPort}
+
Extension Version: ${packageJson.version}
+
+ ` + : '' + } +
+ +
+ + + + ` + } + /** * Renders the current webview panel if it exists otherwise a new webview panel * will be created and displayed. @@ -250,6 +380,12 @@ export class WebviewPanelHost { if (WebviewPanelHost.currentPanel) { // If the webview panel already exists reveal it WebviewPanelHost.currentPanel._panel.reveal(ViewColumn.Beside) + + // Check if we have a port from LSP and update if needed + const currentPort = getPlaygroundPort() + if (currentPort && !WebviewPanelHost.currentPanel.playgroundPort) { + WebviewPanelHost.currentPanel.updatePlaygroundPort(currentPort) + } } else { // If a webview panel does not already exist create and show a new one const panel = window.createWebviewPanel( @@ -278,6 +414,12 @@ export class WebviewPanelHost { ) WebviewPanelHost.currentPanel = new WebviewPanelHost(panel, extensionUri, portLoader, reporter) + + // Check if we already have a port from LSP and update immediately + const currentPort = getPlaygroundPort() + if (currentPort) { + WebviewPanelHost.currentPanel.updatePlaygroundPort(currentPort) + } } } diff --git a/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts b/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts index 36d3f6f467..eb83e727a7 100644 --- a/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts +++ b/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts @@ -346,6 +346,14 @@ export const registerClientEventHandlers = (client: LanguageClient, context: Ext client.onNotification('baml/port', (params: { port: number }) => { playgroundPort = params.port console.log('Received playground port from LSP:', playgroundPort) + + // Update the webview panel if it exists + if (WebviewPanelHost.currentPanel) { + console.log('Updating existing webview panel with port:', playgroundPort) + WebviewPanelHost.currentPanel.updatePlaygroundPort(playgroundPort) + } else { + console.log('No webview panel exists yet, port will be used when panel is created') + } }) // eslint-disable-next-line @typescript-eslint/no-misused-promises From c848e6634d77acac02efcd46286a7086cc46c235 Mon Sep 17 00:00:00 2001 From: egol Date: Wed, 25 Jun 2025 16:54:44 -0700 Subject: [PATCH 66/71] remove vscode to webview communication --- .../packages/vscode/src/extension.ts | 40 +- .../vscode/src/panels/WebviewPanelHost.ts | 358 +----------------- .../plugins/language-server-client/index.ts | 7 +- 3 files changed, 12 insertions(+), 393 deletions(-) diff --git a/typescript/vscode-ext/packages/vscode/src/extension.ts b/typescript/vscode-ext/packages/vscode/src/extension.ts index f1b1bf72ff..ae0fb0bb83 100644 --- a/typescript/vscode-ext/packages/vscode/src/extension.ts +++ b/typescript/vscode-ext/packages/vscode/src/extension.ts @@ -2,12 +2,16 @@ import * as vscode from 'vscode' import axios from 'axios' import glooLens from './LanguageToBamlCodeLensProvider' -import { WebviewPanelHost, openPlaygroundConfig } from './panels/WebviewPanelHost' +import { WebviewPanelHost } from './panels/WebviewPanelHost' import plugins from './plugins' import { requestBamlCLIVersion, requestDiagnostics, getPlaygroundPort } from './plugins/language-server-client' import { telemetry, viewFunctionInPlayground, runTestInPlayground } from './plugins/language-server-client' import cors from 'cors' import { createProxyMiddleware } from 'http-proxy-middleware' +import { Socket } from 'net' +import { type Express } from 'express' +import StatusBarPanel from './panels/StatusBarPanel' +import TelemetryReporter from './telemetryReporter' const outputChannel = vscode.window.createOutputChannel('baml') const diagnosticsCollection = vscode.languages.createDiagnosticCollection('baml-diagnostics') @@ -20,10 +24,6 @@ let isGlowOn: boolean = true let animationTimer: NodeJS.Timeout | null = null let highlightRanges: vscode.Range[] = [] -import type { Express } from 'express' -import StatusBarPanel from './panels/StatusBarPanel' -import { Socket } from 'net' - export function activate(context: vscode.ExtensionContext) { console.log('BAML extension activating') @@ -39,9 +39,6 @@ export function activate(context: vscode.ExtensionContext) { app.use(cors()) const server = app.listen(0, () => { console.log('Server started on port ' + getPort()) - WebviewPanelHost.currentPanel?.postMessage('port_number', { - port: getPort(), - }) }) const getPort = () => { @@ -149,8 +146,6 @@ export function activate(context: vscode.ExtensionContext) { }) } - openPlaygroundConfig.lastOpenedFunction = args?.functionName ?? 'default' - // Call the LSP to change function if a function name is provided if (args?.functionName) { try { @@ -161,12 +156,6 @@ export function activate(context: vscode.ExtensionContext) { } } - // Still send to the webview for immediate UI update - WebviewPanelHost.currentPanel?.postMessage('select_function', { - root_path: 'default', - function_name: args?.functionName ?? 'default', - }) - console.info('Opening BAML panel') }, ) @@ -201,16 +190,6 @@ export function activate(context: vscode.ExtensionContext) { // sends project files as well to webview requestDiagnostics() - openPlaygroundConfig.lastOpenedFunction = args?.functionName ?? 'default' - WebviewPanelHost.currentPanel?.postMessage('select_function', { - root_path: 'default', - function_name: args?.functionName ?? 'default', - }) - - WebviewPanelHost.currentPanel?.postMessage('run_test', { - test_name: args?.testCaseName ?? 'default', - }) - console.info('Opening BAML panel') }, ) @@ -286,14 +265,7 @@ export function activate(context: vscode.ExtensionContext) { const text = editor.document.getText() // TODO: buggy when used with multiple functions, needs a fix. - WebviewPanelHost.currentPanel?.postMessage('update_cursor', { - cursor: { - fileName: name, - fileText: text, - line: position.line + 1, - column: position.character, - }, - }) + // Cursor position tracking removed since we're using iframe approach } } }) diff --git a/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts b/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts index 3dd5e1af96..ffcb1fb697 100644 --- a/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts +++ b/typescript/vscode-ext/packages/vscode/src/panels/WebviewPanelHost.ts @@ -1,54 +1,14 @@ -import type { StringSpan } from '@baml/common' -import { fromIni } from '@aws-sdk/credential-providers' // ES6 import import { type Disposable, Uri, ViewColumn, type Webview, type WebviewPanel, window, workspace } from 'vscode' import * as vscode from 'vscode' import { getNonce } from '../utils/getNonce' -import { getUri } from '../utils/getUri' -import { - EchoResponse, - GetBamlSrcResponse, - LoadEnvRequest, - GetPlaygroundPortResponse, - GetVSCodeSettingsResponse, - GetWebviewUriResponse, - WebviewToVscodeRpc, - encodeBuffer, - LoadEnvResponse, -} from '../vscode-rpc' - -import { type Config, adjectives, animals, colors, uniqueNamesGenerator } from 'unique-names-generator' -import { URI } from 'vscode-uri' -import { getCurrentOpenedFile } from '../helpers/get-open-file' -import { bamlConfig, requestDiagnostics, getPlaygroundPort } from '../plugins/language-server-client' +import { getPlaygroundPort } from '../plugins/language-server-client' import TelemetryReporter from '../telemetryReporter' -import { exec, fork } from 'child_process' -import { promisify } from 'util' -import { dirname, join } from 'path' -import * as dotenv from 'dotenv' -import * as fs from 'fs' -import { AwsCredentialIdentity } from '@smithy/types' -import { refreshBamlConfigSingleton } from '../plugins/language-server-client/bamlConfig' -import { GoogleAuth } from 'google-auth-library' -// import { CredentialsProviderError } from '@aws-sdk/credential-providers' const packageJson = require('../../../package.json') // eslint-disable-line // Manual debug toggle - set to true for debug mode, false for production const DEBUG_MODE = false -const customConfig: Config = { - dictionaries: [adjectives, colors, animals], - separator: '_', - length: 2, -} - -export const openPlaygroundConfig: { lastOpenedFunction: null | string } = { - lastOpenedFunction: null, -} - -const execAsync = promisify(exec) -const readFileAsync = promisify(fs.readFile) - /** * This class manages the state and behavior of HelloWorld webview panels. * @@ -94,9 +54,6 @@ export class WebviewPanelHost { // Show initial loading state this._showLoadingState() - - // Set an event listener to listen for messages passed from the webview context - this._setWebviewMessageListener(this._panel.webview) } /** @@ -423,328 +380,23 @@ export class WebviewPanelHost { } } - public postMessage(command: string, content: T) { - this._panel.webview.postMessage({ command: command, content }) - this.reporter?.sendTelemetryEvent({ - event: `baml.webview.${command}`, - properties: {}, - }) - } - /** * Cleans up and disposes of webview resources when the webview panel is closed. */ public dispose() { WebviewPanelHost.currentPanel = undefined - // Dispose of the current webview panel + // Clean up our resources this._panel.dispose() const config = workspace.getConfiguration() config.update('baml.bamlPanelOpen', false, true) - // Dispose of all disposables (i.e. commands) for the current webview panel while (this._disposables.length) { - const disposable = this._disposables.pop() - if (disposable) { - disposable.dispose() + const x = this._disposables.pop() + if (x) { + x.dispose() } } } - - /** - * Defines and returns the HTML that should be rendered within the webview panel. - * - * @remarks This is also the place where references to the React webview dist files - * are created and inserted into the webview HTML. - * - * @param webview A reference to the extension webview - * @param extensionUri The URI of the directory containing the extension - * @returns A template string literal containing the HTML that should be - * rendered within the webview panel - */ - private _getWebviewContent(webview: Webview, extensionUri: Uri) { - // The CSS file from the React dist output - const stylesUri = getUri(webview, extensionUri, ['web-panel', 'dist', 'assets', 'index.css']) - // The JS file from the React dist output - const scriptUri = getUri(webview, extensionUri, ['web-panel', 'dist', 'assets', 'index.js']) - - const nonce = getNonce() - - // Tip: Install the es6-string-html VS Code extension to enable code highlighting below - return /*html*/ ` - - - - - - - Hello World - - -
Waiting for react: ${scriptUri}
- - - ` - } - - /** - * Sets up an event listener to listen for messages passed from the webview context and - * executes code based on the message that is recieved. - * - * @param webview A reference to the extension webview - * @param context A reference to the extension context - */ - private _setWebviewMessageListener(webview: Webview) { - console.log('_setWebviewMessageListener') - - const addProject = async () => { - await requestDiagnostics() - console.log('last opened func', openPlaygroundConfig.lastOpenedFunction) - this.postMessage('select_function', { - root_path: 'default', - function_name: openPlaygroundConfig.lastOpenedFunction, - }) - this.postMessage('baml_cli_version', bamlConfig.cliVersion) - this.postMessage('baml_settings_updated', bamlConfig) - } - - vscode.workspace.onDidChangeConfiguration((event) => { - console.log('*** CLIENT DID CHANGE CONFIGURATION', event) - if (event.affectsConfiguration('baml')) { - setTimeout(() => { - this.postMessage('baml_settings_updated', refreshBamlConfigSingleton()) - }, 1000) - } - }) - - webview.onDidReceiveMessage( - async ( - message: - | { - command: 'get_port' | 'add_project' | 'cancelTestRun' | 'removeTest' - } - | { - command: 'set_flashing_regions' - content: { - spans: { - file_path: string - start_line: number - start_char: number - end_line: number - end_char: number - }[] - } - } - | { - command: 'jumpToFile' - span: StringSpan - } - | { - command: 'telemetry' - meta: { - action: string - data: Record - } - } - | { - rpcId: number - data: WebviewToVscodeRpc - }, - ) => { - console.log('DEBUG: webview message: ', message) - if ('command' in message) { - switch (message.command) { - case 'add_project': - console.log('webview add_project') - addProject() - - return - case 'jumpToFile': { - try { - console.log('jumpToFile', message.span) - const span = message.span - // span.source_file is a file:/// URI - - const uri = vscode.Uri.parse(span.source_file) - await vscode.workspace.openTextDocument(uri).then((doc) => { - const range = new vscode.Range(doc.positionAt(span.start), doc.positionAt(span.end)) - vscode.window.showTextDocument(doc, { selection: range, viewColumn: ViewColumn.One }) - }) - } catch (e: any) { - console.log(e) - } - return - } - case 'telemetry': { - const { action, data } = message.meta - this.reporter?.sendTelemetryEvent({ - event: `baml.webview.${action}`, - properties: data, - }) - return - } - case 'set_flashing_regions': { - // Call the command handler with the spans - console.log('WEBPANELVIEW set_flashing_regions', message.content.spans) - vscode.commands.executeCommand('baml.setFlashingRegions', { content: message.content }) - return - } - } - } - - if (!('rpcId' in message)) { - return - } - - // console.log('message from webview, after above handlers:', message) - const vscodeMessage = message.data - const vscodeCommand = vscodeMessage.vscodeCommand - - // TODO: implement error handling in our RPC framework - switch (vscodeCommand) { - case 'ECHO': - const echoresp: EchoResponse = { message: vscodeMessage.message } - // also respond with rpc id - this._panel.webview.postMessage({ rpcId: message.rpcId, rpcMethod: vscodeCommand, data: echoresp }) - return - case 'SET_PROXY_SETTINGS': - const { proxyEnabled } = vscodeMessage - const config = vscode.workspace.getConfiguration() - config.update('baml.enablePlaygroundProxy', proxyEnabled, vscode.ConfigurationTarget.Workspace) - return - case 'GET_WEBVIEW_URI': - console.log('GET_WEBVIEW_URI', vscodeMessage) - // This is 1:1 with the contents of `image.file` in a test file, e.g. given `image { file baml_src://path/to-image.png }`, - // relpath will be 'baml_src://path/to-image.png' - const relpath = vscodeMessage.path - - // NB(san): this is a violation of the "never URI.parse rule" - // (see https://www.notion.so/gloochat/windows-uri-treatment-fe87b22abebb4089945eb8cd1ad050ef) - // but this relpath is already a file URI, it seems... - const uriPath = Uri.parse(relpath) - const uri = this._panel.webview.asWebviewUri(uriPath).toString() - - console.log('GET_WEBVIEW_URI', { vscodeMessage, uri, parsed: uriPath }) - let webviewUriResp: GetWebviewUriResponse = { - uri, - } - if (vscodeMessage.contents) { - try { - const contents = await workspace.fs.readFile(uriPath) - webviewUriResp = { - ...webviewUriResp, - contents: encodeBuffer(contents), - } - } catch (e) { - webviewUriResp = { - ...webviewUriResp, - readError: `${e}`, - } - } - } - this._panel.webview.postMessage({ rpcId: message.rpcId, rpcMethod: vscodeCommand, data: webviewUriResp }) - return - case 'GET_PLAYGROUND_PORT': - console.log('GET_PLAYGROUND_PORT', this._port(), Date.now()) - const response: GetPlaygroundPortResponse = { - port: this._port(), - } - this._panel.webview.postMessage({ rpcId: message.rpcId, rpcMethod: vscodeCommand, data: response }) - return - case 'LOAD_AWS_CREDS': - ;(async () => { - try { - const profile = vscodeMessage.profile - const credentialProvider = fromIni({ - profile: profile ?? undefined, - }) - const awsCreds = await credentialProvider() - this._panel.webview.postMessage({ - rpcId: message.rpcId, - rpcMethod: vscodeCommand, - data: { ok: awsCreds }, - }) - } catch (error) { - console.error('Error loading aws creds:', error) - if (error instanceof Error) { - this._panel.webview.postMessage({ - rpcId: message.rpcId, - rpcMethod: vscodeCommand, - data: { - error: { - ...error, - name: error.name, - message: error.message, - }, - }, - }) - } else { - this._panel.webview.postMessage({ - rpcId: message.rpcId, - rpcMethod: vscodeCommand, - data: { error }, - }) - } - } - })() - return - case 'LOAD_GCP_CREDS': - ;(async () => { - try { - const auth = new GoogleAuth({ - scopes: ['https://www.googleapis.com/auth/cloud-platform'], - }) - - const client = await auth.getClient() - const projectId = await auth.getProjectId() - - const tokenResponse = await client.getAccessToken() - - this._panel.webview.postMessage({ - rpcId: message.rpcId, - rpcMethod: vscodeCommand, - data: { - ok: { - accessToken: tokenResponse.token, - projectId, - }, - }, - }) - } catch (error) { - console.error('Error loading gcp creds:', error) - if (error instanceof Error) { - this._panel.webview.postMessage({ - rpcId: message.rpcId, - rpcMethod: vscodeCommand, - data: { - error: { - ...error, - name: error.name, - message: error.message, - }, - }, - }) - } else { - this._panel.webview.postMessage({ - rpcId: message.rpcId, - rpcMethod: vscodeCommand, - data: { error }, - }) - } - } - })() - return - case 'INITIALIZED': // when the playground is initialized and listening for file changes, we should resend all project files. - // request diagnostics, which updates the runtime and triggers a new project files update. - addProject() - console.log('initialized webview') - this._panel.webview.postMessage({ rpcId: message.rpcId, rpcMethod: vscodeCommand, data: { ack: true } }) - return - } - }, - undefined, - this._disposables, - ) - } } diff --git a/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts b/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts index eb83e727a7..6b6f7c733e 100644 --- a/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts +++ b/typescript/vscode-ext/packages/vscode/src/plugins/language-server-client/index.ts @@ -313,7 +313,6 @@ export const registerClientEventHandlers = (client: LanguageClient, context: Ext console.log('Received baml_settings_updated from LSP:', config) BAML_CONFIG_SINGLETON.config = config.config BAML_CONFIG_SINGLETON.cliVersion = config.cliVersion - WebviewPanelHost.currentPanel?.postMessage('baml_settings_updated', BAML_CONFIG_SINGLETON) }) const handleRuntimeUpdated = (params: { root_path: string; files: Record }) => { @@ -324,11 +323,7 @@ export const registerClientEventHandlers = (client: LanguageClient, context: Ext const currentFilePath = URI.parse(activeEditor.document.uri.toString()).fsPath const rootPathUri = URI.file(params.root_path).fsPath if (currentFilePath.startsWith(rootPathUri)) { - console.log('Forwarding runtime_updated to WebviewPanelHost') - WebviewPanelHost.currentPanel?.postMessage('add_project', { - ...params, - root_path: URI.file(params.root_path).toString(), - }) + console.log('Runtime updated for active editor') } else { console.log('runtime_updated ignored: root path does not match active editor', currentFilePath, rootPathUri) } From 6abb18d01c0158f832c15bec7625d024d60e4220 Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 26 Jun 2025 09:24:49 -0700 Subject: [PATCH 67/71] improve naming --- .../language_server/scripts/{build.sh => install_dist.sh} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename engine/language_server/scripts/{build.sh => install_dist.sh} (83%) diff --git a/engine/language_server/scripts/build.sh b/engine/language_server/scripts/install_dist.sh similarity index 83% rename from engine/language_server/scripts/build.sh rename to engine/language_server/scripts/install_dist.sh index 52d874b319..29ff5ba222 100755 --- a/engine/language_server/scripts/build.sh +++ b/engine/language_server/scripts/install_dist.sh @@ -1,8 +1,8 @@ #!/bin/bash -# This script is needed as the language_server embeds the web-panel dist -# directory in the playground_server.rs file. It builds all of the dependencies -# for it as well as the web-panel itself. +# This script installs dependencies for the frontend and builds it so that it +# appears under dist. This is needed as playground_server_helpers.rs embeds the dist +# directory. # Exit on error set -e From 287a383bd7bef30c84c85cd0fed80568962acc48 Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 26 Jun 2025 09:25:25 -0700 Subject: [PATCH 68/71] improve comment for directory embed --- .../src/playground/playground_server_helpers.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engine/language_server/src/playground/playground_server_helpers.rs b/engine/language_server/src/playground/playground_server_helpers.rs index d26769b7d1..21d5ca4058 100644 --- a/engine/language_server/src/playground/playground_server_helpers.rs +++ b/engine/language_server/src/playground/playground_server_helpers.rs @@ -13,8 +13,10 @@ use crate::{ }; /// Embed at compile time everything in dist/ -// WARNING: this is a relative path, will easily break if file structure changes -// WARNING: works as a macro so any build script executes after this is evaluated +/// NOTE: If this line is throwing an ERROR then the script in language_server/scripts/install.sh +/// needs to be ran. +/// WARNING: this is a relative path, will easily break if file structure changes +/// WARNING: works as a macro so any build script executes after this is evaluated static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../typescript/vscode-ext/packages/web-panel/dist"); From 965d2e64ca6e991f4fb8af799eefe20a3647ea5c Mon Sep 17 00:00:00 2001 From: egol Date: Thu, 26 Jun 2025 14:39:48 -0700 Subject: [PATCH 69/71] allow language server to serve files to frontend via existing VS Code URI --- engine/Cargo.lock | 1 + .../baml-schema-wasm/src/runtime_wasm/mod.rs | 3 +- engine/language_server/Cargo.toml | 1 + .../{install_dist.sh => build_dist.sh} | 0 engine/language_server/src/playground/mod.rs | 1 + .../playground/playground_server_helpers.rs | 31 +++++- .../src/playground/playground_server_rpc.rs | 104 ++++++++++++++++++ .../src/baml_wasm_web/EventListener.tsx | 19 +--- .../playground-panel/atoms.ts | 7 -- .../prompt-preview/media-utils.ts | 82 +++++--------- .../prompt-preview/webview-media.tsx | 14 +-- .../playground-panel/side-bar/index.tsx | 2 +- .../src/shared/baml-project-panel/vscode.ts | 98 +++++++---------- 13 files changed, 213 insertions(+), 150 deletions(-) rename engine/language_server/scripts/{install_dist.sh => build_dist.sh} (100%) create mode 100644 engine/language_server/src/playground/playground_server_rpc.rs diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 432fbad736..3a78651ef9 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -3895,6 +3895,7 @@ dependencies = [ "baml-lsp-types", "baml-runtime", "baml-types", + "base64 0.21.7", "colored 3.0.0", "crossbeam", "crossbeam-channel", diff --git a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs index baae960d9b..7214bb45a9 100644 --- a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs +++ b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs @@ -54,7 +54,8 @@ pub fn on_wasm_init() { if #[cfg(debug_assertions)] { const LOG_LEVEL: log::Level = log::Level::Debug; } else { - const LOG_LEVEL: log::Level = log::Level::Info; + // TODO uncomment this + const LOG_LEVEL: log::Level = log::Level::Debug; } }; // I dont think we need this line anymore -- seems to break logging if you add it. diff --git a/engine/language_server/Cargo.toml b/engine/language_server/Cargo.toml index 0c515fa010..9ff54f244c 100644 --- a/engine/language_server/Cargo.toml +++ b/engine/language_server/Cargo.toml @@ -76,6 +76,7 @@ warp = "0.3" futures-util = "0.3" include_dir = "0.7" mime_guess = "2.0.4" +base64 = "0.21" webbrowser = "0.8" diff --git a/engine/language_server/scripts/install_dist.sh b/engine/language_server/scripts/build_dist.sh similarity index 100% rename from engine/language_server/scripts/install_dist.sh rename to engine/language_server/scripts/build_dist.sh diff --git a/engine/language_server/src/playground/mod.rs b/engine/language_server/src/playground/mod.rs index df48ad8a75..f0ed9b6045 100644 --- a/engine/language_server/src/playground/mod.rs +++ b/engine/language_server/src/playground/mod.rs @@ -1,6 +1,7 @@ pub mod definitions; pub mod playground_server; pub mod playground_server_helpers; +pub mod playground_server_rpc; pub use definitions::{FrontendMessage, PlaygroundState}; pub use playground_server::PlaygroundServer; diff --git a/engine/language_server/src/playground/playground_server_helpers.rs b/engine/language_server/src/playground/playground_server_helpers.rs index 21d5ca4058..afd2e0cc5a 100644 --- a/engine/language_server/src/playground/playground_server_helpers.rs +++ b/engine/language_server/src/playground/playground_server_helpers.rs @@ -6,10 +6,14 @@ use include_dir::{include_dir, Dir}; use mime_guess::from_path; use tokio::sync::RwLock; use warp::{http::Response, ws::Message, Filter}; +use serde_json::Value; +use base64::engine::general_purpose; +use base64::Engine as _; use crate::{ playground::definitions::{FrontendMessage, PlaygroundState}, session::Session, + playground::playground_server_rpc::handle_rpc_websocket, }; /// Embed at compile time everything in dist/ @@ -138,15 +142,32 @@ pub fn create_server_routes( session: Arc, ) -> impl Filter + Clone { // WebSocket handler with error handling + let ws_state = state.clone(); + let ws_session = session.clone(); let ws_route = warp::path("ws") .and(warp::ws()) .map(move |ws: warp::ws::Ws| { - let state = state.clone(); - let session = session.clone(); + let state = ws_state.clone(); + let session = ws_session.clone(); ws.on_upgrade(move |socket| async move { start_client_connection(socket, state, session).await; }) }); + + tracing::info!("Setting up RPC websocket..."); + // RPC WebSocket handler + let rpc_session = session.clone(); + let rpc_route = warp::path("rpc") + .and(warp::ws()) + .map(move |ws: warp::ws::Ws| { + let session = rpc_session.clone(); + ws.on_upgrade(move |socket| async move { + handle_rpc_websocket(socket, session).await; + }) + }); + + // Static file serving for user files (e.g., images, data) + let static_files = warp::path("static").and(warp::fs::dir(".")); // Static file serving needed to serve the frontend files let spa = @@ -171,7 +192,11 @@ pub fn create_server_routes( } }); - ws_route.or(spa).with(warp::log("playground-server")) + ws_route + .or(rpc_route) + .or(static_files) + .or(spa) + .with(warp::log("playground-server")) } // Helper function to broadcast project updates with better error handling diff --git a/engine/language_server/src/playground/playground_server_rpc.rs b/engine/language_server/src/playground/playground_server_rpc.rs new file mode 100644 index 0000000000..7b9ca5cbe6 --- /dev/null +++ b/engine/language_server/src/playground/playground_server_rpc.rs @@ -0,0 +1,104 @@ +use std::sync::Arc; + +use serde_json::Value; +use warp::ws::{Message, WebSocket}; + +use crate::session::Session; +use crate::playground::definitions::PlaygroundState; + +use base64::engine::general_purpose; +use base64::Engine as _; +use futures_util::{StreamExt, SinkExt}; +use mime_guess::from_path; + +/// Handles all playground RPC commands over the WebSocket connection. +pub async fn handle_rpc_websocket(ws: WebSocket, session: Arc) { + let (mut ws_tx, mut ws_rx) = ws.split(); + while let Some(Ok(msg)) = ws_rx.next().await { + if msg.is_text() { + if let Ok(json) = serde_json::from_str::(msg.to_str().unwrap()) { + let rpc_id = json["rpcId"].clone(); + let rpc_method = json["rpcMethod"].as_str().unwrap_or(""); + let data = &json["data"]; + // tracing::info!("Handling RPC request!"); + // tracing::info!("RPC METHOD: {:?}", rpc_method); + match rpc_method { + "INITIALIZED" => { + let response = serde_json::json!({ + "rpcMethod": "INITIALIZED", + "rpcId": rpc_id, + "data": { "ok": true } + }); + let _ = ws_tx.send(Message::text(response.to_string())).await; + } + "GET_WEBVIEW_URI" => { + let path = data["path"].as_str().unwrap_or(""); + let port = session.baml_settings.playground_port.unwrap_or(3030); + + // Convert absolute path to relative path for /static/ URI + let rel_path = std::env::current_dir() + .ok() + .and_then(|cwd| std::path::Path::new(path).strip_prefix(&cwd).ok()) + .map(|p| p.to_string_lossy().replace('\\', "/")) + .unwrap_or_else(|| path.to_string()); + + let uri = format!("http://localhost:{}/static/{}", port, rel_path); + let mut response_data = serde_json::json!({ "uri": uri }); + + // For non-image files, include contents as base64 + let mime = from_path(path).first_or_octet_stream(); + if !mime.type_().as_str().eq("image") { + if let Ok(contents) = std::fs::read(path) { + let base64 = general_purpose::STANDARD.encode(&contents); + response_data["contents"] = serde_json::Value::String(base64); + } + } + + let response = serde_json::json!({ + "rpcMethod": "GET_WEBVIEW_URI", + "rpcId": rpc_id, + "data": response_data + }); + let _ = ws_tx.send(Message::text(response.to_string())).await; + } + "GET_PLAYGROUND_PORT" => { + let port = session.baml_settings.playground_port.unwrap_or(3030); + let response = serde_json::json!({ + "rpcMethod": "GET_PLAYGROUND_PORT", + "rpcId": rpc_id, + "data": { "port": port } + }); + let _ = ws_tx.send(Message::text(response.to_string())).await; + } + "SET_PROXY_SETTINGS" => { + let response = serde_json::json!({ + "rpcMethod": "SET_PROXY_SETTINGS", + "rpcId": rpc_id, + "data": { "ok": true } + }); + let _ = ws_tx.send(Message::text(response.to_string())).await; + } + "LOAD_AWS_CREDS" => { + let response = serde_json::json!({ + "rpcMethod": "LOAD_AWS_CREDS", + "rpcId": rpc_id, + "data": { "ok": true } + }); + let _ = ws_tx.send(Message::text(response.to_string())).await; + } + "LOAD_GCP_CREDS" => { + let response = serde_json::json!({ + "rpcMethod": "LOAD_GCP_CREDS", + "rpcId": rpc_id, + "data": { "ok": true } + }); + let _ = ws_tx.send(Message::text(response.to_string())).await; + } + _ => { + tracing::warn!("Unknown RPC method: {}", rpc_method); + } + } + } + } + } +} \ No newline at end of file diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index c55787d017..918e979b85 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -83,7 +83,7 @@ export const isConnectedAtom = atom(true) const ConnectionStatus: React.FC = () => { const isConnected = useAtomValue(isConnectedAtom) - if (isConnected || vscode.isVscode()) return null + if (isConnected) return null return (
@@ -108,7 +108,6 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre const debouncedSetFiles = useDebounceCallback(setFiles, 50, true) const setFlashRanges = useSetAtom(flashRangesAtom) const setIsConnected = useSetAtom(isConnectedAtom) - const isVSCodeWebview = vscode.isVscode() const [selectedFunc, setSelectedFunction] = useAtom(selectedFunctionAtom) const setSelectedTestcase = useSetAtom(selectedTestcaseAtom) @@ -138,12 +137,6 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre // console.log('selectedFunc', selectedFunc) useEffect(() => { - // Only open websocket if not in VSCode webview - if (isVSCodeWebview) { - setIsConnected(true) - // return - } - const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' const ws = new WebSocket(`${scheme}://${window.location.host}/ws`) @@ -170,15 +163,9 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre } return () => ws.close() - }, [setIsConnected, isVSCodeWebview]) + }, [setIsConnected]) useEffect(() => { - // Only open websocket if not in VSCode webview - if (isVSCodeWebview) { - setIsConnected(true) - // return - } - const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' const ws = new WebSocket(`${scheme}://${window.location.host}/ws`) @@ -205,7 +192,7 @@ export const EventListener: React.FC<{ children: React.ReactNode }> = ({ childre } return () => ws.close() - }, [setIsConnected, isVSCodeWebview]) + }, [setIsConnected]) console.log('Websocket execution finished') diff --git a/typescript/playground-common/src/shared/baml-project-panel/playground-panel/atoms.ts b/typescript/playground-common/src/shared/baml-project-panel/playground-panel/atoms.ts index b15e8719f2..5d93fcb4bc 100644 --- a/typescript/playground-common/src/shared/baml-project-panel/playground-panel/atoms.ts +++ b/typescript/playground-common/src/shared/baml-project-panel/playground-panel/atoms.ts @@ -148,11 +148,6 @@ export const showEnvDialogAtom = atom( const hasShownDialog = get(hasShownEnvDialogAtom) if (hasShownDialog) return envDialogOpen - // if we are in vscode, we don't want to show the dialog - if (!vscode.isVscode()) { - return false - } - return hasMissingVars }, (get, set, value: boolean) => { @@ -165,8 +160,6 @@ export const showEnvDialogAtom = atom( export const areEnvVarsMissingAtom = atom((get) => { const requiredVars = get(requiredEnvVarsAtom) - const isVscode = vscode.isVscode() - if (!isVscode) return false const envVars = get(envVarsAtom) return requiredVars.length > 0 && requiredVars.every((key) => !envVars[key]) }) diff --git a/typescript/playground-common/src/shared/baml-project-panel/playground-panel/prompt-preview/media-utils.ts b/typescript/playground-common/src/shared/baml-project-panel/playground-panel/prompt-preview/media-utils.ts index bd089a9fa1..490eb80265 100644 --- a/typescript/playground-common/src/shared/baml-project-panel/playground-panel/prompt-preview/media-utils.ts +++ b/typescript/playground-common/src/shared/baml-project-panel/playground-panel/prompt-preview/media-utils.ts @@ -1,59 +1,31 @@ import { vscode } from '../../vscode' export const findMediaFile = async (path: string): Promise => { - // Helper to hash the path to ensure the same path generates the same data - // const hashPath = (str: string): number => { - // let hash = 0; - // for (let i = 0; i < str.length; i++) { - // hash = (hash << 5) - hash + str.charCodeAt(i); - // hash |= 0; - // } - // return Math.abs(hash); - // }; - - // // Helper to generate a dummy image in JPEG/PNG format with text - // const generateRandomImage = async ( - // type: 'image/jpeg' | 'image/png', - // width: number, - // height: number, - // text: string - // ): Promise => { - // const canvas = new OffscreenCanvas(width, height); - // const ctx = canvas.getContext('2d'); - // if (ctx) { - // const colorSeed = hashPath(text); - // ctx.fillStyle = `#${((colorSeed & 0xFFFFFF) | 0x1000000).toString(16).slice(1)}`; - // ctx.fillRect(0, 0, width, height); - - // ctx.fillStyle = '#FFFFFF'; - // ctx.font = '16px Arial'; - // ctx.fillText(`Placeholder: ${type}`, 10, 50); - // ctx.fillText(path, 10, 70); - // } - // const blob = await canvas.convertToBlob({ type }); - // return new Uint8Array(await blob.arrayBuffer()); - // }; - - // const generateRandomAudio = (path: string): Uint8Array => { - // const audioLength = 1 * 1024 * 1024; - // const randomAudioData = new Uint8Array(audioLength); - // const seed = hashPath(path); - // for (let i = 0; i < audioLength; i++) { - // randomAudioData[i] = (seed + i) % 256; - // } - // return randomAudioData; - // }; - - // const extension = path.split('.').pop()?.toLowerCase(); - // if (extension === 'jpeg' || extension === 'jpg') { - // return await generateRandomImage('image/jpeg', 200, 100, `Dummy JPEG:\n${path}`); - // } else if (extension === 'png') { - // return await generateRandomImage('image/png', 200, 100, `Dummy PNG:\n${path}`); - // } else if (extension === 'mp3') { - // return generateRandomAudio(path); - // } - - return await vscode.readFile(path) - - // throw new Error(`Unknown file extension: ${extension}`); + // Try to get the URI from the backend + const resp = await vscode.readLocalFile('', path) + if (resp.uri) { + // Fetch the file from the URI if provided + const res = await fetch(resp.uri) + if (!res.ok) { + throw new Error(`Failed to fetch file from URI: ${resp.uri}`) + } + const buffer = await res.arrayBuffer() + return new Uint8Array(buffer) + } + if (resp.readError) { + throw new Error(`Failed to read file: ${path}\n${resp.readError}`) + } + if (resp.contents) { + // Fallback: decode base64 contents + const contents = resp.contents + // Use atob to decode base64 to binary string, then to Uint8Array + const binary = atob(contents) + const len = binary.length + const bytes = new Uint8Array(len) + for (let i = 0; i < len; i++) { + bytes[i] = binary.charCodeAt(i) + } + return bytes + } + throw new Error(`Unknown error: '${path}'`) } diff --git a/typescript/playground-common/src/shared/baml-project-panel/playground-panel/prompt-preview/webview-media.tsx b/typescript/playground-common/src/shared/baml-project-panel/playground-panel/prompt-preview/webview-media.tsx index 08f4b8c12f..14663e161a 100644 --- a/typescript/playground-common/src/shared/baml-project-panel/playground-panel/prompt-preview/webview-media.tsx +++ b/typescript/playground-common/src/shared/baml-project-panel/playground-panel/prompt-preview/webview-media.tsx @@ -33,7 +33,7 @@ export const WebviewMedia: React.FC = ({ bamlMediaType, media switch (media.type) { case wasm.WasmChatMessagePartMediaType.File: - return `${media.content}` + return media.content case wasm.WasmChatMessagePartMediaType.Url: return media.content case wasm.WasmChatMessagePartMediaType.Error: @@ -64,16 +64,8 @@ export const WebviewMedia: React.FC = ({ bamlMediaType, media const img = e.currentTarget const { naturalWidth, naturalHeight } = img let size = 'Unknown' - if (mediaUrl?.startsWith('data:')) { - const base64Length = mediaUrl.split(',')[1]?.length - const sizeInBytes = base64Length ? base64Length * 0.75 : 0 - size = - sizeInBytes > 1048576 ? `${(sizeInBytes / 1048576).toFixed(2)} MB` : `${(sizeInBytes / 1024).toFixed(2)} KB` - } else { - const sizeInBytes = naturalWidth * naturalHeight * 4 - size = - sizeInBytes > 1048576 ? `${(sizeInBytes / 1048576).toFixed(2)} MB` : `${(sizeInBytes / 1024).toFixed(2)} KB` - } + const sizeInBytes = naturalWidth * naturalHeight * 4 + size = sizeInBytes > 1048576 ? `${(sizeInBytes / 1048576).toFixed(2)} MB` : `${(sizeInBytes / 1024).toFixed(2)} KB` setImageStats({ width: naturalWidth, height: naturalHeight, size }) } diff --git a/typescript/playground-common/src/shared/baml-project-panel/playground-panel/side-bar/index.tsx b/typescript/playground-common/src/shared/baml-project-panel/playground-panel/side-bar/index.tsx index 107550732b..7aad6a923b 100644 --- a/typescript/playground-common/src/shared/baml-project-panel/playground-panel/side-bar/index.tsx +++ b/typescript/playground-common/src/shared/baml-project-panel/playground-panel/side-bar/index.tsx @@ -53,7 +53,7 @@ const functionsAreStaleAtom = atom((get) => { const isEmbed = typeof window !== 'undefined' && window.location.href.includes('embed') -export const isSidebarOpenAtom = atomWithStorage('isSidebarOpen', isEmbed ? false : vscode.isVscode() ? true : false) +export const isSidebarOpenAtom = atomWithStorage('isSidebarOpen', isEmbed ? true : false) export default function CustomSidebar({ isEmbed = false }: { isEmbed?: boolean }) { const functions = useAtomValue(functionsAtom) diff --git a/typescript/playground-common/src/shared/baml-project-panel/vscode.ts b/typescript/playground-common/src/shared/baml-project-panel/vscode.ts index 142a3883b6..76ced42631 100644 --- a/typescript/playground-common/src/shared/baml-project-panel/vscode.ts +++ b/typescript/playground-common/src/shared/baml-project-panel/vscode.ts @@ -44,27 +44,49 @@ const isRpcResponse = (eventData: unknown): eventData is RpcResponse => { * enabled by acquireVsCodeApi. */ class VSCodeAPIWrapper { - private readonly vsCodeApi: WebviewApi | undefined - + private ws: WebSocket | undefined + private wsReady: Promise | undefined + private wsReadyResolve: (() => void) | undefined private rpcTable: Map void }> private rpcId: number + public isConnected: boolean = false + public onOpen?: () => void constructor() { - // Check if the acquireVsCodeApi function exists in the current development - // context (i.e. VS Code development window or web browser) - if (typeof acquireVsCodeApi === 'function' && typeof window !== 'undefined') { - this.vsCodeApi = acquireVsCodeApi() - window.addEventListener('message', this.listenForRpcResponses.bind(this)) + if (typeof window !== 'undefined') { + // Use robust WebSocket setup like EventListener + const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws' + const host = window.location.host + const url = `${scheme}://${host}/rpc` + this.wsReady = new Promise((resolve) => (this.wsReadyResolve = resolve)) + this.ws = new WebSocket(url) + this.ws.onopen = () => { + console.log('RPC WebSocket Opened') + this.isConnected = true + this.wsReadyResolve?.() + if (this.onOpen) this.onOpen() + } + this.ws.onclose = () => { + console.log('RPC WebSocket Closed') + this.isConnected = false + } + this.ws.onerror = (e) => { + console.error('RPC WebSocket error', e) + this.isConnected = false + } + this.ws.onmessage = (event) => { + console.log('RPC WebSocket message received:', event.data) + let data = event.data + try { + data = JSON.parse(event.data) + } catch {} + this.listenForRpcResponses({ data }) + } } - this.rpcTable = new Map() this.rpcId = 0 } - public isVscode() { - return this.vsCodeApi !== undefined - } - public async readFile(path: string): Promise { const uri = await this.readLocalFile('', path) @@ -73,7 +95,6 @@ class VSCodeAPIWrapper { } if (uri.contents) { const contents = uri.contents - // throw new Error(`not implemented: ${Array.isArray(contents)}: \n ${JSON.stringify(contents)}`) return decodeBuffer(contents) } @@ -173,57 +194,22 @@ class VSCodeAPIWrapper { } } - /** - * Post a message (i.e. send arbitrary data) to the owner of the webview. - * - * @remarks When running webview code inside a web browser, postMessage will instead - * log the given message to the console. - * - * @param message Abitrary data (must be JSON serializable) to send to the extension context. - */ public postMessage(message: unknown) { - if (this.vsCodeApi) { - this.vsCodeApi.postMessage(message) - } else { - window.postMessage(message) + if (this.ws && this.ws.readyState === WebSocket.OPEN) { + this.ws.send(JSON.stringify(message)) + } else if (this.ws && this.wsReady) { + this.wsReady.then(() => this.ws!.send(JSON.stringify(message))) } } - /** - * Get the persistent state stored for this webview. - * - * @remarks When running webview source code inside a web browser, getState will retrieve state - * from local storage (https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). - * - * @return The current state or `undefined` if no state has been set. - */ public getState(): unknown | undefined { - if (this.vsCodeApi) { - return this.vsCodeApi.getState() - } else { - const state = localStorage.getItem('vscodeState') - return state ? JSON.parse(state) : undefined - } + const state = localStorage.getItem('vscodeState') + return state ? JSON.parse(state) : undefined } - /** - * Set the persistent state stored for this webview. - * - * @remarks When running webview source code inside a web browser, setState will set the given - * state using local storage (https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). - * - * @param newState New persisted state. This must be a JSON serializable object. Can be retrieved - * using {@link getState}. - * - * @return The new state. - */ public setState(newState: T): T { - if (this.vsCodeApi) { - return this.vsCodeApi.setState(newState) - } else { - localStorage.setItem('vscodeState', JSON.stringify(newState)) - return newState - } + localStorage.setItem('vscodeState', JSON.stringify(newState)) + return newState } } From 08798c4c883d31466dd148f47ce93c725bb820a6 Mon Sep 17 00:00:00 2001 From: egol Date: Fri, 27 Jun 2025 10:02:53 -0700 Subject: [PATCH 70/71] working proxy --- engine/Cargo.lock | 117 +++- engine/language_server/Cargo.toml | 3 + .../language_server/src/baml_project/mod.rs | 26 +- engine/language_server/src/playground/mod.rs | 1 + .../src/playground/playground_server.rs | 19 +- .../src/playground/playground_server_rpc.rs | 4 +- .../language_server/src/playground/proxy.rs | 295 +++++++++++ engine/language_server/src/server/api.rs | 18 +- .../src/shared/baml-project-panel/atoms.ts | 5 +- typescript/pnpm-lock.yaml | 499 +----------------- .../vscode-ext/packages/vscode/package.json | 7 - .../packages/vscode/src/extension.ts | 105 +--- 12 files changed, 459 insertions(+), 640 deletions(-) create mode 100644 engine/language_server/src/playground/proxy.rs diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 3a78651ef9..8f3e6f328b 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -761,7 +761,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", "tower", "tower-layer", @@ -784,7 +784,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", "tracing", @@ -894,7 +894,7 @@ dependencies = [ "pathdiff 0.1.0", "pretty_assertions", "rand", - "reqwest", + "reqwest 0.12.12", "rstest", "scopeguard", "serde", @@ -1154,7 +1154,7 @@ dependencies = [ "pin-project-lite", "pretty_assertions", "regex", - "reqwest", + "reqwest 0.12.12", "reqwest-eventsource", "ring", "rstest", @@ -1222,7 +1222,7 @@ dependencies = [ "jsonish", "log", "once_cell", - "reqwest", + "reqwest 0.12.12", "serde", "serde-wasm-bindgen 0.6.5", "serde_json", @@ -3129,6 +3129,19 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -3896,11 +3909,13 @@ dependencies = [ "baml-runtime", "baml-types", "base64 0.21.7", + "bytes", "colored 3.0.0", "crossbeam", "crossbeam-channel", "filetime", "futures-util", + "http 0.2.12", "ignore", "include_dir", "indexmap 2.9.0", @@ -3920,6 +3935,7 @@ dependencies = [ "path-absolutize", "pathdiff 0.2.3", "regex", + "reqwest 0.11.27", "rustc-hash 2.1.1", "schemars 0.8.22", "semver", @@ -5328,6 +5344,46 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-tls 0.5.0", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "reqwest" version = "0.12.12" @@ -5345,7 +5401,7 @@ dependencies = [ "http-body-util", "hyper 1.6.0", "hyper-rustls 0.27.7", - "hyper-tls", + "hyper-tls 0.6.0", "hyper-util", "ipnet", "js-sys", @@ -5359,8 +5415,8 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", - "system-configuration", + "sync_wrapper 1.0.2", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-util", @@ -5386,7 +5442,7 @@ dependencies = [ "mime", "nom", "pin-project-lite", - "reqwest", + "reqwest 0.12.12", "thiserror 1.0.69", ] @@ -5641,7 +5697,7 @@ dependencies = [ "baml-types", "env_logger", "log", - "reqwest", + "reqwest 0.12.12", "serde_json", "tokio", "tracing", @@ -6252,6 +6308,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -6272,6 +6334,17 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys 0.5.0", +] + [[package]] name = "system-configuration" version = "0.6.1" @@ -6280,7 +6353,17 @@ checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.9.1", "core-foundation 0.9.4", - "system-configuration-sys", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -6654,7 +6737,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", "tower-layer", "tower-service", @@ -7740,6 +7823,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "winsafe" version = "0.0.19" diff --git a/engine/language_server/Cargo.toml b/engine/language_server/Cargo.toml index 9ff54f244c..57881929d9 100644 --- a/engine/language_server/Cargo.toml +++ b/engine/language_server/Cargo.toml @@ -77,6 +77,9 @@ futures-util = "0.3" include_dir = "0.7" mime_guess = "2.0.4" base64 = "0.21" +reqwest = { version = "0.11", features = ["json"] } +http = "0.2" +bytes = "1.0" webbrowser = "0.8" diff --git a/engine/language_server/src/baml_project/mod.rs b/engine/language_server/src/baml_project/mod.rs index c1969ba069..f55f3b572a 100644 --- a/engine/language_server/src/baml_project/mod.rs +++ b/engine/language_server/src/baml_project/mod.rs @@ -63,7 +63,7 @@ pub struct BamlProject { impl Drop for BamlProject { fn drop(&mut self) { - tracing::info!("Dropping BamlProject"); + tracing::debug!("Dropping BamlProject"); } } @@ -83,7 +83,7 @@ impl std::fmt::Debug for BamlProject { impl BamlProject { pub fn new(root_dir: PathBuf) -> Self { - tracing::info!("Creating BamlProject for {}", root_dir.display()); + tracing::debug!("Creating BamlProject for {}", root_dir.display()); Self { root_dir_name: root_dir, files: HashMap::new(), @@ -172,7 +172,7 @@ impl BamlProject { let generated = match runtime.run_codegen(&all_files, no_version_check.unwrap_or(false)) { Ok(gen) => { let elapsed = start_time.elapsed(); - tracing::info!( + tracing::debug!( "Generated {:?} baml_clients in {:?}ms", gen.len(), elapsed.as_millis() @@ -181,7 +181,7 @@ impl BamlProject { } Err(e) => { let elapsed = start_time.elapsed(); - tracing::info!( + tracing::debug!( "Failed to run codegen in {:?}ms: {:?}", elapsed.as_millis(), e @@ -192,11 +192,11 @@ impl BamlProject { }; match generated.len() { - 1 => tracing::info!( + 1 => tracing::debug!( "Generated 1 baml_client: {}", generated[0].output_dir_full.display() ), - n => tracing::info!( + n => tracing::debug!( "Generated {n} baml_clients: {}", generated .iter() @@ -209,7 +209,7 @@ impl BamlProject { } pub fn set_unsaved_file(&mut self, document_key: &DocumentKey, content: Option) { - tracing::info!( + tracing::debug!( "Setting unsaved file: {}, {}", document_key.path().display(), content.clone().unwrap_or("None".to_string()) @@ -228,7 +228,7 @@ impl BamlProject { self.cached_runtime = None; } pub fn save_file(&mut self, document_key: &DocumentKey, content: &str) { - tracing::info!( + tracing::debug!( "Saving file: {}, {}", document_key.path().display(), content @@ -240,7 +240,7 @@ impl BamlProject { } pub fn update_file(&mut self, document_key: &DocumentKey, content: Option) { - tracing::info!( + tracing::debug!( "Updating file: {}, {}", document_key.path().display(), content.clone().unwrap_or("None".to_string()) @@ -303,7 +303,7 @@ impl BamlProject { ) -> Result { let mut all_files_for_hash = self.files.iter().collect::>(); - log::info!( + log::debug!( "Baml Project saved files: {:#?}, Unsaved files: {:#?}", all_files_for_hash.len(), self.unsaved_files.len() @@ -329,13 +329,13 @@ impl BamlProject { tracing::debug!("Runtime cache hit ({})", current_hash); return cached_result.clone(); } - tracing::info!( + tracing::debug!( "Runtime cache miss (hash mismatch: {} != {})", *cached_hash, current_hash ); } else { - tracing::info!("Runtime cache miss (no cache entry)"); + tracing::debug!("Runtime cache miss (no cache entry)"); } let files_for_runtime = self @@ -1007,7 +1007,7 @@ impl Project { } let elapsed = start_time.elapsed(); - tracing::info!("update_runtime took {:?}ms", elapsed.as_millis()); + tracing::debug!("update_runtime took {:?}ms", elapsed.as_millis()); Ok(()) } diff --git a/engine/language_server/src/playground/mod.rs b/engine/language_server/src/playground/mod.rs index f0ed9b6045..cf34d88569 100644 --- a/engine/language_server/src/playground/mod.rs +++ b/engine/language_server/src/playground/mod.rs @@ -2,6 +2,7 @@ pub mod definitions; pub mod playground_server; pub mod playground_server_helpers; pub mod playground_server_rpc; +pub mod proxy; pub use definitions::{FrontendMessage, PlaygroundState}; pub use playground_server::PlaygroundServer; diff --git a/engine/language_server/src/playground/playground_server.rs b/engine/language_server/src/playground/playground_server.rs index 70fbfd3e9e..c549fe3661 100644 --- a/engine/language_server/src/playground/playground_server.rs +++ b/engine/language_server/src/playground/playground_server.rs @@ -7,6 +7,7 @@ use tokio::sync::RwLock; /// On the input port use crate::playground::definitions::PlaygroundState; use crate::{playground::playground_server_helpers::create_server_routes, session::Session}; +use crate::playground::proxy::ProxyServer; #[derive(Debug, Clone)] pub struct PlaygroundServer { @@ -22,7 +23,23 @@ impl PlaygroundServer { pub async fn run(self, port: u16) -> Result<()> { let routes = create_server_routes(self.state, self.session); - warp::serve(routes).try_bind(([127, 0, 0, 1], port)).await; + // Start the proxy server on a different port + let proxy_port = port + 1; // Use playground port + 1 for proxy + let proxy_server = ProxyServer::new(proxy_port); + + // Spawn the proxy server in a separate task + let proxy_handle = tokio::spawn(async move { + if let Err(e) = proxy_server.start().await { + tracing::error!("Proxy server failed: {}", e); + } + }); + + // Start the main playground server + tracing::info!("Starting main playground server on port {}", port); + warp::serve(routes).run(([127, 0, 0, 1], port)).await; + + // If we get here, the main server has stopped + tracing::info!("Main playground server stopped"); Ok(()) } diff --git a/engine/language_server/src/playground/playground_server_rpc.rs b/engine/language_server/src/playground/playground_server_rpc.rs index 7b9ca5cbe6..0e350c55e3 100644 --- a/engine/language_server/src/playground/playground_server_rpc.rs +++ b/engine/language_server/src/playground/playground_server_rpc.rs @@ -62,11 +62,11 @@ pub async fn handle_rpc_websocket(ws: WebSocket, session: Arc) { let _ = ws_tx.send(Message::text(response.to_string())).await; } "GET_PLAYGROUND_PORT" => { - let port = session.baml_settings.playground_port.unwrap_or(3030); + let playground_port = session.baml_settings.playground_port.unwrap_or(3030); let response = serde_json::json!({ "rpcMethod": "GET_PLAYGROUND_PORT", "rpcId": rpc_id, - "data": { "port": port } + "data": { "port": playground_port } }); let _ = ws_tx.send(Message::text(response.to_string())).await; } diff --git a/engine/language_server/src/playground/proxy.rs b/engine/language_server/src/playground/proxy.rs new file mode 100644 index 0000000000..6ba90c87b4 --- /dev/null +++ b/engine/language_server/src/playground/proxy.rs @@ -0,0 +1,295 @@ +use std::sync::Arc; +use anyhow::Result; +use warp::{Filter, Reply, Rejection}; +use serde_json::Value; + +// Custom response type for binary data +struct BinaryResponse { + body: Vec, + status: http::StatusCode, +} + +impl warp::Reply for BinaryResponse { + fn into_response(self) -> warp::http::Response { + warp::http::Response::builder() + .status(self.status) + .header("access-control-allow-origin", "*") + .body(warp::hyper::Body::from(self.body)) + .unwrap() + } +} + +// Custom error type for proxy +#[derive(Debug)] +struct ProxyError; + +impl warp::reject::Reject for ProxyError {} + +// API keys for model providers - these should be injected into requests +const API_KEY_INJECTION_ALLOWED: &[(&str, &str, &str, &str)] = &[ + ("https://api.openai.com", "Authorization", "OPENAI_API_KEY", "baml-openai-api-key"), + ("https://api.anthropic.com", "x-api-key", "ANTHROPIC_API_KEY", "baml-anthropic-api-key"), + ("https://generativelanguage.googleapis.com", "x-goog-api-key", "GOOGLE_API_KEY", "baml-google-api-key"), + ("https://openrouter.ai", "Authorization", "OPENROUTER_API_KEY", "baml-openrouter-api-key"), + ("https://api.llmapi.com", "Authorization", "LLAMA_API_KEY", "baml-llama-api-key"), +]; + +// Temporary dummy API keys for testing (remove in production) +const DUMMY_API_KEYS: &[(&str, &str)] = &[ + ("OPENAI_API_KEY", "sk-dummy-openai-key-for-testing-only"), + ("ANTHROPIC_API_KEY", "sk-ant-dummy-anthropic-key-for-testing-only"), + ("GOOGLE_API_KEY", "dummy-google-api-key-for-testing-only"), + ("OPENROUTER_API_KEY", "sk-dummy-openrouter-key-for-testing-only"), + ("LLAMA_API_KEY", "sk-dummy-llama-key-for-testing-only"), +]; + +pub struct ProxyServer { + port: u16, +} + +impl ProxyServer { + pub fn new(port: u16) -> Self { + Self { port } + } + + pub async fn start(self) -> Result<()> { + let addr = ([127, 0, 0, 1], self.port); + + // Handle OPTIONS requests (preflight CORS requests) + let cors_route = warp::options() + .and(warp::path::tail()) + .map(|_| { + warp::http::Response::builder() + .status(http::StatusCode::OK) + .header("access-control-allow-origin", "*") + .header("access-control-allow-methods", "GET, POST, PUT, DELETE, OPTIONS") + .header("access-control-allow-headers", "Content-Type, Authorization, x-api-key, baml-original-url, baml-openai-api-key, baml-anthropic-api-key, baml-google-api-key, baml-openrouter-api-key, baml-llama-api-key") + .header("access-control-max-age", "86400") + .body(warp::hyper::Body::empty()) + .unwrap() + }); + + // Proxy all requests - use a catch-all route that matches any path + let proxy_route = warp::any() + .and(warp::body::bytes()) + .and(warp::method()) + .and(warp::path::tail()) // Use tail() to capture any path + .and(warp::header::headers_cloned()) + .and_then(handle_proxy_request); + + // Combine CORS and proxy routes + let routes = cors_route.or(proxy_route); + + tracing::info!("Proxy server listening on port {}", self.port); + warp::serve(routes) + .run(addr) + .await; + + Ok(()) + } +} + +async fn handle_proxy_request( + body: bytes::Bytes, + method: http::Method, + path: warp::path::Tail, + mut headers: http::HeaderMap, +) -> Result { + let path_str = path.as_str(); + tracing::info!("[PROXY] Received request: {} {}", method, path_str); + + // Debug: Log request headers and body + tracing::info!("[PROXY] Request headers: {:?}", headers); + tracing::info!("[PROXY] Request body length: {} bytes", body.len()); + if body.len() < 1000 { // Only log small bodies to avoid spam + tracing::info!("[PROXY] Request body: {}", String::from_utf8_lossy(&body)); + } + + // Get the original URL from the header (same as VSCode extension) + let original_url = match headers.get("baml-original-url") { + Some(url) => match url.to_str() { + Ok(s) => s.to_string(), + Err(_) => { + tracing::warn!("[PROXY] Invalid baml-original-url header"); + return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_REQUEST }); + } + }, + None => { + tracing::warn!("[PROXY] Missing baml-original-url header"); + return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_REQUEST }); + } + }; + + tracing::info!("[PROXY] Original URL: {}", original_url); + + // Clean up headers that upstream may reject (same as VSCode extension) + headers.remove("baml-original-url"); + headers.remove("origin"); + headers.remove("authorization"); // Remove frontend's Authorization header to avoid conflicts + headers.remove("host"); // Remove host header so reqwest sets it based on the target URL + + // Parse the original URL - strip trailing slash like VSCode extension + let clean_original_url = if original_url.ends_with('/') { + &original_url[..original_url.len() - 1] + } else { + &original_url + }; + + let url = match url::Url::parse(clean_original_url) { + Ok(url) => url, + Err(_) => { + return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_REQUEST }); + } + }; + + // Handle image requests by clearing the path (same as VSCode extension) + if path_str.matches('.').count() == 1 && method == http::Method::GET { + tracing::info!("[PROXY] Image request detected, clearing path: {}", path_str); + return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::OK }); + } + + // Build the target URL following VSCode extension logic + let mut target_url = url.clone(); + + // Get the base path from the original URL (like VSCode extension) + let base_path = if url.path().ends_with('/') { + url.path().trim_end_matches('/').to_string() + } else { + url.path().to_string() + }; + + // Construct the final path following VSCode logic + let final_path = if base_path.is_empty() { + // Remove trailing slash from path_str like VSCode extension + if path_str.ends_with('/') { + path_str[..path_str.len() - 1].to_string() + } else { + path_str.to_string() + } + } else { + // Guard against double-prefixing like VSCode extension + if !path_str.starts_with(&base_path) { + // Ensure there's exactly one slash between basePath and existing path + if path_str.starts_with('/') { + format!("{}{}", base_path, path_str) + } else { + format!("{}/{}", base_path, path_str) + } + } else { + path_str.to_string() + } + }; + + // Remove trailing slash from final path like VSCode extension + let clean_final_path = if final_path.ends_with('/') { + &final_path[..final_path.len() - 1] + } else { + &final_path + }; + + target_url.set_path(clean_final_path); + + tracing::info!("[PROXY] {} {} → {:?}", method, path_str, url.origin()); + + // Create the request to the target + let mut request_builder = http::Request::builder() + .method(method.clone()) + .uri(target_url.to_string()); + + // Add headers + for (name, value) in headers.iter() { + request_builder = request_builder.header(name.as_str(), value); + } + + // Inject API keys for allowed origins (same as VSCode extension) + let origin_str = match url.origin() { + url::Origin::Tuple(scheme, host, port) => { + // Match VSCode extension behavior - don't include default ports + match (scheme.as_str(), port) { + ("http", 80) | ("https", 443) => format!("{}://{}", scheme, host), + _ => format!("{}://{}:{}", scheme, host, port) + } + } + url::Origin::Opaque(_) => { + return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_REQUEST }); + } + }; + + tracing::info!("[PROXY] Checking origin: {} against allowed origins", origin_str); + + for (allowed_origin, header_name, env_var, baml_header) in API_KEY_INJECTION_ALLOWED { + if origin_str == *allowed_origin { + tracing::info!("[PROXY] Origin {} matches allowed origin {}", origin_str, allowed_origin); + + // Try to get API key from environment variable first + let api_key = if let Ok(key) = std::env::var(env_var) { + tracing::info!("[PROXY] Using API key from environment variable {}", env_var); + key + } else if let Some(api_key_value) = headers.get(*baml_header) { + if let Ok(key) = api_key_value.to_str() { + tracing::info!("[PROXY] Using API key from header {}", baml_header); + key.to_string() + } else { + tracing::warn!("[PROXY] Invalid API key in header {}", baml_header); + continue; + } + } else { + // Use dummy key as fallback for testing + if let Some((_, dummy_key)) = DUMMY_API_KEYS.iter().find(|(key, _)| **key == **env_var) { + tracing::warn!("[PROXY] Using dummy API key for {} (env var: {}, header: {})", allowed_origin, env_var, baml_header); + dummy_key.to_string() + } else { + tracing::warn!("[PROXY] No API key found for {} (tried env var {} and header {})", allowed_origin, env_var, baml_header); + continue; + } + }; + + let header_value = if *header_name == "Authorization" { + format!("Bearer {}", api_key) + } else { + api_key + }; + request_builder = request_builder.header(*header_name, header_value); + tracing::info!("[PROXY] Injected API key for {} (header: {})", allowed_origin, header_name); + } + } + + for (name, value) in request_builder.headers_ref().unwrap().iter() { + tracing::info!("[PROXY] Outgoing header: {}: {:?}", name, value); + } + + // Build the request + let request = match request_builder.body(body.to_vec()) { + Ok(req) => req, + Err(_) => { + return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::INTERNAL_SERVER_ERROR }); + } + }; + + // Make the request using reqwest + let client = reqwest::Client::new(); + let response = match client.execute(request.try_into().map_err(|_| warp::reject::custom(ProxyError))?).await { + Ok(resp) => resp, + Err(e) => { + tracing::error!("[PROXY ERROR] {} {}: {}", method, path_str, e); + return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_GATEWAY }); + } + }; + + // Build the response + let status = response.status(); + let body_bytes = match response.bytes().await { + Ok(bytes) => bytes, + Err(e) => { + tracing::error!("[PROXY ERROR] Failed to read response body: {}", e); + return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::INTERNAL_SERVER_ERROR }); + } + }; + + tracing::info!("[PROXY] {} {} ← {}", method, path_str, status); + tracing::info!("[PROXY] Upstream response status: {}", status); + tracing::info!("[PROXY] Upstream response body: {}", String::from_utf8_lossy(&body_bytes)); + + // Return response (CORS header will be added by warp middleware) + Ok(BinaryResponse { body: body_bytes.to_vec(), status }) +} \ No newline at end of file diff --git a/engine/language_server/src/server/api.rs b/engine/language_server/src/server/api.rs index f4c7c626c0..f73fb5dc13 100644 --- a/engine/language_server/src/server/api.rs +++ b/engine/language_server/src/server/api.rs @@ -71,12 +71,12 @@ pub(super) fn request<'a>(req: lsp_server::Request) -> Task<'a> { request::GotoDefinition::METHOD => local_request_task::(req), request::Rename::METHOD => local_request_task::(req), request::DocumentDiagnosticRequestHandler::METHOD => { - tracing::info!("diagnostic notif"); + // tracing::info!("diagnostic notif"); local_request_task::(req) // note background request task here sometimes results in inconsistent baml project state... } "getBAMLFunctions" => { - tracing::info!("getBAMLFunctions"); + // tracing::info!("getBAMLFunctions"); return Task::local(move |session, _notifier, requester, responder| { let result: anyhow::Result<(serde_json::Value,)> = { let mut all_functions = Vec::new(); @@ -121,7 +121,7 @@ pub(super) fn request<'a>(req: lsp_server::Request) -> Task<'a> { }); } "requestDiagnostics" => { - tracing::info!("---- requestDiagnostics"); + // tracing::info!("---- requestDiagnostics"); return Task::local(move |session, notifier, _requester, responder| { let result: anyhow::Result<()> = (|| { // tracing::info!("requestDiagnostics: {:?}", req.params); @@ -141,7 +141,7 @@ pub(super) fn request<'a>(req: lsp_server::Request) -> Task<'a> { // TODO: I think we need to send ALL diagnostics for the project. Not sure how this report is different vs sending a signle diagnostic param message let diagnostics = file_diagnostics(project.clone(), &url); - tracing::info!("---- diagnostics Returned: "); + // tracing::info!("---- diagnostics Returned: "); let report = Ok(DocumentDiagnosticReportResult::Report( DocumentDiagnosticReport::Full(RelatedFullDocumentDiagnosticReport { related_documents: None, @@ -233,7 +233,7 @@ pub(super) fn notification<'a>(notif: lsp_server::Notification) -> Vec> } // --- DidSaveTextDocument now uses the simple local task helper --- notification::DidSaveTextDocument::METHOD => { - tracing::info!("Did save text document---------"); + // tracing::info!("Did save text document---------"); handle_notification_result_error::( // Do not use background notifs yet, as baml_client may not have an updated view of the project files // See the did_save_text_document.rs file for more details @@ -276,10 +276,10 @@ fn background_request_task<'a, R: traits::BackgroundDocumentRequestHandler>( let Some(_snapshot) = session.take_snapshot(url) else { return Box::new(|_, _| {}); }; - info!( - "session.projects.len(): {:?}", - session.baml_src_projects.lock().unwrap().len() - ); + // info!( + // "session.projects.len(): {:?}", + // session.baml_src_projects.lock().unwrap().len() + // ); let _db = session.get_or_create_project(&path).clone(); if _db.is_none() { tracing::error!("Could not find project for path"); diff --git a/typescript/playground-common/src/shared/baml-project-panel/atoms.ts b/typescript/playground-common/src/shared/baml-project-panel/atoms.ts index 0a51e30f28..55768eb411 100644 --- a/typescript/playground-common/src/shared/baml-project-panel/atoms.ts +++ b/typescript/playground-common/src/shared/baml-project-panel/atoms.ts @@ -167,7 +167,7 @@ const playgroundPortAtom = unwrap( export const proxyUrlAtom = atom((get) => { const vscodeSettings = get(vscodeSettingsAtom) const port = get(playgroundPortAtom) - const proxyUrl = port && port !== 0 ? `http://localhost:${port}` : undefined + const proxyUrl = port && port !== 0 ? `http://localhost:${port + 1}` : undefined const proxyEnabled = !!vscodeSettings?.enablePlaygroundProxy return { proxyEnabled, @@ -296,7 +296,8 @@ const defaultEnvKeyValues: [string, string][] = (() => { } else { console.log('Not running in a Next.js environment, set default value') // Not running in a Next.js environment, set default value - return [['BOUNDARY_PROXY_URL', 'http://localhost:0000']] + // The proxy is now handled by the LSP, so we'll use a placeholder that will be replaced + return [['BOUNDARY_PROXY_URL', 'http://localhost:3031']] } })() export const envKeyValueStorage = atomWithStorage<[string, string][]>( diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml index 2689b2da7b..8525e9584a 100644 --- a/typescript/pnpm-lock.yaml +++ b/typescript/pnpm-lock.yaml @@ -264,7 +264,7 @@ importers: version: 16.4.7 http-proxy: specifier: ^1.18.1 - version: 1.18.1(debug@4.4.0) + version: 1.18.1 jotai: specifier: ^2.8.0 version: 2.11.0(@types/react@18.3.18)(react@18.3.1) @@ -860,27 +860,15 @@ importers: comlink: specifier: ^4.4.2 version: 4.4.2 - cors: - specifier: ^2.8.5 - version: 2.8.5 dotenv: specifier: ^16.4.7 version: 16.4.7 env-paths: specifier: 2.2.1 version: 2.2.1 - express: - specifier: ^4.21.1 - version: 4.21.2 google-auth-library: specifier: ^9.15.1 version: 9.15.1 - http-proxy: - specifier: ^1.18.1 - version: 1.18.1(debug@4.4.0) - http-proxy-middleware: - specifier: ^3.0.3 - version: 3.0.3 minimatch: specifier: 6.2.0 version: 6.2.0 @@ -918,18 +906,9 @@ importers: '@types/adm-zip': specifier: ^0.5.7 version: 0.5.7 - '@types/cors': - specifier: ^2.8.17 - version: 2.8.17 - '@types/express': - specifier: ^4.17.21 - version: 4.17.21 '@types/glob': specifier: 8.1.0 version: 8.1.0 - '@types/http-proxy': - specifier: ^1.17.14 - version: 1.17.15 '@types/mocha': specifier: 10.0.3 version: 10.0.3 @@ -4759,15 +4738,6 @@ packages: '@types/base16@1.0.5': resolution: {integrity: sha512-OzOWrTluG9cwqidEzC/Q6FAmIPcnZfm8BFRlIx0+UIUqnuAmi5OS88O0RpT3Yz6qdmqObvUhasrbNsCofE4W9A==} - '@types/body-parser@1.19.5': - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/cors@2.8.17': - resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} - '@types/d3-color@3.1.3': resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} @@ -4804,12 +4774,6 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/express-serve-static-core@4.19.6': - resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} - - '@types/express@4.17.21': - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - '@types/glob@8.1.0': resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} @@ -4825,9 +4789,6 @@ packages: '@types/he@1.2.3': resolution: {integrity: sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==} - '@types/http-errors@2.0.4': - resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - '@types/http-proxy@1.17.15': resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==} @@ -4861,9 +4822,6 @@ packages: '@types/mdx@2.0.13': resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} @@ -4891,12 +4849,6 @@ packages: '@types/prop-types@15.7.14': resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} - '@types/qs@6.9.17': - resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react-dom@18.3.5': resolution: {integrity: sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==} peerDependencies: @@ -4920,12 +4872,6 @@ packages: '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - '@types/send@0.17.4': - resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} - - '@types/serve-static@1.15.7': - resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} - '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -5298,10 +5244,6 @@ packages: aborter@1.1.0: resolution: {integrity: sha512-9rHWMcWTEYsMB4l+ttgPujR7OiXH9NQbP0ej+SSVaK1e2yU/tePbYm8g/g9cQhJkgczp6lpEB2fdJYLKT/T0mg==} - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -5461,9 +5403,6 @@ packages: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-includes@3.1.8: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} @@ -5771,10 +5710,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -5850,10 +5785,6 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -6129,24 +6060,9 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} - engines: {node: '>= 0.6'} - copy-descriptor@0.1.1: resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} engines: {node: '>=0.10.0'} @@ -6168,10 +6084,6 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - cpx@1.5.0: resolution: {integrity: sha512-jHTjZhsbg9xWgsP2vuNW2jnnzBX+p4T+vNI9Lbjzs1n4KhOfa22bQppiFYLsWQKd8TzmL5aSP/Me3yfsCwXbDA==} hasBin: true @@ -6398,18 +6310,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -6499,9 +6403,6 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} @@ -6523,14 +6424,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - encoding-sniffer@0.2.0: resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} @@ -6627,9 +6520,6 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -6803,10 +6693,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -6848,10 +6734,6 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - express@4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} - engines: {node: '>= 0.10.0'} - extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -6936,10 +6818,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} - find-index@0.1.1: resolution: {integrity: sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==} @@ -7001,10 +6879,6 @@ packages: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -7026,10 +6900,6 @@ packages: react-dom: optional: true - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -7323,10 +7193,6 @@ packages: htmlparser2@9.1.0: resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - http-proxy-agent@4.0.1: resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} engines: {node: '>= 6'} @@ -7335,10 +7201,6 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-proxy-middleware@3.0.3: - resolution: {integrity: sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - http-proxy@1.18.1: resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} engines: {node: '>=8.0.0'} @@ -7355,10 +7217,6 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -7413,10 +7271,6 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - is-accessor-descriptor@1.0.1: resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} engines: {node: '>= 0.10'} @@ -7633,10 +7487,6 @@ packages: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} - is-plain-object@5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} - engines: {node: '>=0.10.0'} - is-posix-bracket@0.1.1: resolution: {integrity: sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==} engines: {node: '>=0.10.0'} @@ -8397,19 +8247,12 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -8417,10 +8260,6 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - micromark-core-commonmark@2.0.2: resolution: {integrity: sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==} @@ -8680,10 +8519,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -8843,10 +8678,6 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -8940,10 +8771,6 @@ packages: parse5@7.2.1: resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - pascalcase@0.1.1: resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} engines: {node: '>=0.10.0'} @@ -8971,9 +8798,6 @@ packages: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -9156,10 +8980,6 @@ packages: property-information@6.5.0: resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -9177,10 +8997,6 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} - qs@6.13.1: resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} engines: {node: '>=0.6'} @@ -9195,14 +9011,6 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} - rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -9759,10 +9567,6 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - seq@0.3.5: resolution: {integrity: sha512-sisY2Ln1fj43KBkRtXkesnRHYNdswIkIibvNe/0UKm2GZxjMbqmccpiatoKr/k2qX5VKiLU8xm+tz/74LAho4g==} @@ -9772,10 +9576,6 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -9795,9 +9595,6 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shallowequal@1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} @@ -9942,10 +9739,6 @@ packages: resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} engines: {node: '>=0.10.0'} - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - stoppable@1.1.0: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} @@ -10258,10 +10051,6 @@ packages: resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} engines: {node: '>=0.10.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -10458,10 +10247,6 @@ packages: resolution: {integrity: sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==} engines: {node: '>=16'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -10577,10 +10362,6 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - unplugin@1.16.1: resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} engines: {node: '>=14.0.0'} @@ -10677,10 +10458,6 @@ packages: util@0.12.5: resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true @@ -10715,10 +10492,6 @@ packages: validate.io-number@1.0.3: resolution: {integrity: sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==} - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - vfile-message@4.0.2: resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} @@ -15244,19 +15017,6 @@ snapshots: '@types/base16@1.0.5': {} - '@types/body-parser@1.19.5': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 20.17.12 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 20.17.12 - - '@types/cors@2.8.17': - dependencies: - '@types/node': 20.17.12 - '@types/d3-color@3.1.3': {} '@types/d3-drag@3.0.7': @@ -15300,20 +15060,6 @@ snapshots: '@types/estree@1.0.6': {} - '@types/express-serve-static-core@4.19.6': - dependencies: - '@types/node': 20.17.12 - '@types/qs': 6.9.17 - '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 - - '@types/express@4.17.21': - dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.17 - '@types/serve-static': 1.15.7 - '@types/glob@8.1.0': dependencies: '@types/minimatch': 5.1.2 @@ -15333,8 +15079,6 @@ snapshots: '@types/he@1.2.3': {} - '@types/http-errors@2.0.4': {} - '@types/http-proxy@1.17.15': dependencies: '@types/node': 20.17.12 @@ -15368,8 +15112,6 @@ snapshots: '@types/mdx@2.0.13': {} - '@types/mime@1.3.5': {} - '@types/minimatch@5.1.2': {} '@types/mocha@10.0.3': {} @@ -15394,10 +15136,6 @@ snapshots: '@types/prop-types@15.7.14': {} - '@types/qs@6.9.17': {} - - '@types/range-parser@1.2.7': {} - '@types/react-dom@18.3.5(@types/react@18.3.18)': dependencies: '@types/react': 18.3.18 @@ -15423,17 +15161,6 @@ snapshots: '@types/semver@7.5.8': {} - '@types/send@0.17.4': - dependencies: - '@types/mime': 1.3.5 - '@types/node': 20.17.12 - - '@types/serve-static@1.15.7': - dependencies: - '@types/http-errors': 2.0.4 - '@types/node': 20.17.12 - '@types/send': 0.17.4 - '@types/stack-utils@2.0.3': {} '@types/stylis@4.2.5': {} @@ -16056,11 +15783,6 @@ snapshots: aborter@1.1.0: {} - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -16200,8 +15922,6 @@ snapshots: call-bound: 1.0.3 is-array-buffer: 3.0.5 - array-flatten@1.1.1: {} - array-includes@3.1.8: dependencies: call-bind: 1.0.8 @@ -16307,7 +16027,7 @@ snapshots: axios@1.7.9: dependencies: - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9 form-data: 4.0.1 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -16741,23 +16461,6 @@ snapshots: readable-stream: 3.6.2 optional: true - body-parser@1.20.3: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - boolbase@1.0.0: {} bottleneck@2.19.5: {} @@ -16855,8 +16558,6 @@ snapshots: dependencies: streamsearch: 1.1.0 - bytes@3.1.2: {} - cac@6.7.14: {} cache-base@1.0.1: @@ -17180,18 +16881,8 @@ snapshots: concat-map@0.0.1: {} - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - convert-source-map@2.0.0: {} - cookie-signature@1.0.6: {} - - cookie@0.7.1: {} - copy-descriptor@0.1.1: {} copyfiles@2.4.1: @@ -17215,11 +16906,6 @@ snapshots: core-util-is@1.0.3: {} - cors@2.8.5: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - cpx@1.5.0: dependencies: babel-runtime: 6.26.0 @@ -17463,12 +17149,8 @@ snapshots: delayed-stream@1.0.0: {} - depd@2.0.0: {} - dequal@2.0.3: {} - destroy@1.2.0: {} - detect-libc@2.0.3: optional: true @@ -17550,8 +17232,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - ee-first@1.1.1: {} - ejs@3.1.10: dependencies: jake: 10.9.2 @@ -17566,10 +17246,6 @@ snapshots: emoji-regex@9.2.2: {} - encodeurl@1.0.2: {} - - encodeurl@2.0.0: {} - encoding-sniffer@0.2.0: dependencies: iconv-lite: 0.6.3 @@ -17824,8 +17500,6 @@ snapshots: escalade@3.2.0: {} - escape-html@1.0.3: {} - escape-string-regexp@1.0.5: {} escape-string-regexp@2.0.0: {} @@ -18088,8 +17762,6 @@ snapshots: esutils@2.0.3: {} - etag@1.8.1: {} - eventemitter3@4.0.7: {} eventemitter3@5.0.1: {} @@ -18143,42 +17815,6 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - express@4.21.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.12 - proxy-addr: 2.0.7 - qs: 6.13.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -18282,18 +17918,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.3.1: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - find-index@0.1.1: {} find-up@4.1.0: @@ -18316,9 +17940,7 @@ snapshots: flatted@3.3.2: {} - follow-redirects@1.15.9(debug@4.4.0): - optionalDependencies: - debug: 4.4.0 + follow-redirects@1.15.9: {} for-each@0.3.3: dependencies: @@ -18349,8 +17971,6 @@ snapshots: dependencies: fetch-blob: 3.2.0 - forwarded@0.2.0: {} - fraction.js@4.3.7: {} fragment-cache@0.2.1: @@ -18367,8 +17987,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - fresh@0.5.2: {} - fs-constants@1.0.0: optional: true @@ -18751,14 +18369,6 @@ snapshots: domutils: 3.2.2 entities: 4.5.0 - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - http-proxy-agent@4.0.1: dependencies: '@tootallnate/once': 1.1.2 @@ -18774,21 +18384,10 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy-middleware@3.0.3: - dependencies: - '@types/http-proxy': 1.17.15 - debug: 4.4.0 - http-proxy: 1.18.1(debug@4.4.0) - is-glob: 4.0.3 - is-plain-object: 5.0.0 - micromatch: 4.0.8 - transitivePeerDependencies: - - supports-color - - http-proxy@1.18.1(debug@4.4.0): + http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -18809,10 +18408,6 @@ snapshots: human-signals@2.1.0: {} - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 @@ -18862,8 +18457,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - ipaddr.js@1.9.1: {} - is-accessor-descriptor@1.0.1: dependencies: hasown: 2.0.2 @@ -19056,8 +18649,6 @@ snapshots: dependencies: isobject: 3.0.1 - is-plain-object@5.0.0: {} - is-posix-bracket@0.1.1: {} is-primitive@2.0.0: {} @@ -20189,22 +19780,16 @@ snapshots: mdurl@2.0.0: {} - media-typer@0.3.0: {} - memoize-one@5.2.1: {} memoizerific@1.11.3: dependencies: map-or-similar: 1.5.0 - merge-descriptors@1.0.3: {} - merge-stream@2.0.0: {} merge2@1.4.1: {} - methods@1.1.2: {} - micromark-core-commonmark@2.0.2: dependencies: decode-named-character-reference: 1.0.2 @@ -20615,8 +20200,6 @@ snapshots: natural-compare@1.4.0: {} - negotiator@0.6.3: {} - neo-async@2.6.2: {} next-themes@0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -20783,10 +20366,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -20831,7 +20410,7 @@ snapshots: dependencies: '@vscode/vsce': 2.21.1 commander: 6.2.1 - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9 is-ci: 2.0.0 leven: 3.1.0 semver: 7.6.3 @@ -20923,8 +20502,6 @@ snapshots: dependencies: entities: 4.5.0 - parseurl@1.3.3: {} - pascalcase@0.1.1: {} path-exists@4.0.0: {} @@ -20945,8 +20522,6 @@ snapshots: lru-cache: 11.0.2 minipass: 7.1.2 - path-to-regexp@0.1.12: {} - path-type@4.0.0: {} pathval@2.0.0: {} @@ -21114,11 +20689,6 @@ snapshots: property-information@6.5.0: {} - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - proxy-from-env@1.1.0: {} pump@3.0.2: @@ -21133,10 +20703,6 @@ snapshots: pure-rand@6.1.0: {} - qs@6.13.0: - dependencies: - side-channel: 1.1.0 - qs@6.13.1: dependencies: side-channel: 1.1.0 @@ -21153,15 +20719,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - range-parser@1.2.1: {} - - raw-body@2.5.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -21920,24 +21477,6 @@ snapshots: semver@7.6.3: {} - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - seq@0.3.5: dependencies: chainsaw: 0.0.9 @@ -21951,15 +21490,6 @@ snapshots: dependencies: randombytes: 2.1.0 - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -21991,8 +21521,6 @@ snapshots: setimmediate@1.0.5: {} - setprototypeof@1.2.0: {} - shallowequal@1.1.0: {} sharp@0.33.5: @@ -22176,8 +21704,6 @@ snapshots: define-property: 0.2.5 object-copy: 0.1.0 - statuses@2.0.1: {} - stoppable@1.1.0: {} store2@2.14.4: {} @@ -22593,8 +22119,6 @@ snapshots: regex-not: 1.0.2 safe-regex: 1.1.0 - toidentifier@1.0.1: {} - tr46@0.0.3: {} tr46@1.0.1: @@ -22802,11 +22326,6 @@ snapshots: type-fest@4.31.0: {} - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.3 @@ -22947,8 +22466,6 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 - unpipe@1.0.0: {} - unplugin@1.16.1: dependencies: acorn: 8.14.0 @@ -23065,8 +22582,6 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.18 - utils-merge@1.0.1: {} - uuid@10.0.0: {} uuid@8.3.2: {} @@ -23096,8 +22611,6 @@ snapshots: validate.io-number@1.0.3: {} - vary@1.1.2: {} - vfile-message@4.0.2: dependencies: '@types/unist': 3.0.3 diff --git a/typescript/vscode-ext/packages/vscode/package.json b/typescript/vscode-ext/packages/vscode/package.json index 2c4e542307..f26f7645a9 100644 --- a/typescript/vscode-ext/packages/vscode/package.json +++ b/typescript/vscode-ext/packages/vscode/package.json @@ -41,13 +41,9 @@ "adm-zip": "^0.5.16", "axios": "^1.7.9", "comlink": "^4.4.2", - "cors": "^2.8.5", "dotenv": "^16.4.7", "env-paths": "2.2.1", - "express": "^4.21.1", "google-auth-library": "^9.15.1", - "http-proxy": "^1.18.1", - "http-proxy-middleware": "^3.0.3", "minimatch": "6.2.0", "node-fetch": "^3.3.2", "posthog-node": "^3.2.1", @@ -62,10 +58,7 @@ }, "devDependencies": { "@types/adm-zip": "^0.5.7", - "@types/cors": "^2.8.17", - "@types/express": "^4.17.21", "@types/glob": "8.1.0", - "@types/http-proxy": "^1.17.14", "@types/mocha": "10.0.3", "@types/vscode": "1.63.0", "@vscode/test-electron": "2.3.5", diff --git a/typescript/vscode-ext/packages/vscode/src/extension.ts b/typescript/vscode-ext/packages/vscode/src/extension.ts index ae0fb0bb83..5b269a6dba 100644 --- a/typescript/vscode-ext/packages/vscode/src/extension.ts +++ b/typescript/vscode-ext/packages/vscode/src/extension.ts @@ -1,15 +1,10 @@ /* eslint-disable @typescript-eslint/no-misused-promises */ import * as vscode from 'vscode' -import axios from 'axios' import glooLens from './LanguageToBamlCodeLensProvider' import { WebviewPanelHost } from './panels/WebviewPanelHost' import plugins from './plugins' import { requestBamlCLIVersion, requestDiagnostics, getPlaygroundPort } from './plugins/language-server-client' import { telemetry, viewFunctionInPlayground, runTestInPlayground } from './plugins/language-server-client' -import cors from 'cors' -import { createProxyMiddleware } from 'http-proxy-middleware' -import { Socket } from 'net' -import { type Express } from 'express' import StatusBarPanel from './panels/StatusBarPanel' import TelemetryReporter from './telemetryReporter' @@ -17,7 +12,6 @@ const outputChannel = vscode.window.createOutputChannel('baml') const diagnosticsCollection = vscode.languages.createDiagnosticCollection('baml-diagnostics') const LANG_NAME = 'Baml' -let server: any let glowOnDecoration: vscode.TextEditorDecorationType | null = null let glowOffDecoration: vscode.TextEditorDecorationType | null = null let isGlowOn: boolean = true @@ -35,103 +29,12 @@ export function activate(context: vscode.ExtensionContext) { createDecorations() startAnimation() - const app: Express = require('express')() - app.use(cors()) - const server = app.listen(0, () => { - console.log('Server started on port ' + getPort()) - }) - + // Wrapper function to handle null case from getPlaygroundPort const getPort = () => { - const addr = server.address() - if (addr === null) { - vscode.window.showErrorMessage( - 'Failed to start BAML extension server. Please try reloading the window, or restarting VSCode.', - ) - console.error('Failed to start BAML extension server. Please try reloading the window, or restarting VSCode.') - return 0 - } - if (typeof addr === 'string') { - return parseInt(addr) - } - return addr.port + const port = getPlaygroundPort() + return port ?? 3030 // Default to 3030 if null } - app.use( - createProxyMiddleware({ - changeOrigin: true, // leave prependPath = true (default) - /** Inspect and (maybe) rewrite the path. */ - pathRewrite: (path, req) => { - // If the path looks like an image (xyz.png …) and it's a GET → blank it. - if (/\.[a-z0-9]+$/i.test(path) && req.method === 'GET') { - console.log('[PROXY] Image request detected, clearing path:', path) - return '' - } - - // Remove trailing slash so we don't end up with "//". - const out = path.endsWith('/') ? path.slice(0, -1) : path - return out - }, - - /** Dynamically choose target and massage req.url. */ - router: (req) => { - const raw = req.headers['baml-original-url'] - if (typeof raw !== 'string') { - throw new Error('missing baml-original-url header') - } - - // Clean up headers the upstream may reject - delete req.headers['baml-original-url'] - delete req.headers['origin'] - - // Strip trailing slash on header value, then parse - const cleanRaw = raw.endsWith('/') ? raw.slice(0, -1) : raw - const url = new URL(cleanRaw) - - // Base path to prepend *if necessary* - const basePath = url.pathname.replace(/\/$/, '') // '/compat/v1' → '/compat/v1' - if (!req.url) { - throw new Error('missing req.url') - } - - // Guard against double-prefixing - if (basePath && !req.url.startsWith(basePath)) { - // Ensure there's exactly one slash between basePath and existing path - req.url = basePath + (req.url.startsWith('/') ? '' : '/') + req.url - } - - console.log('[PROXY]', req.method, req.url, '→', url.origin) - - // Tell HPM to proxy to the origin only (scheme + host) - return url.origin // e.g. "https://api.llama.com" - }, - - logger: console, - - on: { - /** Add CORS header. */ - proxyRes: (proxyRes, req) => { - proxyRes.headers['access-control-allow-origin'] = '*' - console.log('[PROXY]', req.method, req.url, '←', proxyRes.statusCode) - }, - - /** Robust error reporter with type-guard. */ - error: (err, req, res) => { - console.error('[PROXY ERROR]', req.method, req.url, ':', err.message) - - if ('writeHead' in res) { - const svr = res - if (!svr.headersSent) { - svr.writeHead(500, { 'content-type': 'application/json' }) - } - svr.end(JSON.stringify({ error: err.message })) - } else if (res instanceof Socket) { - res.destroy() - } - }, - }, - }), - ) - const bamlPlaygroundCommand = vscode.commands.registerCommand( 'baml.openBamlPanel', async (args?: { projectId?: string; functionName?: string; implName?: string; showTests?: boolean }) => { @@ -317,7 +220,7 @@ export function deactivate(): void { void plugin.deactivate() } } - server?.close() + // server?.close() } // Create our two decoration states From 53ceaddcdb57c3f659c09f7cd58d1db1f61e68a3 Mon Sep 17 00:00:00 2001 From: egol Date: Fri, 27 Jun 2025 10:09:29 -0700 Subject: [PATCH 71/71] clean up proxy code --- .../language_server/src/playground/proxy.rs | 122 +++++------------- 1 file changed, 34 insertions(+), 88 deletions(-) diff --git a/engine/language_server/src/playground/proxy.rs b/engine/language_server/src/playground/proxy.rs index 6ba90c87b4..606c958a99 100644 --- a/engine/language_server/src/playground/proxy.rs +++ b/engine/language_server/src/playground/proxy.rs @@ -96,39 +96,23 @@ async fn handle_proxy_request( mut headers: http::HeaderMap, ) -> Result { let path_str = path.as_str(); - tracing::info!("[PROXY] Received request: {} {}", method, path_str); - - // Debug: Log request headers and body - tracing::info!("[PROXY] Request headers: {:?}", headers); - tracing::info!("[PROXY] Request body length: {} bytes", body.len()); - if body.len() < 1000 { // Only log small bodies to avoid spam - tracing::info!("[PROXY] Request body: {}", String::from_utf8_lossy(&body)); - } - - // Get the original URL from the header (same as VSCode extension) let original_url = match headers.get("baml-original-url") { Some(url) => match url.to_str() { Ok(s) => s.to_string(), Err(_) => { - tracing::warn!("[PROXY] Invalid baml-original-url header"); return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_REQUEST }); } }, None => { - tracing::warn!("[PROXY] Missing baml-original-url header"); return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_REQUEST }); } }; - tracing::info!("[PROXY] Original URL: {}", original_url); - - // Clean up headers that upstream may reject (same as VSCode extension) headers.remove("baml-original-url"); headers.remove("origin"); - headers.remove("authorization"); // Remove frontend's Authorization header to avoid conflicts - headers.remove("host"); // Remove host header so reqwest sets it based on the target URL + headers.remove("authorization"); + headers.remove("host"); - // Parse the original URL - strip trailing slash like VSCode extension let clean_original_url = if original_url.ends_with('/') { &original_url[..original_url.len() - 1] } else { @@ -142,45 +126,34 @@ async fn handle_proxy_request( } }; - // Handle image requests by clearing the path (same as VSCode extension) if path_str.matches('.').count() == 1 && method == http::Method::GET { - tracing::info!("[PROXY] Image request detected, clearing path: {}", path_str); return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::OK }); } - // Build the target URL following VSCode extension logic let mut target_url = url.clone(); - // Get the base path from the original URL (like VSCode extension) let base_path = if url.path().ends_with('/') { url.path().trim_end_matches('/').to_string() } else { url.path().to_string() }; - // Construct the final path following VSCode logic let final_path = if base_path.is_empty() { - // Remove trailing slash from path_str like VSCode extension - if path_str.ends_with('/') { - path_str[..path_str.len() - 1].to_string() + if let Some(stripped) = path_str.strip_suffix('/') { + stripped.to_string() } else { path_str.to_string() } - } else { - // Guard against double-prefixing like VSCode extension - if !path_str.starts_with(&base_path) { - // Ensure there's exactly one slash between basePath and existing path - if path_str.starts_with('/') { - format!("{}{}", base_path, path_str) - } else { - format!("{}/{}", base_path, path_str) - } + } else if !path_str.starts_with(&base_path) { + if path_str.starts_with('/') { + format!("{}{}", base_path, path_str) } else { - path_str.to_string() + format!("{}/{}", base_path, path_str) } + } else { + path_str.to_string() }; - // Remove trailing slash from final path like VSCode extension let clean_final_path = if final_path.ends_with('/') { &final_path[..final_path.len() - 1] } else { @@ -189,8 +162,6 @@ async fn handle_proxy_request( target_url.set_path(clean_final_path); - tracing::info!("[PROXY] {} {} → {:?}", method, path_str, url.origin()); - // Create the request to the target let mut request_builder = http::Request::builder() .method(method.clone()) @@ -198,13 +169,12 @@ async fn handle_proxy_request( // Add headers for (name, value) in headers.iter() { - request_builder = request_builder.header(name.as_str(), value); + request_builder = request_builder.header(name.as_str(), value); } // Inject API keys for allowed origins (same as VSCode extension) let origin_str = match url.origin() { url::Origin::Tuple(scheme, host, port) => { - // Match VSCode extension behavior - don't include default ports match (scheme.as_str(), port) { ("http", 80) | ("https", 443) => format!("{}://{}", scheme, host), _ => format!("{}://{}:{}", scheme, host, port) @@ -214,51 +184,25 @@ async fn handle_proxy_request( return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_REQUEST }); } }; - - tracing::info!("[PROXY] Checking origin: {} against allowed origins", origin_str); - + + // API key injection logic for (allowed_origin, header_name, env_var, baml_header) in API_KEY_INJECTION_ALLOWED { if origin_str == *allowed_origin { - tracing::info!("[PROXY] Origin {} matches allowed origin {}", origin_str, allowed_origin); - - // Try to get API key from environment variable first - let api_key = if let Ok(key) = std::env::var(env_var) { - tracing::info!("[PROXY] Using API key from environment variable {}", env_var); - key - } else if let Some(api_key_value) = headers.get(*baml_header) { - if let Ok(key) = api_key_value.to_str() { - tracing::info!("[PROXY] Using API key from header {}", baml_header); - key.to_string() + let api_key = std::env::var(env_var) + .ok() + .or_else(|| headers.get(*baml_header).and_then(|v| v.to_str().ok()).map(|s| s.to_string())) + .or_else(|| DUMMY_API_KEYS.iter().find(|(key, _)| *key == *env_var).map(|(_, v)| v.to_string())); + if let Some(api_key) = api_key { + let header_value = if *header_name == "Authorization" { + format!("Bearer {}", api_key) } else { - tracing::warn!("[PROXY] Invalid API key in header {}", baml_header); - continue; - } - } else { - // Use dummy key as fallback for testing - if let Some((_, dummy_key)) = DUMMY_API_KEYS.iter().find(|(key, _)| **key == **env_var) { - tracing::warn!("[PROXY] Using dummy API key for {} (env var: {}, header: {})", allowed_origin, env_var, baml_header); - dummy_key.to_string() - } else { - tracing::warn!("[PROXY] No API key found for {} (tried env var {} and header {})", allowed_origin, env_var, baml_header); - continue; - } - }; - - let header_value = if *header_name == "Authorization" { - format!("Bearer {}", api_key) - } else { - api_key - }; - request_builder = request_builder.header(*header_name, header_value); - tracing::info!("[PROXY] Injected API key for {} (header: {})", allowed_origin, header_name); + api_key + }; + request_builder = request_builder.header(*header_name, header_value); + } } } - for (name, value) in request_builder.headers_ref().unwrap().iter() { - tracing::info!("[PROXY] Outgoing header: {}: {:?}", name, value); - } - - // Build the request let request = match request_builder.body(body.to_vec()) { Ok(req) => req, Err(_) => { @@ -266,30 +210,32 @@ async fn handle_proxy_request( } }; - // Make the request using reqwest let client = reqwest::Client::new(); let response = match client.execute(request.try_into().map_err(|_| warp::reject::custom(ProxyError))?).await { Ok(resp) => resp, Err(e) => { - tracing::error!("[PROXY ERROR] {} {}: {}", method, path_str, e); return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::BAD_GATEWAY }); } }; - // Build the response let status = response.status(); let body_bytes = match response.bytes().await { Ok(bytes) => bytes, Err(e) => { - tracing::error!("[PROXY ERROR] Failed to read response body: {}", e); return Ok(BinaryResponse { body: Vec::new(), status: http::StatusCode::INTERNAL_SERVER_ERROR }); } }; - tracing::info!("[PROXY] {} {} ← {}", method, path_str, status); - tracing::info!("[PROXY] Upstream response status: {}", status); - tracing::info!("[PROXY] Upstream response body: {}", String::from_utf8_lossy(&body_bytes)); + tracing::info!( + "[PROXY] {} {} → {:?} | headers: {:?} | req_body_len: {} | resp_status: {} | resp_body_len: {}", + method, + path_str, + url.origin(), + headers, + body.len(), + status, + body_bytes.len() + ); - // Return response (CORS header will be added by warp middleware) Ok(BinaryResponse { body: body_bytes.to_vec(), status }) } \ No newline at end of file