From 497a07d91e2ed27aac6473515c40cac9ab5c25a0 Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Wed, 24 Jul 2024 16:17:17 +0200 Subject: [PATCH 1/5] `core` data sources `view_filter` support (#6475) * list_data_source_documents view filtering * drying a bit * list_data_source_document_versions implementation * stop here * nits * clean-up * parse env_filter as string with GET --- core/bin/dust_api.rs | 66 ++++- core/bin/qdrant/migrate_embedder.rs | 4 +- core/src/data_sources/data_source.rs | 67 ++++- .../src/data_sources/file_storage_document.rs | 1 - core/src/stores/postgres.rs | 270 ++++++++++-------- core/src/stores/store.rs | 2 + 6 files changed, 276 insertions(+), 134 deletions(-) diff --git a/core/bin/dust_api.rs b/core/bin/dust_api.rs index 897cc254e140..85da76e264f7 100644 --- a/core/bin/dust_api.rs +++ b/core/bin/dust_api.rs @@ -1259,6 +1259,7 @@ struct DatasourceSearchPayload { query: Option, top_k: usize, filter: Option, + view_filter: Option, full_text: bool, credentials: run::Credentials, target_document_tokens: Option, @@ -1299,6 +1300,11 @@ async fn data_sources_search( Some(filter) => Some(filter.postprocess_for_data_source(&data_source_id)), None => None, }, + // TODO(spolu): follow_up PR. + // match payload.view_filter { + // Some(filter) => Some(filter.postprocess_for_data_source(&data_source_id)), + // None => None, + // }, payload.full_text, payload.target_document_tokens, ) @@ -1480,8 +1486,8 @@ async fn data_sources_documents_update_parents( struct DataSourcesDocumentsVersionsListQuery { offset: usize, limit: usize, - // hash of the latest version to retrieve - latest_hash: Option, + latest_hash: Option, // Hash of the latest version to retrieve. + view_filter: Option, // Parsed as JSON. } async fn data_sources_documents_versions_list( @@ -1489,6 +1495,23 @@ async fn data_sources_documents_versions_list( State(state): State>, Query(query): Query, ) -> (StatusCode, Json) { + let view_filter: Option = match query + .view_filter + .as_ref() + .and_then(|f| Some(serde_json::from_str(f))) + { + Some(Ok(f)) => Some(f), + None => None, + Some(Err(e)) => { + return error_response( + StatusCode::BAD_REQUEST, + "invalid_view_filter", + "Failed to parse view_filter query parameter", + Some(e.into()), + ) + } + }; + let project = project::Project::new_from_id(project_id); match state .store @@ -1497,6 +1520,10 @@ async fn data_sources_documents_versions_list( &data_source_id, &document_id, Some((query.limit, query.offset)), + &match view_filter { + Some(filter) => Some(filter.postprocess_for_data_source(&data_source_id)), + None => None, + }, &query.latest_hash, ) .await @@ -1626,6 +1653,7 @@ async fn data_sources_documents_upsert( struct DataSourcesListQuery { offset: usize, limit: usize, + view_filter: Option, // Parsed as JSON. } async fn data_sources_documents_list( @@ -1633,6 +1661,23 @@ async fn data_sources_documents_list( State(state): State>, Query(query): Query, ) -> (StatusCode, Json) { + let view_filter: Option = match query + .view_filter + .as_ref() + .and_then(|f| Some(serde_json::from_str(f))) + { + Some(Ok(f)) => Some(f), + None => None, + Some(Err(e)) => { + return error_response( + StatusCode::BAD_REQUEST, + "invalid_view_filter", + "Failed to parse view_filter query parameter", + Some(e.into()), + ) + } + }; + let project = project::Project::new_from_id(project_id); match state .store @@ -1640,6 +1685,10 @@ async fn data_sources_documents_list( &project, &data_source_id, Some((query.limit, query.offset)), + &match view_filter { + Some(filter) => Some(filter.postprocess_for_data_source(&data_source_id)), + None => None, + }, true, // remove system tags ) .await @@ -1669,6 +1718,7 @@ async fn data_sources_documents_list( #[derive(serde::Deserialize)] struct DataSourcesDocumentsRetrieveQuery { version_hash: Option, + view_filter: Option, } async fn data_sources_documents_retrieve( @@ -1696,7 +1746,17 @@ async fn data_sources_documents_retrieve( None, ), Some(ds) => match ds - .retrieve(state.store.clone(), &document_id, true, &query.version_hash) + .retrieve( + state.store.clone(), + &document_id, + true, + // TODO(spolu): follow_up PR. + // match query.view_filter { + // Some(filter) => Some(filter.postprocess_for_data_source(&data_source_id)), + // None => None, + // }, + &query.version_hash, + ) .await { Err(e) => error_response( diff --git a/core/bin/qdrant/migrate_embedder.rs b/core/bin/qdrant/migrate_embedder.rs index 147fa0a1de40..fa70f8fd6d8f 100644 --- a/core/bin/qdrant/migrate_embedder.rs +++ b/core/bin/qdrant/migrate_embedder.rs @@ -624,8 +624,8 @@ async fn refresh_chunk_count_for_updated_documents( let filter = SearchFilter { timestamp: Some(TimestampFilter { - gt: Some(from_timestamp), - lt: Some(now), + gt: Some(from_timestamp as i64), + lt: Some(now as i64), }), tags: None, parents: None, diff --git a/core/src/data_sources/data_source.rs b/core/src/data_sources/data_source.rs index aa98bdd55d7f..c749c9f548ee 100644 --- a/core/src/data_sources/data_source.rs +++ b/core/src/data_sources/data_source.rs @@ -54,8 +54,8 @@ pub struct ParentsFilter { /// timestamp greater than `gt` and less than `lt`. #[derive(Debug, Serialize, Deserialize, Clone)] pub struct TimestampFilter { - pub gt: Option, - pub lt: Option, + pub gt: Option, + pub lt: Option, } // Custom deserializer for `TimestampFilter` @@ -73,8 +73,8 @@ where let f = Option::::deserialize(deserializer)?.map(|inner_filter| { TimestampFilter { - gt: inner_filter.gt.map(|value| value as u64), // Convert f64 to u64 - lt: inner_filter.lt.map(|value| value as u64), // Convert f64 to u64 + gt: inner_filter.gt.map(|value| value as i64), // Convert f64 to u64 + lt: inner_filter.lt.map(|value| value as i64), // Convert f64 to u64 } }); @@ -403,6 +403,65 @@ impl Document { token_count: None, }) } + + pub fn match_filter(&self, filter: Option) -> bool { + match filter { + Some(filter) => { + let mut m = true; + match filter.tags { + Some(tags) => { + m = m + && match &tags.is_in { + Some(is_in) => is_in.iter().any(|tag| self.tags.contains(tag)), + None => true, + }; + m = m + && match &tags.is_not { + Some(is_not) => is_not.iter().all(|tag| !self.tags.contains(tag)), + None => true, + }; + } + None => (), + } + match filter.parents { + Some(parents) => { + m = m + && match &parents.is_in { + Some(is_in) => { + is_in.iter().any(|parent| self.parents.contains(parent)) + } + None => true, + }; + m = m + && match &parents.is_not { + Some(is_not) => { + is_not.iter().all(|parent| !self.parents.contains(parent)) + } + None => true, + }; + } + None => (), + } + match filter.timestamp { + Some(timestamp) => { + m = m + && match timestamp.gt { + Some(gt) => self.timestamp as i64 >= gt, + None => true, + }; + m = m + && match timestamp.lt { + Some(lt) => self.timestamp as i64 <= lt, + None => true, + }; + } + None => (), + } + m + } + None => true, + } + } } pub fn make_document_id_hash(document_id: &str) -> String { diff --git a/core/src/data_sources/file_storage_document.rs b/core/src/data_sources/file_storage_document.rs index 4a459c619772..59a93e8529e1 100644 --- a/core/src/data_sources/file_storage_document.rs +++ b/core/src/data_sources/file_storage_document.rs @@ -1,7 +1,6 @@ use anyhow::{anyhow, Result}; use cloud_storage::Object; use serde::{Deserialize, Serialize}; -use tokio::try_join; use tracing::info; use crate::utils; diff --git a/core/src/stores/postgres.rs b/core/src/stores/postgres.rs index 28b166885c34..4dc04a0ec478 100644 --- a/core/src/stores/postgres.rs +++ b/core/src/stores/postgres.rs @@ -68,6 +68,58 @@ impl PostgresStore { Ok(()) } + + fn where_clauses_and_params_for_filter<'a>( + filter: &'a Option, + from_idx: usize, + ) -> (Vec, Vec<&'a (dyn ToSql + Sync)>, usize) { + let mut where_clauses: Vec = vec![]; + let mut params: Vec<&'a (dyn ToSql + Sync)> = vec![]; + let mut p_idx: usize = from_idx; + + if let Some(filter) = filter { + if let Some(tags_filter) = &filter.tags { + if let Some(tags) = &tags_filter.is_in { + where_clauses.push(format!("tags_array && ${}", p_idx)); + params.push(tags as &(dyn ToSql + Sync)); + p_idx += 1; + } + if let Some(tags) = &tags_filter.is_not { + where_clauses.push(format!("NOT tags_array && ${}", p_idx)); + params.push(tags as &(dyn ToSql + Sync)); + p_idx += 1; + } + } + + if let Some(parents_filter) = &filter.parents { + if let Some(parents) = &parents_filter.is_in { + where_clauses.push(format!("parents && ${}", p_idx)); + params.push(parents as &(dyn ToSql + Sync)); + p_idx += 1; + } + if let Some(parents) = &parents_filter.is_not { + where_clauses.push(format!("NOT parents && ${}", p_idx)); + params.push(parents as &(dyn ToSql + Sync)); + p_idx += 1; + } + } + + if let Some(ts_filter) = &filter.timestamp { + if let Some(ts) = ts_filter.gt.as_ref() { + where_clauses.push(format!("timestamp > ${}", p_idx)); + params.push(ts as &(dyn ToSql + Sync)); + p_idx += 1; + } + if let Some(ts) = ts_filter.lt.as_ref() { + where_clauses.push(format!("timestamp < ${}", p_idx)); + params.push(ts as &(dyn ToSql + Sync)); + p_idx += 1; + } + } + } + + (where_clauses, params, p_idx) + } } #[async_trait] @@ -1405,6 +1457,7 @@ impl Store for PostgresStore { data_source_id: &str, document_id: &str, limit_offset: Option<(usize, usize)>, + view_filter: &Option, latest_hash: &Option, ) -> Result<(Vec, usize)> { let project_id = project.project_id(); @@ -1434,7 +1487,7 @@ impl Store for PostgresStore { let stmt = c .prepare( "SELECT created FROM data_sources_documents \ - WHERE data_source = $1 AND document_id = $2 AND hash = $3 LIMIT 1", + WHERE data_source = $1 AND document_id = $2 AND hash = $3 LIMIT 1", ) .await?; let r = c @@ -1452,7 +1505,8 @@ impl Store for PostgresStore { let stmt = c .prepare( "SELECT created FROM data_sources_documents \ - WHERE data_source = $1 AND document_id = $2 AND status = 'latest' LIMIT 1", + WHERE data_source = $1 AND document_id = $2 \ + AND status = 'latest' LIMIT 1", ) .await?; let r = c.query(&stmt, &[&data_source_row_id, &document_id]).await?; @@ -1464,40 +1518,45 @@ impl Store for PostgresStore { } }; + let mut where_clauses: Vec = vec![]; + let mut params: Vec<&(dyn ToSql + Sync)> = vec![]; + + where_clauses.push("data_source = $1".to_string()); + params.push(&data_source_row_id); + where_clauses.push("document_id = $2".to_string()); + params.push(&document_id); + where_clauses.push("created <= $3'".to_string()); + params.push(&latest_hash_created); + + let (filter_clauses, filter_params, p_idx) = + Self::where_clauses_and_params_for_filter(view_filter, params.len() + 1); + + where_clauses.extend(filter_clauses); + params.extend(filter_params); + + let sql = format!( + "SELECT hash, created FROM data_sources_documents \ + WHERE {} ORDER BY created DESC", + where_clauses.join(" AND ") + ); + let rows = match limit_offset { None => { - let stmt = c - .prepare( - "SELECT hash, created FROM data_sources_documents \ - WHERE data_source = $1 AND document_id = $2 AND created <= $3 \ - ORDER BY created DESC", - ) - .await?; - c.query( - &stmt, - &[&data_source_row_id, &document_id, &latest_hash_created], - ) - .await? + let stmt = c.prepare(&sql).await?; + c.query(&stmt, ¶ms).await? } Some((limit, offset)) => { + let limit = limit as i64; + let offset = offset as i64; + + let mut params = params.clone(); + params.push(&limit); + params.push(&offset); + let stmt = c - .prepare( - "SELECT hash, created FROM data_sources_documents \ - WHERE data_source = $1 AND document_id = $2 AND created <= $3 \ - ORDER BY created DESC LIMIT $4 OFFSET $5", - ) + .prepare(&(sql + &format!(" LIMIT ${} OFFSET ${}", p_idx, p_idx + 1))) .await?; - c.query( - &stmt, - &[ - &data_source_row_id, - &document_id, - &latest_hash_created, - &(limit as i64), - &(offset as i64), - ], - ) - .await? + c.query(&stmt, ¶ms).await? } }; @@ -1516,14 +1575,14 @@ impl Store for PostgresStore { Some(_) => { let stmt = c .prepare( - "SELECT COUNT(*) FROM data_sources_documents \ - WHERE data_source = $1 AND document_id = $2", + format!( + "SELECT COUNT(*) FROM data_sources_documents WHERE {}", + where_clauses.join(" AND ") + ) + .as_str(), ) .await?; - let t: i64 = c - .query_one(&stmt, &[&data_source_row_id, &document_id]) - .await? - .get(0); + let t: i64 = c.query_one(&stmt, ¶ms).await?.get(0); t as usize } }; @@ -1546,89 +1605,35 @@ impl Store for PostgresStore { let mut where_clauses: Vec = vec![]; let mut params: Vec<&(dyn ToSql + Sync)> = vec![]; - let data_source_internal_id_rows = c + let r = c .query_one( "SELECT id FROM data_sources WHERE project = $1 AND data_source_id = $2", &[&project_id, &data_source_id], ) .await?; - let data_source_internal_id: i64 = data_source_internal_id_rows.get(0); + let data_source_row_id: i64 = r.get(0); where_clauses.push("data_source = $1".to_string()); - params.push(&data_source_internal_id); - - let mut p_idx: usize = 2; - - let tags_is_in: Vec; - let tags_is_not: Vec; - let parents_is_in: Vec; - let parents_is_not: Vec; - let ts_gt: i64; - let ts_lt: i64; - - if let Some(filter) = filter { - if let Some(tags_filter) = &filter.tags { - if let Some(tags) = &tags_filter.is_in { - tags_is_in = tags.to_vec(); - where_clauses.push(format!("tags_array && ${}", p_idx)); - params.push(&tags_is_in); - p_idx += 1; - } - if let Some(tags) = &tags_filter.is_not { - tags_is_not = tags.to_vec(); - where_clauses.push(format!("NOT tags_array && ${}", p_idx)); - params.push(&tags_is_not); - p_idx += 1; - } - } - - if let Some(parents_filter) = &filter.parents { - if let Some(parents) = &parents_filter.is_in { - parents_is_in = parents.to_vec(); - where_clauses.push(format!("parents && ${}", p_idx)); - params.push(&parents_is_in); - p_idx += 1; - } - if let Some(parents) = &parents_filter.is_not { - parents_is_not = parents.to_vec(); - where_clauses.push(format!("NOT parents && ${}", p_idx)); - params.push(&parents_is_not); - p_idx += 1; - } - } - - if let Some(ts_filter) = &filter.timestamp { - if let Some(ts) = ts_filter.gt { - where_clauses.push(format!("timestamp > ${}", p_idx)); - ts_gt = ts as i64; - params.push(&ts_gt); - p_idx += 1; - } - if let Some(ts) = ts_filter.lt { - where_clauses.push(format!("timestamp < ${}", p_idx)); - ts_lt = ts as i64; - params.push(&ts_lt); - p_idx += 1; - } - } - } - + params.push(&data_source_row_id); where_clauses.push("status = 'latest'".to_string()); - let serialized_where_clauses = where_clauses.join(" AND "); + let (filter_clauses, filter_params, p_idx) = + Self::where_clauses_and_params_for_filter(filter, params.len() + 1); + + where_clauses.extend(filter_clauses); + params.extend(filter_params); // compute the total count let count_query = format!( "SELECT COUNT(*) FROM data_sources_documents WHERE {}", - serialized_where_clauses + where_clauses.join(" AND ") ); let count: i64 = c.query_one(&count_query, ¶ms).await?.get(0); let mut query = format!( - "SELECT document_id FROM data_sources_documents \ - WHERE {} ORDER BY timestamp DESC", - serialized_where_clauses + "SELECT document_id FROM data_sources_documents WHERE {} ORDER BY timestamp DESC", + where_clauses.join(" AND ") ); let limit: i64; @@ -1731,6 +1736,7 @@ impl Store for PostgresStore { project: &Project, data_source_id: &str, limit_offset: Option<(usize, usize)>, + view_filter: &Option, remove_system_tags: bool, ) -> Result<(Vec, usize)> { let project_id = project.project_id(); @@ -1752,32 +1758,44 @@ impl Store for PostgresStore { _ => unreachable!(), }; + let mut where_clauses: Vec = vec![]; + let mut params: Vec<&(dyn ToSql + Sync)> = vec![]; + + where_clauses.push("data_source = $1".to_string()); + params.push(&data_source_row_id); + where_clauses.push("status = 'latest'".to_string()); + + let (filter_clauses, filter_params, p_idx) = + Self::where_clauses_and_params_for_filter(view_filter, params.len() + 1); + + where_clauses.extend(filter_clauses); + params.extend(filter_params); + + let sql = format!( + "SELECT id, created, document_id, timestamp, tags_array, parents, source_url, hash, \ + text_size, chunk_count \ + FROM data_sources_documents \ + WHERE {} ORDER BY timestamp DESC", + where_clauses.join(" AND "), + ); + let rows = match limit_offset { None => { - let stmt = c - .prepare( - "SELECT id, created, document_id, timestamp, tags_array, parents, source_url, hash, text_size, \ - chunk_count FROM data_sources_documents \ - WHERE data_source = $1 AND status = 'latest' \ - ORDER BY timestamp DESC", - ) - .await?; - c.query(&stmt, &[&data_source_row_id]).await? + let stmt = c.prepare(&sql).await?; + c.query(&stmt, ¶ms).await? } Some((limit, offset)) => { + let limit = limit as i64; + let offset = offset as i64; + + let mut params = params.clone(); + params.push(&limit); + params.push(&offset); + let stmt = c - .prepare( - "SELECT id, created, document_id, timestamp, tags_array, parents, source_url, hash, text_size, \ - chunk_count FROM data_sources_documents \ - WHERE data_source = $1 AND status = 'latest' \ - ORDER BY timestamp DESC LIMIT $2 OFFSET $3", - ) + .prepare(&(sql + &format!(" LIMIT ${} OFFSET ${}", p_idx, p_idx + 1))) .await?; - c.query( - &stmt, - &[&data_source_row_id, &(limit as i64), &(offset as i64)], - ) - .await? + c.query(&stmt, ¶ms).await? } }; @@ -1826,11 +1844,15 @@ impl Store for PostgresStore { Some(_) => { let stmt = c .prepare( - "SELECT COUNT(*) FROM data_sources_documents \ - WHERE data_source = $1 AND status = 'latest'", + format!( + "SELECT COUNT(*) FROM data_sources_documents \ + WHERE {}", + where_clauses.join(" AND ") + ) + .as_str(), ) .await?; - let t: i64 = c.query_one(&stmt, &[&data_source_row_id]).await?.get(0); + let t: i64 = c.query_one(&stmt, ¶ms).await?.get(0); t as usize } }; diff --git a/core/src/stores/store.rs b/core/src/stores/store.rs index 1bedc000a29b..2aa34026eee4 100644 --- a/core/src/stores/store.rs +++ b/core/src/stores/store.rs @@ -154,6 +154,7 @@ pub trait Store { data_source_id: &str, document_id: &str, limit_offset: Option<(usize, usize)>, + view_filter: &Option, latest_hash: &Option, ) -> Result<(Vec, usize)>; async fn list_data_source_documents( @@ -161,6 +162,7 @@ pub trait Store { project: &Project, data_source_id: &str, limit_offset: Option<(usize, usize)>, + view_filter: &Option, remove_system_tags: bool, ) -> Result<(Vec, usize)>; async fn delete_data_source_document( From 557ca2d95845d619efc96f3d3f50e08ceb170fba Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Wed, 24 Jul 2024 16:52:09 +0200 Subject: [PATCH 2/5] Groups: core data_sources_documents_retrieve view filtering (#6488) * Groups: core data_sources_documents_retrieve view filtering * fix --- core/bin/dust_api.rs | 9 ++++----- core/src/data_sources/data_source.rs | 16 +++++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/core/bin/dust_api.rs b/core/bin/dust_api.rs index 85da76e264f7..1fba517708db 100644 --- a/core/bin/dust_api.rs +++ b/core/bin/dust_api.rs @@ -1749,12 +1749,11 @@ async fn data_sources_documents_retrieve( .retrieve( state.store.clone(), &document_id, + &match query.view_filter { + Some(filter) => Some(filter.postprocess_for_data_source(&data_source_id)), + None => None, + }, true, - // TODO(spolu): follow_up PR. - // match query.view_filter { - // Some(filter) => Some(filter.postprocess_for_data_source(&data_source_id)), - // None => None, - // }, &query.version_hash, ) .await diff --git a/core/src/data_sources/data_source.rs b/core/src/data_sources/data_source.rs index c749c9f548ee..64023d3772d9 100644 --- a/core/src/data_sources/data_source.rs +++ b/core/src/data_sources/data_source.rs @@ -404,11 +404,11 @@ impl Document { }) } - pub fn match_filter(&self, filter: Option) -> bool { - match filter { + pub fn match_filter(&self, filter: &Option) -> bool { + match &filter { Some(filter) => { let mut m = true; - match filter.tags { + match &filter.tags { Some(tags) => { m = m && match &tags.is_in { @@ -423,7 +423,7 @@ impl Document { } None => (), } - match filter.parents { + match &filter.parents { Some(parents) => { m = m && match &parents.is_in { @@ -442,7 +442,7 @@ impl Document { } None => (), } - match filter.timestamp { + match &filter.timestamp { Some(timestamp) => { m = m && match timestamp.gt { @@ -1815,6 +1815,7 @@ impl DataSource { &self, store: Box, document_id: &str, + view_filter: &Option, remove_system_tags: bool, version_hash: &Option, ) -> Result> { @@ -1835,6 +1836,11 @@ impl DataSource { } }; + // If the view_filter does not match the document we return as if it didn't exist. + if !d.match_filter(view_filter) { + return Ok(None); + } + d.tags = if remove_system_tags { // remove tags that are prefixed with the system tag prefix d.tags From 5afc22270e88db8df8bb2846dbd0fc9245837618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daphn=C3=A9=20Popin?= Date: Wed, 24 Jul 2024 17:50:21 +0200 Subject: [PATCH 3/5] Add Groups resource (#6474) * Add Groups resource * Apply feedback * Apply feedback * Feedabck again --- front/admin/db.ts | 3 + front/lib/resources/group_resource.ts | 121 +++++++++++++++++++ front/lib/resources/storage/models/groups.ts | 85 +++++++++++++ front/lib/resources/string_ids.ts | 1 + front/migrations/db/migration_45.sql | 11 ++ types/src/front/groups.ts | 9 ++ types/src/index.ts | 1 + 7 files changed, 231 insertions(+) create mode 100644 front/lib/resources/group_resource.ts create mode 100644 front/lib/resources/storage/models/groups.ts create mode 100644 front/migrations/db/migration_45.sql create mode 100644 types/src/front/groups.ts diff --git a/front/admin/db.ts b/front/admin/db.ts index 99767470f0a8..97534959b752 100644 --- a/front/admin/db.ts +++ b/front/admin/db.ts @@ -65,6 +65,7 @@ import { } from "@app/lib/models/workspace"; import { ContentFragmentModel } from "@app/lib/resources/storage/models/content_fragment"; import { FileModel } from "@app/lib/resources/storage/models/files"; +import { GroupModel } from "@app/lib/resources/storage/models/groups"; import { KeyModel } from "@app/lib/resources/storage/models/keys"; // Labs - Can be removed at all times if a solution is dropped import { @@ -90,6 +91,8 @@ async function main() { await WorkspaceHasDomain.sync({ alter: true }); await MembershipModel.sync({ alter: true }); await MembershipInvitation.sync({ alter: true }); + await GroupModel.sync({ alter: true }); + await App.sync({ alter: true }); await Dataset.sync({ alter: true }); await Provider.sync({ alter: true }); diff --git a/front/lib/resources/group_resource.ts b/front/lib/resources/group_resource.ts new file mode 100644 index 000000000000..c3431d03de90 --- /dev/null +++ b/front/lib/resources/group_resource.ts @@ -0,0 +1,121 @@ +import type { ModelId, Result } from "@dust-tt/types"; +import { Err, Ok } from "@dust-tt/types"; +import type { + Attributes, + CreationAttributes, + ModelStatic, + Transaction, +} from "sequelize"; + +import type { Authenticator } from "@app/lib/auth"; +import { BaseResource } from "@app/lib/resources/base_resource"; +import { GroupModel } from "@app/lib/resources/storage/models/groups"; +import type { ReadonlyAttributesType } from "@app/lib/resources/storage/types"; +import { getResourceIdFromSId, makeSId } from "@app/lib/resources/string_ids"; + +// Attributes are marked as read-only to reflect the stateless nature of our Resource. +// This design will be moved up to BaseResource once we transition away from Sequelize. +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-unsafe-declaration-merging +export interface GroupResource extends ReadonlyAttributesType {} +// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging +export class GroupResource extends BaseResource { + static model: ModelStatic = GroupModel; + + constructor(model: ModelStatic, blob: Attributes) { + super(GroupModel, blob); + } + + static async makeNew(blob: CreationAttributes) { + const group = await GroupModel.create(blob); + + return new this(GroupModel, group.get()); + } + + get sId(): string { + return GroupResource.modelIdToSId({ + id: this.id, + workspaceId: this.workspaceId, + }); + } + + static modelIdToSId({ + id, + workspaceId, + }: { + id: ModelId; + workspaceId: ModelId; + }): string { + return makeSId("group", { + id, + workspaceId, + }); + } + + async delete( + auth: Authenticator, + transaction?: Transaction + ): Promise> { + try { + await this.model.destroy({ + where: { + id: this.id, + }, + transaction, + }); + + return new Ok(undefined); + } catch (err) { + return new Err(err as Error); + } + } + + static async fetchById( + auth: Authenticator, + sId: string + ): Promise { + const owner = auth.getNonNullableWorkspace(); + + const groupModelId = getResourceIdFromSId(sId); + if (!groupModelId) { + return null; + } + + const blob = await this.model.findOne({ + where: { + id: groupModelId, + workspaceId: owner.id, + }, + }); + if (!blob) { + return null; + } + + // Use `.get` to extract model attributes, omitting Sequelize instance metadata. + return new this(this.model, blob.get()); + } + + static async fetchByAuthWorkspace( + auth: Authenticator, + transaction?: Transaction + ): Promise { + const owner = auth.getNonNullableWorkspace(); + + const groups = await this.model.findAll({ + where: { + workspaceId: owner.id, + }, + transaction, + }); + + return groups.map((group) => new this(GroupModel, group.get())); + } + + toJSON() { + return { + id: this.id, + name: this.name, + workspaceId: this.workspaceId, + type: this.type, + }; + } +} diff --git a/front/lib/resources/storage/models/groups.ts b/front/lib/resources/storage/models/groups.ts new file mode 100644 index 000000000000..6d0e87764f14 --- /dev/null +++ b/front/lib/resources/storage/models/groups.ts @@ -0,0 +1,85 @@ +import type { GroupType } from "@dust-tt/types"; +import { isSystemGroupType } from "@dust-tt/types"; +import type { + CreationOptional, + ForeignKey, + InferAttributes, + InferCreationAttributes, + Transaction, +} from "sequelize"; +import { DataTypes, Model } from "sequelize"; + +import { Workspace } from "@app/lib/models/workspace"; +import { frontSequelize } from "@app/lib/resources/storage"; + +export class GroupModel extends Model< + InferAttributes, + InferCreationAttributes +> { + declare id: CreationOptional; + declare createdAt: CreationOptional; + declare updatedAt: CreationOptional; + + declare name: string; + declare type: GroupType; + + declare workspaceId: ForeignKey; +} +GroupModel.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + }, + name: { + type: DataTypes.STRING, + allowNull: false, + }, + type: { + type: DataTypes.STRING, + allowNull: false, + }, + }, + { + modelName: "groups", + sequelize: frontSequelize, + indexes: [{ unique: true, fields: ["workspaceId", "name"] }], + } +); + +GroupModel.addHook( + "beforeSave", + "enforce_one_system_group_per_workspace", + async (group: GroupModel, options: { transaction: Transaction }) => { + if (isSystemGroupType(group.type)) { + const existingSystemGroupType = await GroupModel.findOne({ + where: { + workspaceId: group.workspaceId, + type: group.type, + }, + transaction: options.transaction, + }); + + if (existingSystemGroupType) { + throw new Error("A system group exists for this workspace."); + } + } + } +); + +Workspace.hasMany(GroupModel, { + foreignKey: { allowNull: false }, + onDelete: "RESTRICT", +}); +GroupModel.belongsTo(Workspace); diff --git a/front/lib/resources/string_ids.ts b/front/lib/resources/string_ids.ts index 32ca39ea192a..75ddfcfd4a2f 100644 --- a/front/lib/resources/string_ids.ts +++ b/front/lib/resources/string_ids.ts @@ -20,6 +20,7 @@ const REGION = 1; // US. const RESOURCES_PREFIX = { file: "fil", + group: "grp", }; const ALL_RESOURCES_PREFIXES = Object.values(RESOURCES_PREFIX); diff --git a/front/migrations/db/migration_45.sql b/front/migrations/db/migration_45.sql new file mode 100644 index 000000000000..42e540f51682 --- /dev/null +++ b/front/migrations/db/migration_45.sql @@ -0,0 +1,11 @@ +-- Migration created on Jul 24, 2024 +CREATE TABLE IF NOT EXISTS "groups" ( + "id" SERIAL , + "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, + "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, + "name" VARCHAR(255) NOT NULL, + "type" VARCHAR(255) NOT NULL, + "workspaceId" INTEGER NOT NULL REFERENCES "workspaces" ("id") ON DELETE RESTRICT ON UPDATE CASCADE, + PRIMARY KEY ("id") +); +CREATE UNIQUE INDEX "groups_workspace_id_name" ON "groups" ("workspaceId", "name"); diff --git a/types/src/front/groups.ts b/types/src/front/groups.ts new file mode 100644 index 000000000000..0c1828428f51 --- /dev/null +++ b/types/src/front/groups.ts @@ -0,0 +1,9 @@ +export const GROUP_TYPES = ["regular", "workspace", "system"] as const; +export type GroupType = (typeof GROUP_TYPES)[number]; + +export function isValidGroupType(value: unknown): value is GroupType { + return GROUP_TYPES.includes(value as GroupType); +} +export function isSystemGroupType(value: GroupType): boolean { + return value === "system"; +} diff --git a/types/src/index.ts b/types/src/index.ts index 8fc8907be3ba..cfd9549301eb 100644 --- a/types/src/index.ts +++ b/types/src/index.ts @@ -37,6 +37,7 @@ export * from "./front/dataset"; export * from "./front/document"; export * from "./front/dust_app_secret"; export * from "./front/files"; +export * from "./front/groups"; export * from "./front/key"; export * from "./front/lib/actions/registry"; export * from "./front/lib/actions/types"; From e661a018a79956042b5f9c4ca3f5c56134b7448a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daphn=C3=A9=20Popin?= Date: Wed, 24 Jul 2024 18:47:18 +0200 Subject: [PATCH 4/5] Assistant Builder: Claude sonnet default (#6492) --- front/components/assistant_builder/AssistantBuilder.tsx | 4 ++-- front/components/assistant_builder/types.ts | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/front/components/assistant_builder/AssistantBuilder.tsx b/front/components/assistant_builder/AssistantBuilder.tsx index ad49c3c017a9..879fc3188e78 100644 --- a/front/components/assistant_builder/AssistantBuilder.tsx +++ b/front/components/assistant_builder/AssistantBuilder.tsx @@ -16,8 +16,8 @@ import type { } from "@dust-tt/types"; import { assertNever, + CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG, GPT_3_5_TURBO_MODEL_CONFIG, - GPT_4_TURBO_MODEL_CONFIG, isBuilder, SUPPORTED_MODEL_CONFIGS, } from "@dust-tt/types"; @@ -124,7 +124,7 @@ export default function AssistantBuilder({ ...getDefaultAssistantState().generationSettings, modelSettings: !isUpgraded(plan) ? GPT_3_5_TURBO_MODEL_CONFIG - : GPT_4_TURBO_MODEL_CONFIG, + : CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG, }, } ); diff --git a/front/components/assistant_builder/types.ts b/front/components/assistant_builder/types.ts index eaa1b86cb8a0..ed2ccb8cc735 100644 --- a/front/components/assistant_builder/types.ts +++ b/front/components/assistant_builder/types.ts @@ -11,7 +11,10 @@ import type { TimeframeUnit, WorkspaceType, } from "@dust-tt/types"; -import { assertNever, GPT_4_TURBO_MODEL_CONFIG } from "@dust-tt/types"; +import { + assertNever, + CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG, +} from "@dust-tt/types"; import { DEFAULT_PROCESS_ACTION_NAME, @@ -200,8 +203,8 @@ export function getDefaultAssistantState() { avatarUrl: null, generationSettings: { modelSettings: { - modelId: GPT_4_TURBO_MODEL_CONFIG.modelId, - providerId: GPT_4_TURBO_MODEL_CONFIG.providerId, + modelId: CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG.modelId, + providerId: CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG.providerId, }, temperature: 0.7, }, From 42d85e4ec778295bfbed7c5a4a4163ee36814b7a Mon Sep 17 00:00:00 2001 From: Flavien David Date: Wed, 24 Jul 2024 22:49:57 +0200 Subject: [PATCH 5/5] Visualization foundations (#6489) * Create .nvmrc * Add foundations for viz * :sparkles: * :see_no_evil: * :see_no_evil: * Fix useFile hook * :scissors: * Remove Sparkle from viz --- .../front/assistant/actions/visualization.ts | 42 + viz/.eslintrc.json | 11 +- viz/.nvmrc | 1 + viz/app/components/Components.tsx | 58 ++ viz/app/components/VisualizationWrapper.tsx | 312 +++++++ viz/app/content/page.tsx | 14 + viz/app/globals.css | 2 + viz/next.config.mjs | 23 +- viz/package-lock.json | 777 ++++++++++++++++-- viz/package.json | 16 +- viz/tailwind.config.ts | 5 + 11 files changed, 1180 insertions(+), 81 deletions(-) create mode 100644 viz/.nvmrc create mode 100644 viz/app/components/Components.tsx create mode 100644 viz/app/components/VisualizationWrapper.tsx create mode 100644 viz/app/content/page.tsx diff --git a/types/src/front/assistant/actions/visualization.ts b/types/src/front/assistant/actions/visualization.ts index 3873bdbb7575..798f697c308c 100644 --- a/types/src/front/assistant/actions/visualization.ts +++ b/types/src/front/assistant/actions/visualization.ts @@ -25,3 +25,45 @@ export interface VisualizationActionType extends BaseAction { export const VisualizationActionOutputSchema = t.type({ generation: t.string, }); + +export function visualizationExtractCodeNonStreaming(code: string) { + const regex = /]*>\s*([\s\S]*?)\s*<\/visualization>/; + let extractedCode: string | null = null; + const match = code.match(regex); + if (match && match[1]) { + extractedCode = match[1]; + } + if (!extractedCode) { + return null; + } + return extractedCode; +} + +export function visualizationExtractCodeStreaming(code: string) { + const startOffset = code.indexOf(">"); + if (startOffset === -1) { + return null; + } + const endOffset = code.indexOf(""); + if (endOffset === -1) { + return code.substring(startOffset + 1); + } else { + return code.substring(startOffset + 1, endOffset); + } +} + +export function visualizationExtractCode(code: string) { + return ( + visualizationExtractCodeNonStreaming(code) || + visualizationExtractCodeStreaming(code) + ); +} + +// This defines the commands that the iframe can send to the host window. +export type VisualizationRPCCommand = "getCodeToExecute" | "retry" | "getFile"; +export type VisualizationRPCRequest = { + command: VisualizationRPCCommand; + messageUniqueId: string; + actionId: number; + params: unknown; +}; diff --git a/viz/.eslintrc.json b/viz/.eslintrc.json index bffb357a7122..3faa07b9a705 100644 --- a/viz/.eslintrc.json +++ b/viz/.eslintrc.json @@ -1,3 +1,12 @@ { - "extends": "next/core-web-vitals" + "extends": [ + "next/core-web-vitals", + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "eqeqeq": "error", + "no-unused-vars": "error", + "@typescript-eslint/no-explicit-any": "error" + } } diff --git a/viz/.nvmrc b/viz/.nvmrc new file mode 100644 index 000000000000..62d44807d084 --- /dev/null +++ b/viz/.nvmrc @@ -0,0 +1 @@ +20.13.0 diff --git a/viz/app/components/Components.tsx b/viz/app/components/Components.tsx new file mode 100644 index 000000000000..44f0653e5d77 --- /dev/null +++ b/viz/app/components/Components.tsx @@ -0,0 +1,58 @@ +"use client"; + +// We can't use Sparkle components in the viz app, +// because of client-side rendering issue. +// So we define the components here. + +export const Button = ({ + label, + onClick, +}: { + label: string; + onClick: () => void; +}) => { + return ( + + ); +}; + +export const ErrorMessage = ({ + children, + title, +}: { + children: React.ReactNode; + title: string; +}) => { + return ( +
+
+ + + +

{title}

+
+
{children}
+
+ ); +}; + +export const Spinner = () => { + return ( +
+
+
+ ); +}; diff --git a/viz/app/components/VisualizationWrapper.tsx b/viz/app/components/VisualizationWrapper.tsx new file mode 100644 index 000000000000..4b8989121e02 --- /dev/null +++ b/viz/app/components/VisualizationWrapper.tsx @@ -0,0 +1,312 @@ +"use client"; + +import type { + VisualizationRPCCommand, + VisualizationRPCRequest, +} from "@dust-tt/types"; +import { Button, ErrorMessage, Spinner } from "@viz/app/components/Components"; +import * as papaparseAll from "papaparse"; +import * as reactAll from "react"; +import React, { useCallback } from "react"; +import { useEffect, useState } from "react"; +import { importCode, Runner } from "react-runner"; +import {} from "react-runner"; +import * as rechartsAll from "recharts"; + +// We can't import functions from the types package, so we define them here. +function visualizationExtractCodeNonStreaming(code: string) { + const regex = /]*>\s*([\s\S]*?)\s*<\/visualization>/; + let extractedCode: string | null = null; + const match = code.match(regex); + if (match && match[1]) { + extractedCode = match[1]; + } + if (!extractedCode) { + return null; + } + return extractedCode; +} + +export function useVisualizationAPI(actionId: number) { + const [error, setError] = useState(null); + + const fetchCode = useCallback(async (): Promise => { + const getCode = makeIframeMessagePassingFunction< + { actionId: number }, + { code?: string } + >("getCodeToExecute", actionId); + try { + const result = await getCode({ actionId }); + + const extractedCode = visualizationExtractCodeNonStreaming( + result.code ?? "" + ); + if (!extractedCode) { + setError(new Error("Failed to extract visualization code.")); + return null; + } + + return extractedCode; + } catch (error) { + console.error(error); + setError( + error instanceof Error + ? error + : new Error("Failed to fetch visualization code.") + ); + + return null; + } + }, [actionId]); + + const fetchFile = useCallback( + async (fileId: string): Promise => { + const getFile = makeIframeMessagePassingFunction< + { fileId: string }, + { file?: File } + >("getFile", actionId); + const res = await getFile({ fileId }); + + if (!res.file) { + setError(new Error("Failed to fetch file.")); + return null; + } + + return res.file; + }, + [actionId] + ); + + // This retry function sends a command to the host window requesting a retry of a previous + // operation, typically if the generated code fails. + const retry = useCallback(async (): Promise => { + const sendRetry = makeIframeMessagePassingFunction("retry", actionId); + // TODO(2024-07-24 flav) Pass the error message to the host window. + await sendRetry({}); + }, [actionId]); + + return { fetchCode, fetchFile, error, retry }; +} + +// This function creates a function that sends a command to the host window with templated Input and Output types. +function makeIframeMessagePassingFunction( + methodName: VisualizationRPCCommand, + actionId: number +) { + return (params?: Params) => { + return new Promise((resolve, reject) => { + const messageUniqueId = Math.random().toString(); + const listener = (event: MessageEvent) => { + if (event.data.messageUniqueId === messageUniqueId) { + if (event.data.error) { + reject(event.data.error); + } else { + resolve(event.data.result); + } + window.removeEventListener("message", listener); + } + }; + window.addEventListener("message", listener); + window.top?.postMessage( + { + command: methodName, + messageUniqueId, + actionId, + params, + } satisfies VisualizationRPCRequest, + "*" + ); + }); + }; +} + +const useFile = (actionId: number, fileId: string) => { + const [file, setFile] = useState(null); + + const { fetchFile } = useVisualizationAPI(actionId); // Adjust the import based on your project structure + + useEffect(() => { + const fetch = async () => { + try { + const fetchedFile = await fetchFile(fileId); + setFile(fetchedFile); + } catch (err) { + setFile(null); + } + }; + + if (fileId) { + fetch(); + } + }, [fileId, fetchFile]); + + return file; +}; + +// This component renders the generated code. +// It gets the generated code via message passing to the host window. +export function VisualizationWrapper({ actionId }: { actionId: string }) { + const [code, setCode] = useState(null); + const [errored, setErrored] = useState(null); + const actionIdParsed = parseInt(actionId, 10); + + const { fetchCode, error, retry } = useVisualizationAPI(actionIdParsed); + const useFileWrapped = (fileId: string) => useFile(actionIdParsed, fileId); + + useEffect(() => { + const loadCode = async () => { + try { + const fetchedCode = await fetchCode(); + if (fetchedCode) { + setCode(fetchedCode); + } else { + setErrored(new Error("No visualization code found")); + } + } catch (error) { + console.error(error); + setErrored(new Error("Failed to fetch visualization code")); + } + }; + + loadCode(); + }, [fetchCode]); + + // Sync the Visualization API error with the local state. + useEffect(() => { + if (error) { + setErrored(error); + } + }, [error]); + + if (errored) { + return retry()} />; + } + + if (!code) { + return ; + } + + const generatedCodeScope = { + recharts: rechartsAll, + react: reactAll, + papaparse: papaparseAll, + "@dust/react-hooks": { useFile: useFileWrapped }, + }; + + const scope = { + import: { + recharts: rechartsAll, + react: reactAll, + // Here we expose the code generated as a module to be imported by the wrapper code below. + "@dust/generated-code": importCode(code, { import: generatedCodeScope }), + }, + }; + + // This code imports and renders the generated code. + const wrapperCode = ` + () => { + import Comp from '@dust/generated-code'; + + return (); + } + `; + + return ( + { + if (error) { + setErrored(error); + } + }} + /> + ); +} + +// This is the component to render when an error occurs. +function VisualizationError({ + error, + retry, +}: { + error: Error; + retry: () => void; +}) { + const [showDetails, setShowDetails] = useState(false); + + return ( +
+ + <> + We encountered an error while running the code generated above. You + can try again by clicking the button below. +
+ + {showDetails && ( +
+ Error message: {error.message} +
+ )} +
+ +
+
+
+
+ ); +} + +type ErrorBoundaryProps = { + actionId: string; +}; + +type ErrorBoundaryState = { + hasError: boolean; + error: unknown; +}; + +// This is the error boundary component that wraps the VisualizationWrapper component. +// It needs to be a class component for error handling to work. +export class VisualizationWrapperWithErrorHandling extends React.Component< + ErrorBoundaryProps, + ErrorBoundaryState +> { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { hasError: false, error: null }; + } + + static getDerivedStateFromError() { + // Update state so the next render will show the fallback UI. + return { hasError: true }; + } + + componentDidCatch(error: unknown) { + this.setState({ hasError: true, error }); + } + + render() { + if (this.state.hasError) { + let error: Error; + if (this.state.error instanceof Error) { + error = this.state.error; + } else { + error = new Error("Unknown error."); + } + + const retry = makeIframeMessagePassingFunction( + "retry", + parseInt(this.props.actionId, 10) + ); + return retry} />; + } + + return ; + } +} diff --git a/viz/app/content/page.tsx b/viz/app/content/page.tsx new file mode 100644 index 000000000000..e01902cc6aa9 --- /dev/null +++ b/viz/app/content/page.tsx @@ -0,0 +1,14 @@ +import { VisualizationWrapperWithErrorHandling } from "@viz/app/components/VisualizationWrapper"; + +type IframeProps = { + wId: string; + aId: string; +}; + +export default function Iframe({ + searchParams, +}: { + searchParams: IframeProps; +}) { + return ; +} diff --git a/viz/app/globals.css b/viz/app/globals.css index 875c01e819b9..f502ac958c06 100644 --- a/viz/app/globals.css +++ b/viz/app/globals.css @@ -1,6 +1,8 @@ +/* purgecss start ignore */ @tailwind base; @tailwind components; @tailwind utilities; +/* purgecss end ignore */ :root { --foreground-rgb: 0, 0, 0; diff --git a/viz/next.config.mjs b/viz/next.config.mjs index 4678774e6d60..00e5ab523908 100644 --- a/viz/next.config.mjs +++ b/viz/next.config.mjs @@ -1,4 +1,25 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const isDev = process.env.NODE_ENV === "development"; + +const nextConfig = { + async headers() { + return [ + { + source: "/:path*", + headers: [ + { + key: "Access-Control-Allow-Origin", + value: isDev ? "http://localhost:3000" : "https://dust.tt", + }, + ], + }, + // Allow CORS for static files. + { + source: "/_next/static/:path*", + headers: [{ key: "Access-Control-Allow-Origin", value: "*" }], + }, + ]; + }, +}; export default nextConfig; diff --git a/viz/package-lock.json b/viz/package-lock.json index 09946f054931..8469aaf6b3e1 100644 --- a/viz/package-lock.json +++ b/viz/package-lock.json @@ -8,15 +8,21 @@ "name": "viz", "version": "0.1.0", "dependencies": { + "@dust-tt/types": "file:../types", "dd-trace": "^5.1.0", "next": "14.2.5", + "papaparse": "^5.4.1", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "react-runner": "^1.0.5", + "recharts": "^2.12.7" }, "devDependencies": { "@types/node": "^20", + "@types/papaparse": "^5.3.14", "@types/react": "^18", "@types/react-dom": "^18", + "@typescript-eslint/eslint-plugin": "^7.17.0", "eslint": "^8", "eslint-config-next": "14.2.5", "postcss": "^8", @@ -24,6 +30,35 @@ "typescript": "^5" } }, + "../types": { + "name": "@dust-tt/types", + "version": "0.1.0", + "dependencies": { + "@notionhq/client": "^2.2.4", + "csv-parse": "^5.5.6", + "csv-stringify": "^6.5.0", + "dts-cli": "^2.0.5", + "eslint-plugin-simple-import-sort": "^12.1.0", + "eventsource-parser": "^1.1.1", + "hot-shots": "^10.0.0", + "htmlparser2": "^9.1.0", + "io-ts": "^2.2.20", + "io-ts-reporters": "^2.0.1", + "io-ts-types": "^0.5.19", + "moment-timezone": "^0.5.43", + "redis": "^4.6.8", + "uuid": "^9.0.1" + }, + "devDependencies": { + "@tsconfig/recommended": "^1.0.3", + "@types/uuid": "^9.0.7", + "tslib": "^2.6.2", + "typescript": "^5.4.5" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -36,6 +71,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@datadog/native-appsec": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/@datadog/native-appsec/-/native-appsec-8.0.1.tgz", @@ -121,6 +167,10 @@ "resolved": "https://registry.npmjs.org/@datadog/sketches-js/-/sketches-js-2.1.1.tgz", "integrity": "sha512-d5RjycE+MObE/hU+8OM5Zp4VjTwiPLRa8299fj7muOmR16fb942z8byoMbCErnGh0lBevvgkGrLclQDvINbIyg==" }, + "node_modules/@dust-tt/types": { + "resolved": "../types", + "link": true + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -216,7 +266,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -233,7 +282,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -245,7 +293,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -260,7 +307,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -274,7 +320,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -283,7 +328,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -291,14 +335,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -522,7 +564,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" @@ -602,6 +643,60 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -616,6 +711,15 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/papaparse": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", + "integrity": "sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", @@ -641,6 +745,86 @@ "@types/react": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz", + "integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.17.0", + "@typescript-eslint/type-utils": "7.17.0", + "@typescript-eslint/utils": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz", + "integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz", + "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz", + "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.17.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/parser": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", @@ -686,6 +870,115 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz", + "integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.17.0", + "@typescript-eslint/utils": "7.17.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz", + "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz", + "integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz", + "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.17.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/types": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", @@ -751,6 +1044,127 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@typescript-eslint/utils": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz", + "integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.17.0", + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/typescript-estree": "7.17.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz", + "integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz", + "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz", + "integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz", + "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.17.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/visitor-keys": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", @@ -822,7 +1236,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -831,7 +1244,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -845,8 +1257,7 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "node_modules/anymatch": { "version": "3.1.3", @@ -1083,8 +1494,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/binary-extensions": { "version": "2.3.0", @@ -1249,11 +1659,18 @@ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1264,14 +1681,12 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "engines": { "node": ">= 6" } @@ -1286,7 +1701,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1316,8 +1730,117 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -1449,6 +1972,11 @@ } } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, "node_modules/deep-equal": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", @@ -1576,17 +2104,24 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/enhanced-resolve": { "version": "5.17.1", @@ -2208,12 +2743,25 @@ "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.3.tgz", "integrity": "sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw==" }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -2336,7 +2884,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -2456,7 +3003,6 @@ "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", @@ -2490,7 +3036,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -2499,7 +3044,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2764,6 +3308,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -2933,7 +3485,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -3159,8 +3710,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", @@ -3187,7 +3737,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -3348,8 +3897,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/locate-path": { "version": "6.0.0", @@ -3366,6 +3914,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3396,8 +3949,7 @@ "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/merge2": { "version": "1.4.1", @@ -3446,7 +3998,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -3485,7 +4036,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -3619,7 +4169,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3814,6 +4363,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3848,7 +4402,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -3863,7 +4416,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -3919,7 +4471,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, "engines": { "node": ">= 6" } @@ -4106,7 +4657,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -4191,8 +4741,48 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-runner": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/react-runner/-/react-runner-1.0.5.tgz", + "integrity": "sha512-eCIybRpssp6ffjqXqId024esO9UP2lV838Lvm3fC7VgMQ/dQHhR0jJwOY2IPrYD3AaM/bcvMikmASIRZqNUHsw==", + "dependencies": { + "sucrase": "^3.21.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17 || ^18", + "react-dom": "^16.0.0 || ^17 || ^18" + } + }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } }, "node_modules/read-cache": { "version": "1.0.0", @@ -4215,6 +4805,36 @@ "node": ">=8.10.0" } }, + "node_modules/recharts": { + "version": "2.12.7", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.7.tgz", + "integrity": "sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^16.10.2", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -4236,6 +4856,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -4457,7 +5082,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -4469,7 +5093,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -4504,7 +5127,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -4561,7 +5183,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -4579,7 +5200,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -4592,14 +5212,12 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -4611,7 +5229,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -4721,7 +5338,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4734,7 +5350,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4789,7 +5404,6 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -4887,7 +5501,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "dependencies": { "any-promise": "^1.0.0" } @@ -4896,7 +5509,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -4904,6 +5516,11 @@ "node": ">=0.8" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/tlhunter-sorted-set": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/tlhunter-sorted-set/-/tlhunter-sorted-set-0.1.0.tgz", @@ -4936,8 +5553,7 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -5101,11 +5717,31 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -5208,7 +5844,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -5226,7 +5861,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5242,14 +5876,12 @@ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5263,7 +5895,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -5275,7 +5906,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -5287,7 +5917,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, diff --git a/viz/package.json b/viz/package.json index fb6f5c9de088..6d06ef0b3707 100644 --- a/viz/package.json +++ b/viz/package.json @@ -9,19 +9,25 @@ "lint": "next lint" }, "dependencies": { + "@dust-tt/types": "file:../types", + "dd-trace": "^5.1.0", + "next": "14.2.5", + "papaparse": "^5.4.1", "react": "^18", "react-dom": "^18", - "next": "14.2.5", - "dd-trace": "^5.1.0" + "react-runner": "^1.0.5", + "recharts": "^2.12.7" }, "devDependencies": { - "typescript": "^5", "@types/node": "^20", + "@types/papaparse": "^5.3.14", "@types/react": "^18", "@types/react-dom": "^18", + "@typescript-eslint/eslint-plugin": "^7.17.0", + "eslint": "^8", + "eslint-config-next": "14.2.5", "postcss": "^8", "tailwindcss": "^3.4.1", - "eslint": "^8", - "eslint-config-next": "14.2.5" + "typescript": "^5" } } diff --git a/viz/tailwind.config.ts b/viz/tailwind.config.ts index 1ff376b23567..f228fa03b195 100644 --- a/viz/tailwind.config.ts +++ b/viz/tailwind.config.ts @@ -15,5 +15,10 @@ const config: Config = { }, }, plugins: [], + safelist: [ + { + pattern: /./, // This matches all class names. + }, + ], }; export default config;