From 005e960968d085357861954deae28b1e6cce4e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Barczy=C5=84ski?= <104033489+WojciechBarczynski@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:11:52 +0200 Subject: [PATCH 01/51] Initial version of border radius, box shadow and borders handling in the layout shader (#815) --- .../src/transformations/layout.rs | 74 +-- .../transformations/layout/apply_layouts.wgsl | 323 ++++++++++++- .../src/transformations/layout/flatten.rs | 77 +++- .../src/transformations/layout/params.rs | 429 ++++++++++++++---- .../src/transformations/layout/shader.rs | 52 ++- .../src/transformations/web_renderer.rs | 2 + .../web_renderer/browser_client.rs | 10 +- .../tranformation_matrices.rs} | 53 +-- 8 files changed, 795 insertions(+), 225 deletions(-) rename compositor_render/src/transformations/{layout/transformation_matrices.rs => web_renderer/tranformation_matrices.rs} (54%) diff --git a/compositor_render/src/transformations/layout.rs b/compositor_render/src/transformations/layout.rs index 3a5ff2828..1f3b2c168 100644 --- a/compositor_render/src/transformations/layout.rs +++ b/compositor_render/src/transformations/layout.rs @@ -11,16 +11,12 @@ mod flatten; mod layout_renderer; mod params; mod shader; -mod transformation_matrices; -use self::{ - params::{LayoutNodeParams, ParamsBuffer}, - shader::LayoutShader, -}; +use self::shader::LayoutShader; pub(crate) use layout_renderer::LayoutRenderer; + use log::error; -pub(crate) use transformation_matrices::{vertices_transformation_matrix, Position}; pub(crate) trait LayoutProvider: Send { fn layouts(&mut self, pts: Duration, inputs: &[Option]) -> NestedLayout; @@ -30,7 +26,6 @@ pub(crate) trait LayoutProvider: Send { pub(crate) struct LayoutNode { layout_provider: Box, shader: Arc, - params: ParamsBuffer, } #[derive(Debug, Clone)] @@ -41,6 +36,24 @@ pub struct Crop { pub height: f32, } +#[derive(Debug, Clone)] +pub struct BorderRadius { + pub top_left: f32, + pub top_right: f32, + pub bottom_right: f32, + pub bottom_left: f32, +} + +#[derive(Debug, Clone)] +pub struct ParentMask { + pub radius: BorderRadius, + // position of parent on the output frame + pub top: f32, + pub left: f32, + pub width: f32, + pub height: f32, +} + #[derive(Debug, Clone)] struct RenderLayout { top: f32, @@ -48,13 +61,26 @@ struct RenderLayout { width: f32, height: f32, rotation_degrees: f32, + border_radius: BorderRadius, + parent_masks: Vec, content: RenderLayoutContent, } #[derive(Debug, Clone)] enum RenderLayoutContent { - Color(RGBAColor), - ChildNode { index: usize, crop: Crop }, + Color { + color: RGBAColor, + border_color: RGBAColor, + border_width: f32, + }, + ChildNode { + index: usize, + crop: Crop, + border_color: RGBAColor, + border_width: f32, + }, + #[allow(dead_code)] + BoxShadow { color: RGBAColor, blur_radius: f32 }, } #[derive(Debug, Clone)] @@ -97,7 +123,6 @@ impl LayoutNode { Self { layout_provider, shader, - params: ParamsBuffer::new(ctx.wgpu_ctx, vec![]), } } @@ -118,34 +143,11 @@ impl LayoutNode { .layouts(pts, &input_resolutions) .flatten(&input_resolutions, output_resolution); - let params: Vec = layouts - .iter() - .map(|layout| { - let (is_texture, background_color, input_resolution) = match layout.content { - RenderLayoutContent::ChildNode { index, .. } => ( - 1, - RGBAColor(0, 0, 0, 0), - *input_resolutions.get(index).unwrap_or(&None), - ), - RenderLayoutContent::Color(color) => (0, color, None), - }; - - LayoutNodeParams { - is_texture, - background_color, - transform_vertices_matrix: layout - .vertices_transformation_matrix(&output_resolution), - transform_texture_coords_matrix: layout - .texture_coords_transformation_matrix(&input_resolution), - } - }) - .collect(); - self.params.update(params, ctx.wgpu_ctx); - let textures: Vec> = layouts .iter() .map(|layout| match layout.content { - RenderLayoutContent::Color(_) => None, + RenderLayoutContent::BoxShadow { .. } => None, + RenderLayoutContent::Color { .. } => None, RenderLayoutContent::ChildNode { index, .. } => match sources.get(index) { Some(node_texture) => Some(*node_texture), None => { @@ -158,7 +160,7 @@ impl LayoutNode { let target = target.ensure_size(ctx.wgpu_ctx, output_resolution); self.shader - .render(ctx.wgpu_ctx, self.params.bind_group(), &textures, target); + .render(ctx.wgpu_ctx, output_resolution, layouts, &textures, target); } } diff --git a/compositor_render/src/transformations/layout/apply_layouts.wgsl b/compositor_render/src/transformations/layout/apply_layouts.wgsl index 7bfae09a1..c24e8a772 100644 --- a/compositor_render/src/transformations/layout/apply_layouts.wgsl +++ b/compositor_render/src/transformations/layout/apply_layouts.wgsl @@ -1,51 +1,332 @@ struct VertexInput { + // position in clip space [-1, -1] (bottom-left) X [1, 1] (top-right) @location(0) position: vec3, + // texture coordinates in texture coordiantes [0, 0] (top-left) X [1, 1] (bottom-right) @location(1) tex_coords: vec2, } struct VertexOutput { + // position in output in pixel coordinates [0, 0] (top-left) X [output_resolution.x, output_resolution.y] (bottom-right) @builtin(position) position: vec4, + // texture coordinates in texture coordiantes [0, 0] (top-left) X [1, 1] (bottom-right) @location(0) tex_coords: vec2, + // Position relative to center of the rectangle in [-rect_width/2, rect_width/2] X [-rect_height/2, height/2] + @location(2) center_position: vec2 } +struct BoxShadowParams { + border_radius: vec4, + color: vec4, + top: f32, + left: f32, + width: f32, + height: f32, + rotation_degrees: f32, + blur_radius: f32, +} + +struct TextureParams { + border_radius: vec4, + border_color: vec4, + // position + top: f32, + left: f32, + width: f32, + height: f32, + // texture crop + crop_top: f32, + crop_left: f32, + crop_width: f32, + crop_height: f32, + + rotation_degrees: f32, + // border size in pixels + border_width: f32, +} + +struct ColorParams { + border_radius: vec4, + border_color: vec4, + color: vec4, + + top: f32, + left: f32, + width: f32, + height: f32, -struct Layout { - vertices_transformation: mat4x4, - texture_coord_transformation: mat4x4, - color: vec4, // used only when is_texture == 0 - is_texture: u32, // 0 -> color, 1 -> texture + rotation_degrees: f32, + border_width: f32, } +struct ParentBorderRadius { + radius: vec4, + top: f32, + left: f32, + width: f32, + height: f32, +} + +struct LayoutInfo { + // 0 -> Texture, 1 -> Color, 2 -> BoxShadow + layout_type: u32, + index: u32, + parent_masks_len: u32 +} + + @group(0) @binding(0) var texture: texture_2d; -@group(1) @binding(0) var layouts: array; -@group(2) @binding(0) var sampler_: sampler; -var layout_id: u32; +@group(1) @binding(0) var output_resolution: vec2; +@group(1) @binding(1) var texture_params: array; +@group(1) @binding(2) var color_params: array; +@group(1) @binding(3) var box_shadow_params: array; + +@group(2) @binding(0) var parent_masks: array; + +@group(3) @binding(0) var sampler_: sampler; + +var layout_info: LayoutInfo; + +fn rotation_matrix(rotation: f32) -> mat4x4 { + // wgsl is column-major + let angle = radians(rotation); + let c = cos(angle); + let s = sin(angle); + return mat4x4( + vec4(c, s, 0.0, 0.0), + vec4(-s, c, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0) + ); +} + +fn scale_matrix(scale: vec2) -> mat4x4 { + return mat4x4( + vec4(scale.x, 0.0, 0.0, 0.0), + vec4(0.0, scale.y, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0) + ); +} + + +fn translation_matrix(translation: vec2) -> mat4x4 { + return mat4x4( + vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(translation, 0.0, 1.0) + ); +} + +fn vertices_transformation_matrix(left: f32, top: f32, width: f32, height: f32, rotation: f32) -> mat4x4 { + let scale_to_size = vec2( + width / output_resolution.x, + height / output_resolution.y + ); + let scale_to_pixels = vec2( + output_resolution.x / 2.0, + output_resolution.y / 2.0 + ); + let scale_to_clip_space = vec2( + 1.0 / scale_to_pixels.x, + 1.0 / scale_to_pixels.y + ); + + let scale_to_pixels_mat = scale_matrix(scale_to_pixels * scale_to_size); + let scale_to_clip_space_mat = scale_matrix(scale_to_clip_space); + + let left_border_x = -(output_resolution.x / 2.0); + let distance_left_to_middle = left + width / 2.0; + let top_border_y = output_resolution.y / 2.0; + let distance_top_to_middle = top + height / 2.0; + let translation = vec2( + left_border_x + distance_left_to_middle, + top_border_y - distance_top_to_middle + ); + + let translation_mat = translation_matrix(translation); + let rotation_mat = rotation_matrix(rotation); + + return scale_to_clip_space_mat * translation_mat * rotation_mat * scale_to_pixels_mat; +} + +fn texture_coord_transformation_matrix(crop_left: f32, crop_top: f32, crop_width: f32, crop_height: f32) -> mat4x4 { + let dim = textureDimensions(texture); + let scale = vec2( + crop_width / f32(dim.x), + crop_height / f32(dim.y), + ); + + let translation = vec2( + crop_left / f32(dim.x), + crop_top / f32(dim.y), + ); + + return translation_matrix(translation) * scale_matrix(scale); +} @vertex fn vs_main(input: VertexInput) -> VertexOutput { var output: VertexOutput; - let vertices_transformation_matrix: mat4x4 = layouts[layout_id].vertices_transformation; - let texture_coord_transformation_matrix: mat4x4 = layouts[layout_id].texture_coord_transformation; + switch (layout_info.layout_type) { + // texture + case 0u: { + let vertices_transformation = vertices_transformation_matrix( + texture_params[layout_info.index].left, + texture_params[layout_info.index].top, + texture_params[layout_info.index].width, + texture_params[layout_info.index].height, + texture_params[layout_info.index].rotation_degrees + ); + let texture_transformation = texture_coord_transformation_matrix( + texture_params[layout_info.index].crop_left, + texture_params[layout_info.index].crop_top, + texture_params[layout_info.index].crop_width, + texture_params[layout_info.index].crop_height + ); + output.position = vertices_transformation * vec4(input.position, 1.0); + output.tex_coords = (texture_transformation * vec4(input.tex_coords, 0.0, 1.0)).xy; + let rect_size = vec2(texture_params[layout_info.index].width, texture_params[layout_info.index].height); + output.center_position = input.position.xy / 2.0 * rect_size; + } + // color + case 1u: { + let vertices_transformation = vertices_transformation_matrix( + color_params[layout_info.index].left, + color_params[layout_info.index].top, + color_params[layout_info.index].width, + color_params[layout_info.index].height, + color_params[layout_info.index].rotation_degrees + ); + output.position = vertices_transformation * vec4(input.position, 1.0); + output.tex_coords = input.tex_coords; + let rect_size = vec2(color_params[layout_info.index].width, color_params[layout_info.index].height); + output.center_position = input.position.xy / 2.0 * rect_size; + } + // box shadow + case 2u: { + let width = box_shadow_params[layout_info.index].width + 2.0 * box_shadow_params[layout_info.index].blur_radius; + let height = box_shadow_params[layout_info.index].height + 2.0 * box_shadow_params[layout_info.index].blur_radius; - output.position = vec4(input.position, 1.0) * vertices_transformation_matrix; - output.tex_coords = (vec4(input.tex_coords, 0.0, 1.0) * texture_coord_transformation_matrix).xy; + let vertices_transformation = vertices_transformation_matrix( + box_shadow_params[layout_info.index].left - box_shadow_params[layout_info.index].blur_radius, + box_shadow_params[layout_info.index].top - box_shadow_params[layout_info.index].blur_radius, + width, + height, + box_shadow_params[layout_info.index].rotation_degrees + ); + output.position = vertices_transformation * vec4(input.position, 1.0); + output.tex_coords = input.tex_coords; + let rect_size = vec2(width, height); + output.center_position = input.position.xy / 2.0 * rect_size; + } + default {} + } return output; } +// Signed distance function for rounded rectangle https://iquilezles.org/articles/distfunctions +// adapted from https://www.shadertoy.com/view/4llXD7 +// dist - signed distance from the center of the rectangle in pixels +// size - size of the rectangle in pixels +// radius - radius of the corners in pixels [top-left, top-right, bottom-right, bottom-left] +// rotation - rotation of the rectangle in degrees +// WARNING - it doesn't work when border radius is > min(size.x, size.y) / 2 +fn roundedRectSDF(dist: vec2, size: vec2, radius: vec4, rotation: f32) -> f32 { + let half_size = size / 2.0; + + // wierd hack to get the radius of the nearest corner stored in r.x + var r: vec2 = vec2(0.0, 0.0); + r = select(radius.yz, radius.xw, dist.x < 0.0 ); + r.x = select(r.y, r.x, dist.y < 0.0 ); + + let q = abs(dist) - half_size + r.x; + return min(max(q.x, q.y), 0.0) + length(max(q, vec2(0.0, 0.0))) - r.x; +} + @fragment fn fs_main(input: VertexOutput) -> @location(0) vec4 { - let current_layout = layouts[layout_id]; + let transparent = vec4(0.0, 0.0, 0.0, 0.0); + // TODO: Add parent mask handling + let parent_mask_alpha = 1.0; - // sampling can't be conditional, so in case of plane_id == -1 - // sample textures[0], but ignore the result. - if (current_layout.is_texture == 0u) { - return current_layout.color; - } - // clamp transparent, when crop > input texture - let is_inside: f32 = round(f32(input.tex_coords.x < 1.0 && input.tex_coords.x > 0.0 && input.tex_coords.y > 0.0 && input.tex_coords.y < 1.0)); + switch layout_info.layout_type { + case 0u: { + let sample = textureSample(texture, sampler_, input.tex_coords); - return is_inside * textureSample(texture, sampler_, input.tex_coords); + let width = texture_params[layout_info.index].width; + let height = texture_params[layout_info.index].height; + let border_radius = texture_params[layout_info.index].border_radius; + let rotation_degrees = texture_params[layout_info.index].rotation_degrees; + let border_width = texture_params[layout_info.index].border_width; + let border_color = texture_params[layout_info.index].border_color; + + let size = vec2(width, height); + let edge_distance = roundedRectSDF( + input.center_position, + size, + border_radius, + rotation_degrees + ); + + let smoothed_alpha = 1.0 - smoothstep(0.0, 2.0, edge_distance); + let border_alpha = 1.0 - smoothstep(-border_width + 1.0, -border_width, edge_distance); + + let mixed_background = mix(transparent, sample, min(smoothed_alpha, parent_mask_alpha)); + let mixed_border = mix(mixed_background, border_color, min(border_alpha, smoothed_alpha)); + return mixed_border; + } + case 1u: { + let color = color_params[layout_info.index].color; + + let width = color_params[layout_info.index].width; + let height = color_params[layout_info.index].height; + let border_radius = color_params[layout_info.index].border_radius; + let rotation_degrees = color_params[layout_info.index].rotation_degrees; + let border_width = color_params[layout_info.index].border_width; + let border_color = color_params[layout_info.index].border_color; + + let size = vec2(width, height); + let edge_distance = roundedRectSDF( + input.center_position, + size, + border_radius, + rotation_degrees + ); + + let smoothed_alpha = 1.0 - smoothstep(0.0, 2.0, edge_distance); + let border_alpha = 1.0 - smoothstep(-border_width + 1.0, -border_width, edge_distance); + + let mixed_background = mix(transparent, color, min(smoothed_alpha, parent_mask_alpha)); + let mixed_border = mix(mixed_background, border_color, border_alpha); + return mixed_border; + } + case 2u: { + let color = box_shadow_params[layout_info.index].color; + + let width = box_shadow_params[layout_info.index].width; + let height = box_shadow_params[layout_info.index].height; + let border_radius = box_shadow_params[layout_info.index].border_radius; + let rotation_degrees = box_shadow_params[layout_info.index].rotation_degrees; + let blur_radius = box_shadow_params[layout_info.index].blur_radius; + + let size = vec2(width, height); + let edge_distance = roundedRectSDF( + input.center_position, + size, + border_radius, + rotation_degrees + ); + + let smoothed_alpha = 1.0 - smoothstep(0.0, blur_radius, edge_distance); + let mixed_background = mix(transparent, color, min(smoothed_alpha, parent_mask_alpha)); + return mixed_background; + } + default { + return vec4(0.0, 0.0, 0.0, 0.0); + } + } } diff --git a/compositor_render/src/transformations/layout/flatten.rs b/compositor_render/src/transformations/layout/flatten.rs index 131a623fa..7d03fef91 100644 --- a/compositor_render/src/transformations/layout/flatten.rs +++ b/compositor_render/src/transformations/layout/flatten.rs @@ -51,9 +51,12 @@ impl NestedLayout { return false; } match &layout.content { - RenderLayoutContent::Color(RGBAColor(_, _, _, 0)) => false, - RenderLayoutContent::Color(_) => true, - RenderLayoutContent::ChildNode { crop, index } => { + RenderLayoutContent::Color { + color: RGBAColor(_, _, _, 0), + .. + } => false, + RenderLayoutContent::Color { .. } => true, + RenderLayoutContent::ChildNode { crop, index, .. } => { let size = input_resolutions.get(*index).copied().flatten(); if let Some(size) = size { if crop.left > size.width as f32 || crop.top > size.height as f32 { @@ -65,6 +68,9 @@ impl NestedLayout { } true } + + #[allow(clippy::todo)] + RenderLayoutContent::BoxShadow { .. } => todo!(), } } @@ -77,6 +83,13 @@ impl NestedLayout { height: layout.height * self.scale_y, rotation_degrees: layout.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct content: layout.content, + border_radius: super::BorderRadius { + top_left: 0.0, + top_right: 0.0, + bottom_right: 0.0, + bottom_left: 0.0, + }, + parent_masks: Vec::new(), }, Some(crop) => { // Below values are only correct if `crop` is in the same coordinate @@ -93,19 +106,36 @@ impl NestedLayout { let cropped_width = cropped_right - cropped_left; let cropped_height = cropped_bottom - cropped_top; match layout.content { - RenderLayoutContent::Color(color) => { + RenderLayoutContent::Color { + color, + border_color, + border_width, + } => { RenderLayout { top: self.top + (cropped_top * self.scale_y), left: self.left + (cropped_left * self.scale_x), width: cropped_width * self.scale_x, height: cropped_height * self.scale_y, rotation_degrees: layout.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct - content: RenderLayoutContent::Color(color), + content: RenderLayoutContent::Color { + color, + border_color, + border_width, + }, + border_radius: super::BorderRadius { + top_left: 0.0, + top_right: 0.0, + bottom_right: 0.0, + bottom_left: 0.0, + }, + parent_masks: Vec::new(), } } RenderLayoutContent::ChildNode { index, crop: child_crop, + border_color, + border_width, } => { // Calculate how much top/left coordinates changed when cropping. It represents // how much was removed in layout coordinates. Ignore the change of a position that @@ -131,9 +161,23 @@ impl NestedLayout { width: cropped_width * self.scale_x, height: cropped_height * self.scale_y, rotation_degrees: layout.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct - content: RenderLayoutContent::ChildNode { index, crop }, + content: RenderLayoutContent::ChildNode { + index, + crop, + border_color, + border_width, + }, + border_radius: super::BorderRadius { + top_left: 0.0, + top_right: 0.0, + bottom_right: 0.0, + bottom_left: 0.0, + }, + parent_masks: Vec::new(), } } + #[allow(clippy::todo)] + RenderLayoutContent::BoxShadow { .. } => todo!(), } } } @@ -147,7 +191,11 @@ impl NestedLayout { height: self.height, rotation_degrees: self.rotation_degrees, content: match self.content { - LayoutContent::Color(color) => RenderLayoutContent::Color(color), + LayoutContent::Color(color) => RenderLayoutContent::Color { + color, + border_color: RGBAColor(0, 0, 0, 0), + border_width: 0.0, + }, LayoutContent::ChildNode { index, size } => RenderLayoutContent::ChildNode { index, crop: Crop { @@ -156,9 +204,22 @@ impl NestedLayout { width: size.width, height: size.height, }, + border_color: RGBAColor(0, 0, 0, 0), + border_width: 0.0, + }, + LayoutContent::None => RenderLayoutContent::Color { + color: RGBAColor(0, 0, 0, 0), + border_color: RGBAColor(0, 0, 0, 0), + border_width: 0.0, }, - LayoutContent::None => RenderLayoutContent::Color(RGBAColor(0, 0, 0, 0)), }, + border_radius: super::BorderRadius { + top_left: 0.0, + top_right: 0.0, + bottom_right: 0.0, + bottom_left: 0.0, + }, + parent_masks: Vec::new(), } } } diff --git a/compositor_render/src/transformations/layout/params.rs b/compositor_render/src/transformations/layout/params.rs index 1c3fc7474..f9eafbdeb 100644 --- a/compositor_render/src/transformations/layout/params.rs +++ b/compositor_render/src/transformations/layout/params.rs @@ -1,126 +1,371 @@ -use nalgebra_glm::Mat4; -use wgpu::util::DeviceExt; +use tracing::error; +use wgpu::{ + util::{BufferInitDescriptor, DeviceExt}, + BindGroupLayoutDescriptor, BufferUsages, +}; -use crate::{scene::RGBAColor, wgpu::WgpuCtx}; +use crate::{scene::RGBAColor, wgpu::WgpuCtx, Resolution}; -#[derive(Debug, Clone)] -pub(super) struct LayoutNodeParams { - pub(super) transform_vertices_matrix: Mat4, - pub(super) transform_texture_coords_matrix: Mat4, - pub(super) is_texture: u32, - pub(super) background_color: RGBAColor, +use super::{BorderRadius, RenderLayout}; + +const MAX_PARENT_BORDER_RADISUES: usize = 20; +const MAX_LAYOUTS_COUNT: usize = 100; +const TEXTURE_PARAMS_BUFFER_SIZE: usize = MAX_LAYOUTS_COUNT * 80; +const COLOR_PARAMS_SIZE: usize = MAX_LAYOUTS_COUNT * 80; +const BOX_SHADOW_PARAMS_SIZE: usize = MAX_LAYOUTS_COUNT * 80; + +#[derive(Debug)] +pub struct LayoutInfo { + pub layout_type: u32, + pub index: u32, + pub parent_border_radiuses_len: u32, } -impl Default for LayoutNodeParams { - fn default() -> Self { - Self { - transform_vertices_matrix: Mat4::identity(), - transform_texture_coords_matrix: Mat4::identity(), - is_texture: 0, - background_color: RGBAColor(0, 0, 0, 0), - } +impl LayoutInfo { + pub fn to_bytes(&self) -> [u8; 16] { + let mut result = [0u8; 16]; + result[0..4].copy_from_slice(&self.layout_type.to_le_bytes()); + result[4..8].copy_from_slice(&self.index.to_le_bytes()); + result[8..12].copy_from_slice(&self.parent_border_radiuses_len.to_le_bytes()); + result } } -pub(super) struct ParamsBuffer { - bind_group: wgpu::BindGroup, - buffer: wgpu::Buffer, - content: bytes::Bytes, +#[derive(Debug)] +pub struct ParamsBindGroups { + pub bind_group_1: wgpu::BindGroup, + pub bind_group_1_layout: wgpu::BindGroupLayout, + output_resolution_buffer: wgpu::Buffer, + texture_params_buffer: wgpu::Buffer, + color_params_buffer: wgpu::Buffer, + box_shadow_params_buffer: wgpu::Buffer, + pub bind_groups_2: Vec<(wgpu::BindGroup, wgpu::Buffer)>, + pub bind_group_2_layout: wgpu::BindGroupLayout, } -impl ParamsBuffer { - pub fn new(wgpu_ctx: &WgpuCtx, params: Vec) -> Self { - let mut content = Self::shader_buffer_content(¶ms); - if content.is_empty() { - content = bytes::Bytes::copy_from_slice(&[0]); - } +impl ParamsBindGroups { + pub fn new(ctx: &WgpuCtx) -> ParamsBindGroups { + let output_resolution_buffer = create_buffer(ctx, 8); + let texture_params_buffer = create_buffer(ctx, TEXTURE_PARAMS_BUFFER_SIZE); + let color_params_buffer = create_buffer(ctx, COLOR_PARAMS_SIZE); + let box_shadow_params_buffer = create_buffer(ctx, BOX_SHADOW_PARAMS_SIZE); - let buffer = wgpu_ctx + let bind_group_1_layout = ctx .device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("params buffer"), - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - contents: &content, + .create_bind_group_layout(&BindGroupLayoutDescriptor { + label: Some("Bind group 1 layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + count: None, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + count: None, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + }, + wgpu::BindGroupLayoutEntry { + binding: 2, + count: None, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + }, + wgpu::BindGroupLayoutEntry { + binding: 3, + count: None, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + }, + ], }); - let bind_group = wgpu_ctx - .device - .create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("params bind group"), - layout: &wgpu_ctx.uniform_bgl, + let bind_group_1 = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Bind group 1"), + layout: &bind_group_1_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: output_resolution_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: texture_params_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: color_params_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 3, + resource: box_shadow_params_buffer.as_entire_binding(), + }, + ], + }); + + let bind_group_2_layout = + ctx.device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Bind group 2 layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let mut bind_groups_2 = Vec::with_capacity(100); + for _ in 0..100 { + let buffer = create_buffer(ctx, 20 * 32); + + let bind_group_2 = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Bind group 2"), + layout: &bind_group_2_layout, entries: &[wgpu::BindGroupEntry { binding: 0, resource: buffer.as_entire_binding(), }], }); + bind_groups_2.push((bind_group_2, buffer)); + } Self { - bind_group, - buffer, - content, + bind_group_1, + output_resolution_buffer, + texture_params_buffer, + color_params_buffer, + box_shadow_params_buffer, + bind_groups_2, + bind_group_1_layout, + bind_group_2_layout, } } - pub fn bind_group(&self) -> &wgpu::BindGroup { - &self.bind_group - } - - pub fn update(&mut self, params: Vec, wgpu_ctx: &WgpuCtx) { - let content = Self::shader_buffer_content(¶ms); - if self.content.len() != content.len() { - *self = Self::new(wgpu_ctx, params); + pub fn update( + &self, + ctx: &WgpuCtx, + output_resolution: Resolution, + layouts: Vec, + ) -> Vec { + if layouts.len() > MAX_LAYOUTS_COUNT { + error!( + "Max layouts count ({}) exceeded ({}). Skipping rendering some of them.", + MAX_LAYOUTS_COUNT, + layouts.len() + ) } - if self.content != content { - wgpu_ctx.queue.write_buffer(&self.buffer, 0, &content); + let mut output_resolution_bytes = [0u8; 8]; + output_resolution_bytes[0..4] + .copy_from_slice(&(output_resolution.width as f32).to_le_bytes()); + output_resolution_bytes[4..8] + .copy_from_slice(&(output_resolution.height as f32).to_le_bytes()); + + ctx.queue + .write_buffer(&self.output_resolution_buffer, 0, &output_resolution_bytes); + + let mut layout_infos = Vec::new(); + + let mut texture_params = Vec::new(); + let mut color_params = Vec::new(); + let mut box_shadow_params = Vec::new(); + + for (index, layout) in layouts.iter().enumerate().take(MAX_LAYOUTS_COUNT) { + let RenderLayout { + top, + left, + width, + height, + rotation_degrees, + border_radius, + parent_masks: parent_border_radiuses, + content, + } = layout; + let border_radius_bytes = borders_radius_to_bytes(border_radius.clone()); + + match content { + super::RenderLayoutContent::Color { + color, + border_color, + border_width, + } => { + let layout_info = LayoutInfo { + layout_type: 1, + index: color_params.len() as u32, + parent_border_radiuses_len: parent_border_radiuses.len() as u32, + }; + let mut color_params_bytes = [0u8; 80]; + color_params_bytes[0..16].copy_from_slice(&border_radius_bytes); + color_params_bytes[16..32].copy_from_slice(&color_to_bytes(*border_color)); + color_params_bytes[32..48].copy_from_slice(&color_to_bytes(*color)); + color_params_bytes[48..52].copy_from_slice(&top.to_le_bytes()); + color_params_bytes[52..56].copy_from_slice(&left.to_le_bytes()); + color_params_bytes[56..60].copy_from_slice(&width.to_le_bytes()); + color_params_bytes[60..64].copy_from_slice(&height.to_le_bytes()); + color_params_bytes[64..68].copy_from_slice(&rotation_degrees.to_le_bytes()); + color_params_bytes[68..72].copy_from_slice(&border_width.to_le_bytes()); + color_params.push(color_params_bytes); + layout_infos.push(layout_info); + } + super::RenderLayoutContent::ChildNode { + index: _, + crop, + border_color, + border_width, + } => { + let layout_info = LayoutInfo { + layout_type: 0, + index: texture_params.len() as u32, + parent_border_radiuses_len: parent_border_radiuses.len() as u32, + }; + let mut texture_params_bytes = [0u8; 80]; + texture_params_bytes[0..16].copy_from_slice(&border_radius_bytes); + texture_params_bytes[16..32].copy_from_slice(&color_to_bytes(*border_color)); + texture_params_bytes[32..36].copy_from_slice(&top.to_le_bytes()); + texture_params_bytes[36..40].copy_from_slice(&left.to_le_bytes()); + texture_params_bytes[40..44].copy_from_slice(&width.to_le_bytes()); + texture_params_bytes[44..48].copy_from_slice(&height.to_le_bytes()); + texture_params_bytes[48..52].copy_from_slice(&crop.top.to_le_bytes()); + texture_params_bytes[52..56].copy_from_slice(&crop.left.to_le_bytes()); + texture_params_bytes[56..60].copy_from_slice(&crop.width.to_le_bytes()); + texture_params_bytes[60..64].copy_from_slice(&crop.height.to_le_bytes()); + texture_params_bytes[64..68].copy_from_slice(&rotation_degrees.to_le_bytes()); + texture_params_bytes[68..72].copy_from_slice(&border_width.to_le_bytes()); + texture_params.push(texture_params_bytes); + layout_infos.push(layout_info); + } + super::RenderLayoutContent::BoxShadow { color, blur_radius } => { + let layout_info = LayoutInfo { + layout_type: 2, + index: box_shadow_params.len() as u32, + parent_border_radiuses_len: parent_border_radiuses.len() as u32, + }; + let mut box_shadow_params_bytes = [0u8; 64]; + box_shadow_params_bytes[0..16].copy_from_slice(&border_radius_bytes); + box_shadow_params_bytes[16..32].copy_from_slice(&color_to_bytes(*color)); + box_shadow_params_bytes[32..36].copy_from_slice(&top.to_le_bytes()); + box_shadow_params_bytes[36..40].copy_from_slice(&left.to_le_bytes()); + box_shadow_params_bytes[40..44].copy_from_slice(&width.to_le_bytes()); + box_shadow_params_bytes[44..48].copy_from_slice(&height.to_le_bytes()); + box_shadow_params_bytes[48..52] + .copy_from_slice(&rotation_degrees.to_le_bytes()); + box_shadow_params_bytes[52..56].copy_from_slice(&blur_radius.to_le_bytes()); + box_shadow_params.push(box_shadow_params_bytes); + layout_infos.push(layout_info); + } + } + if parent_border_radiuses.len() > MAX_PARENT_BORDER_RADISUES { + error!( + "Max parent border radiuses count ({}) exceeded ({}). Slkipping rendering some og them.", + MAX_PARENT_BORDER_RADISUES, + parent_border_radiuses.len() + ); + } + + let mut parent_border_radiuses_bytes = Vec::new(); + + for parent_border_radius in parent_border_radiuses.iter().take(20) { + let mut parent_border_radius_bytes = [0u8; 32]; + parent_border_radius_bytes[0..16].copy_from_slice(&borders_radius_to_bytes( + parent_border_radius.radius.clone(), + )); + parent_border_radius_bytes[16..20] + .copy_from_slice(&parent_border_radius.top.to_le_bytes()); + parent_border_radius_bytes[20..24] + .copy_from_slice(&parent_border_radius.left.to_le_bytes()); + parent_border_radius_bytes[24..28] + .copy_from_slice(&parent_border_radius.width.to_le_bytes()); + parent_border_radius_bytes[28..32] + .copy_from_slice(&parent_border_radius.height.to_le_bytes()); + + parent_border_radiuses_bytes.push(parent_border_radius_bytes); + } + + parent_border_radiuses_bytes.resize_with(20, || [0u8; 32]); + match self.bind_groups_2.get(index) { + Some((_bg, buffer)) => { + ctx.queue + .write_buffer(buffer, 0, &parent_border_radiuses_bytes.concat()); + } + None => { + error!("Not enought parent border radiuses bind groups preallocated"); + } + } + + ctx.queue.write_buffer( + &self.bind_groups_2[index].1, + 0, + &parent_border_radiuses_bytes.concat(), + ); } - } + texture_params.resize_with(100, || [0u8; 80]); + color_params.resize_with(100, || [0u8; 80]); + box_shadow_params.resize_with(100, || [0u8; 64]); + + ctx.queue + .write_buffer(&self.texture_params_buffer, 0, &texture_params.concat()); + ctx.queue + .write_buffer(&self.color_params_buffer, 0, &color_params.concat()); + ctx.queue.write_buffer( + &self.box_shadow_params_buffer, + 0, + &box_shadow_params.concat(), + ); - fn shader_buffer_content(params: &[LayoutNodeParams]) -> bytes::Bytes { - // this should only be enabled on `wasm32`, but it needs to be enabled as a temporary fix - // (@wbarczynski has a PR fixing this in the works right now) - let params = { - // On WebGL we have to fill the whole array - const MAX_PARAMS_COUNT: usize = 100; - let mut params = params.to_vec(); - params.resize_with(MAX_PARAMS_COUNT, LayoutNodeParams::default); - params - }; - - params - .iter() - .map(LayoutNodeParams::shader_buffer_content) - .collect::>() - .concat() - .into() + layout_infos } } -impl LayoutNodeParams { - fn shader_buffer_content(&self) -> [u8; 160] { - let Self { - transform_vertices_matrix, - transform_texture_coords_matrix, - is_texture, - background_color, - } = self; - let mut result = [0; 160]; - fn from_u8_color(value: u8) -> [u8; 4] { - (value as f32 / 255.0).to_ne_bytes() - } - - result[0..64].copy_from_slice(bytemuck::bytes_of(&transform_vertices_matrix.transpose())); - result[64..128].copy_from_slice(bytemuck::bytes_of( - &transform_texture_coords_matrix.transpose(), - )); - result[128..132].copy_from_slice(&from_u8_color(background_color.0)); - result[132..136].copy_from_slice(&from_u8_color(background_color.1)); - result[136..140].copy_from_slice(&from_u8_color(background_color.2)); - result[140..144].copy_from_slice(&from_u8_color(background_color.3)); +fn create_buffer(ctx: &WgpuCtx, size: usize) -> wgpu::Buffer { + ctx.device.create_buffer_init(&BufferInitDescriptor { + label: Some("params buffer"), + contents: &vec![0u8; size], + usage: BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }) +} - result[144..148].copy_from_slice(&is_texture.to_ne_bytes()); - // 12 bytes padding +fn borders_radius_to_bytes(border_radius: BorderRadius) -> [u8; 16] { + let mut result = [0u8; 16]; + result[0..4].copy_from_slice(&border_radius.top_left.to_le_bytes()); + result[4..8].copy_from_slice(&border_radius.top_right.to_le_bytes()); + result[8..12].copy_from_slice(&border_radius.bottom_right.to_le_bytes()); + result[12..16].copy_from_slice(&border_radius.bottom_left.to_le_bytes()); + result +} - result +fn color_to_bytes(color: RGBAColor) -> [u8; 16] { + let RGBAColor(r, g, b, a) = color; + fn color_from_u8(color: u8) -> [u8; 4] { + (color as f32 / 255.0).to_le_bytes() } + + let mut result = [0u8; 16]; + result[0..4].copy_from_slice(&color_from_u8(r)); + result[4..8].copy_from_slice(&color_from_u8(g)); + result[8..12].copy_from_slice(&color_from_u8(b)); + result[12..16].copy_from_slice(&color_from_u8(a)); + result } diff --git a/compositor_render/src/transformations/layout/shader.rs b/compositor_render/src/transformations/layout/shader.rs index 12fcc6243..55cbd00a6 100644 --- a/compositor_render/src/transformations/layout/shader.rs +++ b/compositor_render/src/transformations/layout/shader.rs @@ -1,16 +1,24 @@ use std::sync::Arc; -use crate::wgpu::{ - common_pipeline::{self, CreateShaderError, Sampler}, - texture::{NodeTexture, NodeTextureState}, - WgpuCtx, WgpuErrorScope, +use tracing::error; + +use crate::{ + wgpu::{ + common_pipeline::{self, CreateShaderError, Sampler}, + texture::{NodeTexture, NodeTextureState}, + WgpuCtx, WgpuErrorScope, + }, + Resolution, }; +use super::{params::ParamsBindGroups, RenderLayout}; + #[derive(Debug)] pub struct LayoutShader { pipeline: wgpu::RenderPipeline, sampler: Sampler, texture_bgl: wgpu::BindGroupLayout, + params_bind_groups: ParamsBindGroups, } impl LayoutShader { @@ -32,8 +40,8 @@ impl LayoutShader { shader_module: wgpu::ShaderModule, ) -> Result { let sampler = Sampler::new(&wgpu_ctx.device); - let texture_bgl = common_pipeline::create_single_texture_bgl(&wgpu_ctx.device); + let params_bind_groups = ParamsBindGroups::new(wgpu_ctx); let pipeline_layout = wgpu_ctx @@ -42,12 +50,13 @@ impl LayoutShader { label: Some("shader transformation pipeline layout"), bind_group_layouts: &[ &texture_bgl, - &wgpu_ctx.uniform_bgl, + ¶ms_bind_groups.bind_group_1_layout, + ¶ms_bind_groups.bind_group_2_layout, &sampler.bind_group_layout, ], push_constant_ranges: &[wgpu::PushConstantRange { stages: wgpu::ShaderStages::VERTEX_FRAGMENT, - range: 0..4, + range: 0..16, }], }); @@ -61,18 +70,31 @@ impl LayoutShader { pipeline, sampler, texture_bgl, + params_bind_groups, }) } pub fn render( &self, wgpu_ctx: &Arc, - params: &wgpu::BindGroup, + output_resolution: Resolution, + layouts: Vec, textures: &[Option<&NodeTexture>], target: &NodeTextureState, ) { + let layout_infos = self + .params_bind_groups + .update(wgpu_ctx, output_resolution, layouts); let input_texture_bgs: Vec = self.input_textures_bg(wgpu_ctx, textures); + if layout_infos.len() != input_texture_bgs.len() { + error!( + "Layout infos len ({:?}) and textures bind groups count ({:?}) mismatch", + layout_infos.len(), + input_texture_bgs.len() + ); + } + let mut encoder = wgpu_ctx.device.create_command_encoder(&Default::default()); { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { @@ -91,18 +113,24 @@ impl LayoutShader { occlusion_query_set: None, }); - for (layout_id, texture_bg) in input_texture_bgs.iter().enumerate() { + for (index, (texture_bg, layout_info)) in input_texture_bgs + .iter() + .zip(layout_infos.iter()) + .take(100) + .enumerate() + { render_pass.set_pipeline(&self.pipeline); render_pass.set_push_constants( wgpu::ShaderStages::VERTEX_FRAGMENT, 0, - &(layout_id as u32).to_le_bytes(), + &layout_info.to_bytes(), ); render_pass.set_bind_group(0, texture_bg, &[]); - render_pass.set_bind_group(1, params, &[]); - render_pass.set_bind_group(2, &self.sampler.bind_group, &[]); + render_pass.set_bind_group(1, &self.params_bind_groups.bind_group_1, &[]); + render_pass.set_bind_group(2, &self.params_bind_groups.bind_groups_2[index].0, &[]); + render_pass.set_bind_group(3, &self.sampler.bind_group, &[]); wgpu_ctx.plane.draw(&mut render_pass); } diff --git a/compositor_render/src/transformations/web_renderer.rs b/compositor_render/src/transformations/web_renderer.rs index bd6fbc918..7f306a7c5 100644 --- a/compositor_render/src/transformations/web_renderer.rs +++ b/compositor_render/src/transformations/web_renderer.rs @@ -10,6 +10,8 @@ mod renderer; #[path = "web_renderer/disabled_renderer.rs"] mod renderer; +mod tranformation_matrices; + pub use renderer::*; pub mod chromium_context; diff --git a/compositor_render/src/transformations/web_renderer/browser_client.rs b/compositor_render/src/transformations/web_renderer/browser_client.rs index 52a707bd9..491f16491 100644 --- a/compositor_render/src/transformations/web_renderer/browser_client.rs +++ b/compositor_render/src/transformations/web_renderer/browser_client.rs @@ -1,16 +1,16 @@ use std::sync::{Arc, Mutex}; -use crate::{ - transformations::layout::{vertices_transformation_matrix, Position}, - Resolution, -}; +use crate::Resolution; use bytes::Bytes; use compositor_chromium::cef; use log::error; use crate::transformations::web_renderer::{FrameData, SourceTransforms}; -use super::GET_FRAME_POSITIONS_MESSAGE; +use super::{ + tranformation_matrices::{vertices_transformation_matrix, Position}, + GET_FRAME_POSITIONS_MESSAGE, +}; #[derive(Clone)] pub(super) struct BrowserClient { diff --git a/compositor_render/src/transformations/layout/transformation_matrices.rs b/compositor_render/src/transformations/web_renderer/tranformation_matrices.rs similarity index 54% rename from compositor_render/src/transformations/layout/transformation_matrices.rs rename to compositor_render/src/transformations/web_renderer/tranformation_matrices.rs index 0c1c26767..4168f1ed9 100644 --- a/compositor_render/src/transformations/layout/transformation_matrices.rs +++ b/compositor_render/src/transformations/web_renderer/tranformation_matrices.rs @@ -2,57 +2,8 @@ use nalgebra_glm::{rotate_z, scale, translate, vec3, Mat4, Vec3}; use crate::Resolution; -use super::RenderLayout; - -impl RenderLayout { - /// Returns matrix that transforms input plane vertices - /// (located in corners of clip space), to final position - pub(super) fn vertices_transformation_matrix(&self, output_resolution: &Resolution) -> Mat4 { - vertices_transformation_matrix( - &Position { - top: self.top, - left: self.left, - width: self.width, - height: self.height, - rotation_degrees: self.rotation_degrees, - }, - output_resolution, - ) - } - - pub(super) fn texture_coords_transformation_matrix( - &self, - input_resolution: &Option, - ) -> Mat4 { - let Some(input_resolution) = input_resolution else { - return Mat4::identity(); - }; - - match self.content { - super::RenderLayoutContent::Color(_) => Mat4::identity(), - super::RenderLayoutContent::ChildNode { ref crop, .. } => { - let x_scale = crop.width / input_resolution.width as f32; - let y_scale = crop.height / input_resolution.height as f32; - - let x_translate = crop.left / input_resolution.width as f32; - let y_translate = crop.top / input_resolution.height as f32; - - let mut transform_texture_matrix = Mat4::identity(); - transform_texture_matrix = translate( - &transform_texture_matrix, - &vec3(x_translate, y_translate, 0.0), - ); - transform_texture_matrix = - scale(&transform_texture_matrix, &vec3(x_scale, y_scale, 1.0)); - - transform_texture_matrix - } - } - } -} - #[derive(Debug)] -pub(crate) struct Position { +pub(super) struct Position { pub(crate) top: f32, pub(crate) left: f32, pub(crate) width: f32, @@ -60,7 +11,7 @@ pub(crate) struct Position { pub(crate) rotation_degrees: f32, } -pub(crate) fn vertices_transformation_matrix( +pub(super) fn vertices_transformation_matrix( position: &Position, output_resolution: &Resolution, ) -> Mat4 { From 7ec0fdc7e3b0dbccba33b06b28217199adb752d6 Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:46:05 +0200 Subject: [PATCH 02/51] [vk-video] Various minor fixes (#829) --- vk-video/src/parser/au_splitter.rs | 11 ++--------- vk-video/src/vulkan_decoder/vulkan_ctx.rs | 24 +++++++---------------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/vk-video/src/parser/au_splitter.rs b/vk-video/src/parser/au_splitter.rs index ad46ffabd..580bd4b28 100644 --- a/vk-video/src/parser/au_splitter.rs +++ b/vk-video/src/parser/au_splitter.rs @@ -46,20 +46,17 @@ impl AUSplitter { // defguardp first_mb_in_slice_zero(a) // when a.first_mb_in_slice == 0 and // a.nal_unit_type in [1, 2, 5] -// fn first_mb_in_slice_zero(slice: &Slice) -> bool { slice.header.first_mb_in_slice == 0 } // defguardp frame_num_differs(a, b) when a.frame_num != b.frame_num -// fn frame_num_differs(last: &Slice, curr: &Slice) -> bool { last.header.frame_num != curr.header.frame_num } // defguardp pic_parameter_set_id_differs(a, b) // when a.pic_parameter_set_id != b.pic_parameter_set_id -// fn pps_id_differs(last: &Slice, curr: &Slice) -> bool { last.pps_id != curr.pps_id } @@ -67,7 +64,6 @@ fn pps_id_differs(last: &Slice, curr: &Slice) -> bool { // defguardp field_pic_flag_differs(a, b) when a.field_pic_flag != b.field_pic_flag // // defguardp bottom_field_flag_differs(a, b) when a.bottom_field_flag != b.bottom_field_flag -// fn field_pic_flag_differs(last: &Slice, curr: &Slice) -> bool { last.header.field_pic != curr.header.field_pic } @@ -75,7 +71,6 @@ fn field_pic_flag_differs(last: &Slice, curr: &Slice) -> bool { // defguardp nal_ref_idc_differs_one_zero(a, b) // when (a.nal_ref_idc == 0 or b.nal_ref_idc == 0) and // a.nal_ref_idc != b.nal_ref_idc -// fn nal_ref_idc_differs_one_zero(last: &Slice, curr: &Slice) -> bool { (last.nal_header.nal_ref_idc() == 0 || curr.nal_header.nal_ref_idc() == 0) && last.nal_header.nal_ref_idc() != curr.nal_header.nal_ref_idc() @@ -85,7 +80,6 @@ fn nal_ref_idc_differs_one_zero(last: &Slice, curr: &Slice) -> bool { // when a.pic_order_cnt_type == 0 and b.pic_order_cnt_type == 0 and // (a.pic_order_cnt_lsb != b.pic_order_cnt_lsb or // a.delta_pic_order_cnt_bottom != b.delta_pic_order_cnt_bottom) -// fn pic_order_cnt_zero_check(last: &Slice, curr: &Slice) -> bool { let (last_pic_order_cnt_lsb, last_delta_pic_order_cnt_bottom) = match last.header.pic_order_cnt_lsb { @@ -111,20 +105,19 @@ fn pic_order_cnt_zero_check(last: &Slice, curr: &Slice) -> bool { || last_delta_pic_order_cnt_bottom != curr_delta_pic_order_cnt_bottom } +// TODO // defguardp pic_order_cnt_one_check_zero(a, b) // when a.pic_order_cnt_type == 1 and b.pic_order_cnt_type == 1 and // hd(a.delta_pic_order_cnt) != hd(b.delta_pic_order_cnt) -// TODO +// TODO // defguardp pic_order_cnt_one_check_one(a, b) // when a.pic_order_cnt_type == 1 and b.pic_order_cnt_type == 1 and // hd(hd(a.delta_pic_order_cnt)) != hd(hd(b.delta_pic_order_cnt)) -// TODO // defguardp idr_and_non_idr(a, b) // when (a.nal_unit_type == 5 or b.nal_unit_type == 5) and // a.nal_unit_type != b.nal_unit_type -// fn idr_and_non_idr(last: &Slice, curr: &Slice) -> bool { (last.nal_header.nal_unit_type().id() == 5) ^ (curr.nal_header.nal_unit_type().id() == 5) } diff --git a/vk-video/src/vulkan_decoder/vulkan_ctx.rs b/vk-video/src/vulkan_decoder/vulkan_ctx.rs index befb3c19b..4aa4bb185 100644 --- a/vk-video/src/vulkan_decoder/vulkan_ctx.rs +++ b/vk-video/src/vulkan_decoder/vulkan_ctx.rs @@ -4,7 +4,7 @@ use std::{ }; use ash::{vk, Entry}; -use tracing::{error, info}; +use tracing::{debug, error}; use super::{ Allocator, CommandBuffer, CommandPool, DebugMessenger, Device, H264ProfileInfo, Instance, @@ -142,13 +142,6 @@ impl VulkanCtx { ) -> Result { let entry = Arc::new(unsafe { Entry::load()? }); - let instance_extension_properties = - unsafe { entry.enumerate_instance_extension_properties(None)? }; - info!( - "instance_extension_properties amount: {}", - instance_extension_properties.len() - ); - let api_version = vk::make_api_version(0, 1, 3, 0); let app_info = vk::ApplicationInfo { api_version, @@ -248,9 +241,6 @@ impl VulkanCtx { let wgpu_features = wgpu_features | wgpu::Features::TEXTURE_FORMAT_NV12; - // TODO: we can only get the required extensions after exposing the adapter; the creation - // of the adapter and verification of whether the device supports all extensions should - // happen while picking the device. let wgpu_extensions = wgpu_adapter .adapter .required_device_extensions(wgpu_features); @@ -495,7 +485,7 @@ fn find_device<'a>( .max_dpb_slots(caps.max_dpb_slots) .max_active_reference_pictures(caps.max_active_reference_pictures) .std_header_version(caps.std_header_version); - info!("caps: {caps:#?}"); + debug!("video_caps: {caps:#?}"); let flags = decode_caps.flags; @@ -563,7 +553,7 @@ fn find_device<'a>( .contains(vk::QueueFlags::VIDEO_DECODE_KHR) }) .map(|(i, _)| i) - .collect::>(); // TODO: have to split the queues + .collect::>(); let Some(transfer_queue_idx) = queues .iter() @@ -603,10 +593,10 @@ fn find_device<'a>( continue; }; - info!("deocde_caps: {decode_caps:#?}"); - info!("h264_caps: {h264_caps:#?}"); - info!("dpb_format_properties: {h264_dpb_format_properties:#?}"); - info!("dst_format_properties: {h264_dst_format_properties:#?}"); + debug!("deocde_caps: {decode_caps:#?}"); + debug!("h264_caps: {h264_caps:#?}"); + debug!("dpb_format_properties: {h264_dpb_format_properties:#?}"); + debug!("dst_format_properties: {h264_dst_format_properties:#?}"); return Ok(ChosenDevice { physical_device: device, From 666659bcb7d3df61d136d55e41f30ddde7b525f5 Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:38:56 +0200 Subject: [PATCH 03/51] [vk-video] Get picture dimensions for download/transfer correctly (#828) --- vk-video/src/vulkan_decoder.rs | 20 ++++++++----- .../src/vulkan_decoder/session_resources.rs | 29 ++++++++++++++----- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/vk-video/src/vulkan_decoder.rs b/vk-video/src/vulkan_decoder.rs index f2152e472..985d9ca2c 100644 --- a/vk-video/src/vulkan_decoder.rs +++ b/vk-video/src/vulkan_decoder.rs @@ -225,14 +225,14 @@ impl VulkanDecoder<'_> { Some(session) => session.process_sps( &self.vulkan_ctx, &self.command_buffers.decode_buffer, - sps, + sps.clone(), &self.sync_structures.fence_memory_barrier_completed, )?, None => { self.video_session_resources = Some(VideoSessionResources::new_from_sps( &self.vulkan_ctx, &self.command_buffers.decode_buffer, - sps, + sps.clone(), &self.sync_structures.fence_memory_barrier_completed, )?) } @@ -245,7 +245,7 @@ impl VulkanDecoder<'_> { self.video_session_resources .as_mut() .ok_or(VulkanDecoderError::NoSession)? - .process_pps(pps)?; + .process_pps(pps.clone())?; Ok(()) } @@ -502,9 +502,15 @@ impl VulkanDecoder<'_> { self.reference_id_to_dpb_slot_index .insert(reference_id, new_reference_slot_index); - // TODO: those are not the real dimensions of the image. the real dimensions should be - // calculated from the sps - let dimensions = video_session_resources.video_session.max_coded_extent; + let sps = video_session_resources + .sps + .get(&decode_information.sps_id) + .ok_or(VulkanDecoderError::NoSession)?; + + let dimensions = vk::Extent2D { + width: sps.width()?, + height: sps.height()?, + }; Ok(DecodeOutput { image: target_image, @@ -871,8 +877,6 @@ impl VulkanDecoder<'_> { ) }; - // TODO: in this section, we shouldn't be using `max_coded_extent` and use the real frame - // resolution let y_plane_size = dimensions.width as u64 * dimensions.height as u64; let dst_buffer = Buffer::new_transfer( diff --git a/vk-video/src/vulkan_decoder/session_resources.rs b/vk-video/src/vulkan_decoder/session_resources.rs index e59c71e09..f8877d661 100644 --- a/vk-video/src/vulkan_decoder/session_resources.rs +++ b/vk-video/src/vulkan_decoder/session_resources.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use ash::vk; use h264_reader::nal::{pps::PicParameterSet, sps::SeqParameterSet}; use images::DecodingImages; @@ -15,13 +17,15 @@ pub(super) struct VideoSessionResources<'a> { pub(crate) video_session: VideoSession, pub(crate) parameters_manager: VideoSessionParametersManager, pub(crate) decoding_images: DecodingImages<'a>, + pub(crate) sps: HashMap, + pub(crate) pps: HashMap<(u8, u8), PicParameterSet>, } impl VideoSessionResources<'_> { pub(crate) fn new_from_sps( vulkan_ctx: &VulkanCtx, decode_buffer: &CommandBuffer, - sps: &SeqParameterSet, + sps: SeqParameterSet, fence_memory_barrier_completed: &Fence, ) -> Result { let profile = H264ProfileInfo::decode_h264_yuv420(); @@ -46,7 +50,7 @@ impl VideoSessionResources<'_> { let mut parameters_manager = VideoSessionParametersManager::new(vulkan_ctx, video_session.session)?; - parameters_manager.put_sps(sps)?; + parameters_manager.put_sps(&sps)?; let decoding_images = Self::new_decoding_images( vulkan_ctx, @@ -56,10 +60,14 @@ impl VideoSessionResources<'_> { fence_memory_barrier_completed, )?; + let sps = HashMap::from_iter([(sps.id().id(), sps)]); + Ok(VideoSessionResources { video_session, parameters_manager, decoding_images, + sps, + pps: HashMap::new(), }) } @@ -67,7 +75,7 @@ impl VideoSessionResources<'_> { &mut self, vulkan_ctx: &VulkanCtx, decode_buffer: &CommandBuffer, - sps: &SeqParameterSet, + sps: SeqParameterSet, fence_memory_barrier_completed: &Fence, ) -> Result<(), VulkanDecoderError> { let profile = H264ProfileInfo::decode_h264_yuv420(); @@ -85,7 +93,7 @@ impl VideoSessionResources<'_> { && self.video_session.max_dpb_slots >= max_dpb_slots { // no need to change the session - self.parameters_manager.put_sps(sps)?; + self.parameters_manager.put_sps(&sps)?; return Ok(()); } @@ -100,7 +108,7 @@ impl VideoSessionResources<'_> { self.parameters_manager .change_session(self.video_session.session)?; - self.parameters_manager.put_sps(sps)?; + self.parameters_manager.put_sps(&sps)?; self.decoding_images = Self::new_decoding_images( vulkan_ctx, @@ -110,11 +118,18 @@ impl VideoSessionResources<'_> { fence_memory_barrier_completed, )?; + self.sps.insert(sps.id().id(), sps); + Ok(()) } - pub(crate) fn process_pps(&mut self, pps: &PicParameterSet) -> Result<(), VulkanDecoderError> { - self.parameters_manager.put_pps(pps) + pub(crate) fn process_pps(&mut self, pps: PicParameterSet) -> Result<(), VulkanDecoderError> { + self.parameters_manager.put_pps(&pps)?; + self.pps.insert( + (pps.seq_parameter_set_id.id(), pps.pic_parameter_set_id.id()), + pps, + ); + Ok(()) } fn new_decoding_images<'a>( From dd20c3b6e3fb14fa45a5d50cc66aadf8d6ba0355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Radkowski?= Date: Mon, 21 Oct 2024 12:02:01 +0200 Subject: [PATCH 04/51] Flush encoder on EOS (#832) --- .../src/pipeline/encoder/ffmpeg_h264.rs | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs b/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs index c6ebe37f9..9eeb2339c 100644 --- a/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs +++ b/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs @@ -4,6 +4,7 @@ use compositor_render::{Frame, FrameData, OutputId, Resolution}; use crossbeam_channel::{Receiver, Sender}; use ffmpeg_next::{ codec::{Context, Id}, + encoder::Video, format::Pixel, frame, Dictionary, Packet, Rational, }; @@ -241,46 +242,63 @@ fn run_encoder_thread( continue; } - loop { - match encoder.receive_packet(&mut packet) { - Ok(_) => { - match encoded_chunk_from_av_packet( - &packet, - EncodedChunkKind::Video(VideoCodec::H264), - 1_000_000, - ) { - Ok(chunk) => { - trace!(pts=?packet.pts(), "H264 encoder produced an encoded packet."); - if packet_sender.send(EncoderOutputEvent::Data(chunk)).is_err() { - warn!("Failed to send encoded video from H264 encoder. Channel closed."); - return Ok(()); - } - } - Err(e) => { - warn!("failed to parse an ffmpeg packet received from encoder: {e}",); - break; - } - } - } - - Err(ffmpeg_next::Error::Other { - errno: ffmpeg_next::error::EAGAIN, - }) => break, // encoder needs more frames to produce a packet - - Err(e) => { - error!("Encoder error: {e}."); - break; - } + while let Some(chunk) = receive_chunk(&mut encoder, &mut packet) { + if packet_sender.send(EncoderOutputEvent::Data(chunk)).is_err() { + warn!("Failed to send encoded video from H264 encoder. Channel closed."); + return Ok(()); } } } + // Flush the encoder + if let Err(e) = encoder.send_eof() { + error!("Failed to enter draining mode on encoder: {e}."); + } + while let Some(chunk) = receive_chunk(&mut encoder, &mut packet) { + if packet_sender.send(EncoderOutputEvent::Data(chunk)).is_err() { + warn!("Failed to send encoded video from H264 encoder. Channel closed."); + return Ok(()); + } + } + if let Err(_err) = packet_sender.send(EncoderOutputEvent::VideoEOS) { warn!("Failed to send EOS from H264 encoder. Channel closed.") } Ok(()) } +fn receive_chunk(encoder: &mut Video, packet: &mut Packet) -> Option { + match encoder.receive_packet(packet) { + Ok(_) => { + match encoded_chunk_from_av_packet( + packet, + EncodedChunkKind::Video(VideoCodec::H264), + 1_000_000, + ) { + Ok(chunk) => { + trace!(pts=?packet.pts(), "H264 encoder produced an encoded packet."); + Some(chunk) + } + Err(e) => { + warn!("failed to parse an ffmpeg packet received from encoder: {e}",); + None + } + } + } + + Err(ffmpeg_next::Error::Eof) => None, + + Err(ffmpeg_next::Error::Other { + errno: ffmpeg_next::error::EAGAIN, + }) => None, // encoder needs more frames to produce a packet + + Err(e) => { + error!("Encoder error: {e}."); + None + } + } +} + #[derive(Debug)] struct FrameConversionError(String); From abf9e9502811e4ec1ef4b6021c6cf38e34bba3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Radkowski?= Date: Mon, 21 Oct 2024 15:38:02 +0200 Subject: [PATCH 05/51] Forbid output update after EOS (#833) --- compositor_pipeline/src/pipeline.rs | 22 +++++++++++++++++++ .../src/pipeline/encoder/opus.rs | 2 +- .../src/pipeline/pipeline_output.rs | 4 ++++ compositor_pipeline/src/queue/queue_thread.rs | 8 +++++-- .../src/tests/offline_processing.rs | 2 +- 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/compositor_pipeline/src/pipeline.rs b/compositor_pipeline/src/pipeline.rs index 6e534d124..465f4b641 100644 --- a/compositor_pipeline/src/pipeline.rs +++ b/compositor_pipeline/src/pipeline.rs @@ -378,6 +378,15 @@ impl Pipeline { .outputs .get(&output_id) .ok_or_else(|| UpdateSceneError::OutputNotRegistered(output_id.clone()))?; + + if let Some(cond) = &output.video_end_condition { + if cond.did_output_end() { + // Ignore updates after EOS + warn!("Received output update on a finished output"); + return Ok(()); + } + } + let (Some(resolution), Some(frame_format)) = ( output.output.resolution(), output.output.output_frame_format(), @@ -396,6 +405,19 @@ impl Pipeline { output_id: &OutputId, audio: AudioMixingParams, ) -> Result<(), UpdateSceneError> { + let output = self + .outputs + .get(output_id) + .ok_or_else(|| UpdateSceneError::OutputNotRegistered(output_id.clone()))?; + + if let Some(cond) = &output.audio_end_condition { + if cond.did_output_end() { + // Ignore updates after EOS + warn!("Received output update on a finished output"); + return Ok(()); + } + } + info!(?output_id, "Update audio mixer {:#?}", audio); self.audio_mixer.update_output(output_id, audio) } diff --git a/compositor_pipeline/src/pipeline/encoder/opus.rs b/compositor_pipeline/src/pipeline/encoder/opus.rs index 1e83b022a..97d333189 100644 --- a/compositor_pipeline/src/pipeline/encoder/opus.rs +++ b/compositor_pipeline/src/pipeline/encoder/opus.rs @@ -38,7 +38,7 @@ impl OpusEncoder { std::thread::Builder::new() .name("Opus encoder thread".to_string()) .spawn(move || { - let _span = span!(Level::INFO, "Opus encoder thread",).entered(); + let _span = span!(Level::INFO, "Opus encoder thread").entered(); run_encoder_thread(encoder, samples_batch_receiver, packets_sender) }) .unwrap(); diff --git a/compositor_pipeline/src/pipeline/pipeline_output.rs b/compositor_pipeline/src/pipeline/pipeline_output.rs index eb9b79aaa..cfb695886 100644 --- a/compositor_pipeline/src/pipeline/pipeline_output.rs +++ b/compositor_pipeline/src/pipeline/pipeline_output.rs @@ -234,6 +234,10 @@ impl PipelineOutputEndConditionState { EosStatus::None } + pub(super) fn did_output_end(&self) -> bool { + self.did_end + } + pub(super) fn on_input_registered(&mut self, input_id: &InputId) { self.on_event(StateChange::AddInput(input_id)) } diff --git a/compositor_pipeline/src/queue/queue_thread.rs b/compositor_pipeline/src/queue/queue_thread.rs index 4bd47ff63..b9f3c9dc4 100644 --- a/compositor_pipeline/src/queue/queue_thread.rs +++ b/compositor_pipeline/src/queue/queue_thread.rs @@ -236,7 +236,9 @@ impl VideoQueueProcessor { let pts = frames_batch.pts; debug!(?pts, "Pushing video frames."); if is_required { - self.sender.send(frames_batch).unwrap() + if self.sender.send(frames_batch).is_err() { + warn!(?pts, "Dropping video frame on queue output."); + } } else { let send_deadline = self.queue_start_time.add(frames_batch.pts); if self @@ -341,7 +343,9 @@ impl AudioQueueProcessor { let pts_range = (samples.start_pts, samples.end_pts); debug!(?pts_range, "Pushing audio samples."); if is_required { - self.sender.send(samples).unwrap() + if self.sender.send(samples).is_err() { + warn!(?pts_range, "Dropping audio batch on queue output."); + } } else if self.sender.try_send(samples).is_err() { warn!(?pts_range, "Dropping audio batch on queue output.") } diff --git a/integration_tests/src/tests/offline_processing.rs b/integration_tests/src/tests/offline_processing.rs index 2cb0c72e9..1b96bd824 100644 --- a/integration_tests/src/tests/offline_processing.rs +++ b/integration_tests/src/tests/offline_processing.rs @@ -123,7 +123,7 @@ pub fn offline_processing() -> Result<()> { if !(1.9..=2.1).contains(&duration) { return Err(anyhow!("Invalid duration: {}", duration)); } - if !(930_000..=1_000_000).contains(&bit_rate) { + if !(930_000..=1_008_200).contains(&bit_rate) { return Err(anyhow!("Invalid bit rate: {}", bit_rate)); } From c18531beb8b2a91bc8b69ba71d94d9bb934d9885 Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:23:04 +0200 Subject: [PATCH 06/51] [vk-video] Add support for long-time references (#827) --- vk-video/build.rs | 14 +- vk-video/src/parser.rs | 2 + vk-video/src/parser/reference_manager.rs | 748 ++++++++++++++++------- 3 files changed, 544 insertions(+), 220 deletions(-) diff --git a/vk-video/build.rs b/vk-video/build.rs index 6fc1495c2..928e40213 100644 --- a/vk-video/build.rs +++ b/vk-video/build.rs @@ -1,13 +1,13 @@ fn main() { cfg_aliases::cfg_aliases! { - vulkan: { - any( - windows, - all( - unix, - not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")) - ) + vulkan: { + any( + windows, + all( + unix, + not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")) ) + ) }, } } diff --git a/vk-video/src/parser.rs b/vk-video/src/parser.rs index 622e86187..1fbcc41c0 100644 --- a/vk-video/src/parser.rs +++ b/vk-video/src/parser.rs @@ -32,8 +32,10 @@ pub struct DecodeInformation { } #[derive(Debug, Clone)] +#[allow(non_snake_case)] pub(crate) struct ReferencePictureInfo { pub(crate) id: ReferenceId, + pub(crate) LongTermPicNum: Option, pub(crate) picture_info: PictureInfo, } diff --git a/vk-video/src/parser/reference_manager.rs b/vk-video/src/parser/reference_manager.rs index 05ad2d4ad..4eb5f8d4f 100644 --- a/vk-video/src/parser/reference_manager.rs +++ b/vk-video/src/parser/reference_manager.rs @@ -3,15 +3,14 @@ use std::sync::Arc; use h264_reader::nal::{ pps::PicParameterSet, slice::{ - DecRefPicMarking, ModificationOfPicNums, NumRefIdxActive, RefPicListModifications, - SliceHeader, + DecRefPicMarking, MemoryManagementControlOperation, ModificationOfPicNums, NumRefIdxActive, + RefPicListModifications, SliceHeader, }, sps::SeqParameterSet, }; use super::{ - DecodeInformation, DecoderInstruction, ParserError, PictureInfo, ReferencePictureInfo, Slice, - SpsExt, + DecodeInformation, DecoderInstruction, PictureInfo, ReferencePictureInfo, Slice, SpsExt, }; #[derive(Debug, thiserror::Error)] @@ -19,18 +18,12 @@ pub enum ReferenceManagementError { #[error("B frames are not supported")] BFramesNotSupported, - #[error("Long-term references are not supported")] - LongTermRefsNotSupported, - #[error("SI frames are not supported")] SIFramesNotSupported, #[error("SP frames are not supported")] SPFramesNotSupported, - #[error("Adaptive memory control decoded reference picture marking process is not supported")] - AdaptiveMemCtlNotSupported, - #[error("PicOrderCntType {0} is not supperted")] PicOrderCntTypeNotSupported(u8), @@ -42,12 +35,24 @@ pub enum ReferenceManagementError { pub struct ReferenceId(usize); #[derive(Debug, Default)] +#[allow(non_snake_case)] pub(crate) struct ReferenceContext { pictures: ReferencePictures, next_reference_id: ReferenceId, - _previous_frame_num: usize, + previous_frame_num: usize, prev_pic_order_cnt_msb: i32, prev_pic_order_cnt_lsb: i32, + MaxLongTermFrameIdx: MaxLongTermFrameIdx, + prevFrameNumOffset: i64, + previous_picture_included_mmco_equal_5: bool, + current_picture_included_mmco_equal_5: bool, +} + +#[derive(Debug, Default)] +enum MaxLongTermFrameIdx { + #[default] + NoLongTermFrameIndices, + Idx(u64), } impl ReferenceContext { @@ -61,12 +66,34 @@ impl ReferenceContext { *self = Self { pictures: ReferencePictures::default(), next_reference_id: ReferenceId::default(), - _previous_frame_num: 0, + previous_frame_num: 0, prev_pic_order_cnt_msb: 0, prev_pic_order_cnt_lsb: 0, + MaxLongTermFrameIdx: MaxLongTermFrameIdx::NoLongTermFrameIndices, + prevFrameNumOffset: 0, + previous_picture_included_mmco_equal_5: false, + current_picture_included_mmco_equal_5: false, }; } + #[allow(non_snake_case)] + fn add_long_term_reference( + &mut self, + header: Arc, + LongTermFrameIdx: u64, + pic_order_cnt: [i32; 2], + ) -> ReferenceId { + let id = self.get_next_reference_id(); + self.pictures.long_term.push(LongTermReferencePicture { + header, + id, + LongTermFrameIdx, + pic_order_cnt, + }); + + id + } + fn add_short_term_reference( &mut self, header: Arc, @@ -86,7 +113,7 @@ impl ReferenceContext { mut slices: Vec, sps: &SeqParameterSet, pps: &PicParameterSet, - ) -> Result, ParserError> { + ) -> Result, ReferenceManagementError> { let header = slices.last().unwrap().header.clone(); // maybe this should be done in a different place, but if you think about it, there's not @@ -101,92 +128,298 @@ impl ReferenceContext { rbsp_bytes.append(&mut slice.rbsp_bytes); } - match header.dec_ref_pic_marking { + let decode_info = + self.decode_information_for_frame(header.clone(), slice_indices, rbsp_bytes, sps, pps)?; + + let decoder_instructions = match &header.clone().dec_ref_pic_marking { Some(DecRefPicMarking::Idr { long_term_reference_flag, .. - }) => { - if long_term_reference_flag { - Err(ReferenceManagementError::LongTermRefsNotSupported)?; - } + }) => self.reference_picture_marking_process_idr( + header, + decode_info, + *long_term_reference_flag, + )?, - let decode_info = self.decode_information_for_frame( - header.clone(), - slice_indices, - rbsp_bytes, + Some(DecRefPicMarking::SlidingWindow) => { + self.reference_picture_marking_process_sliding_window(sps, header, decode_info)? + } + Some(DecRefPicMarking::Adaptive(memory_management_control_operations)) => self + .reference_picture_marking_process_adaptive( sps, - pps, - )?; + header, + decode_info, + memory_management_control_operations, + )?, - self.reset_state(); + // this picture is not a reference + None => vec![DecoderInstruction::Decode { decode_info }], + }; - let reference_id = - self.add_short_term_reference(header, decode_info.picture_info.PicOrderCnt); + self.previous_picture_included_mmco_equal_5 = self.current_picture_included_mmco_equal_5; + self.current_picture_included_mmco_equal_5 = false; - Ok(vec![DecoderInstruction::Idr { - decode_info, - reference_id, - }]) + Ok(decoder_instructions) + } + + fn remove_long_term_ref( + &mut self, + long_term_frame_idx: u64, + ) -> Result { + for (i, frame) in self.pictures.long_term.iter().enumerate() { + if frame.LongTermFrameIdx == long_term_frame_idx { + return Ok(self.pictures.long_term.remove(i)); + } + } + + Err(ReferenceManagementError::IncorrectData( + format!("cannot remove long term reference with id {long_term_frame_idx}, because it does not exist") + )) + } + + #[allow(non_snake_case)] + fn remove_short_term_ref( + &mut self, + current_frame_num: i64, + sps: &SeqParameterSet, + pic_num_to_remove: i64, + ) -> Result { + for (i, picture) in self.pictures.short_term.iter().enumerate() { + let PicNum = decode_picture_numbers_for_short_term_ref( + picture.header.frame_num.into(), + current_frame_num, + sps, + ) + .PicNum; + + if PicNum == pic_num_to_remove { + return Ok(self.pictures.short_term.remove(i)); } + } - Some(DecRefPicMarking::SlidingWindow) => { - let num_short_term = self.pictures.short_term.len(); - let num_long_term = self.pictures.long_term.len(); + Err(ReferenceManagementError::IncorrectData( + format!("cannot remove long term reference with pic num {pic_num_to_remove}, because it does not exist") + )) + } - let decode_info = self.decode_information_for_frame( - header.clone(), - slice_indices, - rbsp_bytes, - sps, - pps, - )?; - let reference_id = self - .add_short_term_reference(header.clone(), decode_info.picture_info.PicOrderCnt); + fn reference_picture_marking_process_adaptive( + &mut self, + sps: &SeqParameterSet, + header: Arc, + decode_info: DecodeInformation, + memory_management_control_operations: &[MemoryManagementControlOperation], + ) -> Result, ReferenceManagementError> { + let mut decoder_instructions = Vec::new(); + + let mut new_long_term_frame_idx = None; + + for memory_management_control_operation in memory_management_control_operations { + match memory_management_control_operation { + MemoryManagementControlOperation::ShortTermUnusedForRef { + difference_of_pic_nums_minus1, + } => { + let pic_num_to_remove = + header.frame_num as i64 - (*difference_of_pic_nums_minus1 as i64 + 1); + + let removed = self.remove_short_term_ref( + header.frame_num.into(), + sps, + pic_num_to_remove, + )?; - let mut decoder_instructions = vec![DecoderInstruction::DecodeAndStoreAs { - decode_info, - reference_id, - }]; + decoder_instructions.push(DecoderInstruction::Drop { + reference_ids: vec![removed.id], + }); + } - if num_short_term + num_long_term == sps.max_num_ref_frames.max(1) as usize - && !self.pictures.short_term.is_empty() - { - let (idx, _) = self + MemoryManagementControlOperation::LongTermUnusedForRef { long_term_pic_num } => { + let removed = self.remove_long_term_ref(*long_term_pic_num as u64)?; + + decoder_instructions.push(DecoderInstruction::Drop { + reference_ids: vec![removed.id], + }); + } + + MemoryManagementControlOperation::ShortTermUsedForLongTerm { + difference_of_pic_nums_minus1, + long_term_frame_idx, + } => { + if let Ok(removed) = self.remove_long_term_ref(*long_term_frame_idx as u64) { + decoder_instructions.push(DecoderInstruction::Drop { + reference_ids: vec![removed.id], + }); + } + + let pic_num_to_remove = + header.frame_num as i64 - (*difference_of_pic_nums_minus1 as i64 + 1); + + let picture = self.remove_short_term_ref( + header.frame_num.into(), + sps, + pic_num_to_remove, + )?; + + self.pictures.long_term.push(LongTermReferencePicture { + header: picture.header, + LongTermFrameIdx: *long_term_frame_idx as u64, + pic_order_cnt: picture.pic_order_cnt, + id: picture.id, + }); + } + + MemoryManagementControlOperation::MaxUsedLongTermFrameRef { + max_long_term_frame_idx_plus1, + } => { + if *max_long_term_frame_idx_plus1 != 0 { + self.MaxLongTermFrameIdx = + MaxLongTermFrameIdx::Idx(*max_long_term_frame_idx_plus1 as u64 - 1); + } else { + self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::NoLongTermFrameIndices; + } + + let max_idx = *max_long_term_frame_idx_plus1 as i128 - 1; + + let reference_ids_to_remove = self .pictures - .short_term + .long_term .iter() - .enumerate() - .min_by_key(|(_, reference)| { - reference - .decode_picture_numbers(header.frame_num as i64, sps) - .unwrap() - .FrameNumWrap - }) - .unwrap(); + .filter(|p| p.LongTermFrameIdx as i128 > max_idx) + .map(|p| p.id) + .collect(); + + self.pictures.long_term = self + .pictures + .long_term + .iter() + .filter(|p| p.LongTermFrameIdx as i128 <= max_idx) + .cloned() + .collect(); decoder_instructions.push(DecoderInstruction::Drop { - reference_ids: vec![self.pictures.short_term.remove(idx).id], + reference_ids: reference_ids_to_remove, }) } - Ok(decoder_instructions) + MemoryManagementControlOperation::AllRefPicturesUnused => { + let reference_ids = self + .pictures + .short_term + .drain(..) + .map(|p| p.id) + .chain(self.pictures.long_term.drain(..).map(|p| p.id)) + .collect(); + + self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::NoLongTermFrameIndices; + self.current_picture_included_mmco_equal_5 = true; + + decoder_instructions.push(DecoderInstruction::Drop { reference_ids }) + } + MemoryManagementControlOperation::CurrentUsedForLongTerm { + long_term_frame_idx, + } => { + if let Ok(picture) = self.remove_long_term_ref(*long_term_frame_idx as u64) { + decoder_instructions.push(DecoderInstruction::Drop { + reference_ids: vec![picture.id], + }); + } + + new_long_term_frame_idx = Some(*long_term_frame_idx as u64); + } } + } + + let reference_id = match new_long_term_frame_idx { + Some(long_term_frame_idx) => self.add_long_term_reference( + header, + long_term_frame_idx, + decode_info.picture_info.PicOrderCnt, + ), + None => self.add_short_term_reference(header, decode_info.picture_info.PicOrderCnt), + }; - Some(DecRefPicMarking::Adaptive(_)) => { - Err(ReferenceManagementError::AdaptiveMemCtlNotSupported)? + decoder_instructions.insert( + 0, + DecoderInstruction::DecodeAndStoreAs { + decode_info, + reference_id, + }, + ); + + if let MaxLongTermFrameIdx::Idx(max) = self.MaxLongTermFrameIdx { + if self.pictures.long_term.len() > max as usize + 1 { + return Err(ReferenceManagementError::IncorrectData(format!( + "there are {} long-term references, but there shouldn't be more than {max}", + self.pictures.long_term.len() + ))); } + } - // this picture is not a reference - None => Ok(vec![DecoderInstruction::Decode { - decode_info: self.decode_information_for_frame( - header, - slice_indices, - rbsp_bytes, - sps, - pps, - )?, - }]), + Ok(decoder_instructions) + } + + fn reference_picture_marking_process_sliding_window( + &mut self, + sps: &SeqParameterSet, + header: Arc, + decode_info: DecodeInformation, + ) -> Result, ReferenceManagementError> { + let num_short_term = self.pictures.short_term.len(); + let num_long_term = self.pictures.long_term.len(); + + let reference_id = + self.add_short_term_reference(header.clone(), decode_info.picture_info.PicOrderCnt); + + let mut decoder_instructions = vec![DecoderInstruction::DecodeAndStoreAs { + decode_info, + reference_id, + }]; + + if num_short_term + num_long_term == sps.max_num_ref_frames.max(1) as usize + && !self.pictures.short_term.is_empty() + { + let (idx, _) = self + .pictures + .short_term + .iter() + .enumerate() + .min_by_key(|(_, reference)| { + decode_picture_numbers_for_short_term_ref( + reference.header.frame_num.into(), + header.frame_num.into(), + sps, + ) + .FrameNumWrap + }) + .unwrap(); + + decoder_instructions.push(DecoderInstruction::Drop { + reference_ids: vec![self.pictures.short_term.remove(idx).id], + }) } + + Ok(decoder_instructions) + } + + fn reference_picture_marking_process_idr( + &mut self, + header: Arc, + decode_info: DecodeInformation, + long_term_reference_flag: bool, + ) -> Result, ReferenceManagementError> { + self.reset_state(); + + let reference_id = if long_term_reference_flag { + self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::Idx(0); + self.add_long_term_reference(header, 0, decode_info.picture_info.PicOrderCnt) + } else { + self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::NoLongTermFrameIndices; + self.add_short_term_reference(header, decode_info.picture_info.PicOrderCnt) + }; + + Ok(vec![DecoderInstruction::Idr { + decode_info, + reference_id, + }]) } fn decode_information_for_frame( @@ -196,11 +429,25 @@ impl ReferenceContext { rbsp_bytes: Vec, sps: &SeqParameterSet, pps: &PicParameterSet, - ) -> Result { + ) -> Result { let reference_list = match header.slice_type.family { h264_reader::nal::slice::SliceFamily::P => { + let num_ref_idx_l0_active = header + .num_ref_idx_active + .as_ref() + .map(|num| match num { + NumRefIdxActive::P { + num_ref_idx_l0_active_minus1, + } => Ok(*num_ref_idx_l0_active_minus1), + NumRefIdxActive::B { .. } => { + Err(ReferenceManagementError::BFramesNotSupported) + } + }) + .unwrap_or(Ok(pps.num_ref_idx_l0_default_active_minus1))? + + 1; + let mut reference_list = - self.initialize_reference_picture_list_for_frame(&header, sps, pps)?; + self.initialize_reference_picture_list_for_frame(&header, sps)?; match &header.ref_pic_list_modification { Some(RefPicListModifications::P { @@ -221,6 +468,8 @@ impl ReferenceContext { ))?, } + reference_list.truncate(num_ref_idx_l0_active as usize); + Some(reference_list) } h264_reader::nal::slice::SliceFamily::I => None, @@ -238,20 +487,85 @@ impl ReferenceContext { let pic_order_cnt = match sps.pic_order_cnt { h264_reader::nal::sps::PicOrderCntType::TypeZero { log2_max_pic_order_cnt_lsb_minus4, - } => { - // this section is very hard to read, but all of this code is just copied from the - // h.264 spec, where it looks almost exactly like this + } => self.decode_pic_order_cnt_type_zero(&header, log2_max_pic_order_cnt_lsb_minus4)?, - let max_pic_order_cnt_lsb = 2_i32.pow(log2_max_pic_order_cnt_lsb_minus4 as u32 + 4); + h264_reader::nal::sps::PicOrderCntType::TypeOne { .. } => { + Err(ReferenceManagementError::PicOrderCntTypeNotSupported(1))? + } - let (prev_pic_order_cnt_msb, prev_pic_order_cnt_lsb) = - if header.idr_pic_id.is_some() { - (0, 0) - } else { - (self.prev_pic_order_cnt_msb, self.prev_pic_order_cnt_lsb) - }; + h264_reader::nal::sps::PicOrderCntType::TypeTwo => { + self.decode_pic_order_cnt_type_two(&header, sps)? + } + }; + + Ok(DecodeInformation { + reference_list, + header: header.clone(), + slice_indices, + rbsp_bytes, + sps_id: sps.id().id(), + pps_id: pps.pic_parameter_set_id.id(), + picture_info: PictureInfo { + non_existing: false, + used_for_long_term_reference: false, + PicOrderCnt: pic_order_cnt, + FrameNum: header.frame_num, + }, + }) + } + + #[allow(non_snake_case)] + fn decode_pic_order_cnt_type_two( + &mut self, + header: &SliceHeader, + sps: &SeqParameterSet, + ) -> Result<[i32; 2], ReferenceManagementError> { + let FrameNumOffset = if header.idr_pic_id.is_some() { + 0 + } else { + let prevFrameNumOffset = if self.previous_picture_included_mmco_equal_5 { + 0 + } else { + self.prevFrameNumOffset + }; + + if self.previous_frame_num > header.frame_num.into() { + prevFrameNumOffset + sps.max_frame_num() + } else { + prevFrameNumOffset + } + }; + + let tempPicOrderCnt = if header.idr_pic_id.is_some() { + 0 + } else if header.dec_ref_pic_marking.is_none() { + 2 * (FrameNumOffset as i32 + header.frame_num as i32) - 1 + } else { + 2 * (FrameNumOffset as i32 + header.frame_num as i32) + }; + + self.prevFrameNumOffset = FrameNumOffset; + + Ok([tempPicOrderCnt; 2]) + } - let (pic_order_cnt_lsb, delta_pic_order_cnt_bottom) = match header + fn decode_pic_order_cnt_type_zero( + &mut self, + header: &SliceHeader, + log2_max_pic_order_cnt_lsb_minus4: u8, + ) -> Result<[i32; 2], ReferenceManagementError> { + // this section is very hard to read, but all of this code is just copied from the + // h.264 spec, where it looks almost exactly like this + + let max_pic_order_cnt_lsb = 2_i32.pow(log2_max_pic_order_cnt_lsb_minus4 as u32 + 4); + + let (prev_pic_order_cnt_msb, prev_pic_order_cnt_lsb) = if header.idr_pic_id.is_some() { + (0, 0) + } else { + (self.prev_pic_order_cnt_msb, self.prev_pic_order_cnt_lsb) + }; + + let (pic_order_cnt_lsb, delta_pic_order_cnt_bottom) = match header .pic_order_cnt_lsb .as_ref() .ok_or(ReferenceManagementError::IncorrectData("pic_order_cnt_lsb is not present in a slice header, but is required for decoding".into()))? @@ -268,93 +582,64 @@ impl ReferenceContext { } }; - let pic_order_cnt_lsb = pic_order_cnt_lsb as i32; - - let pic_order_cnt_msb = if pic_order_cnt_lsb < prev_pic_order_cnt_lsb - && prev_pic_order_cnt_lsb - pic_order_cnt_lsb >= max_pic_order_cnt_lsb / 2 - { - prev_pic_order_cnt_msb + max_pic_order_cnt_lsb - } else if pic_order_cnt_lsb > prev_pic_order_cnt_lsb - && pic_order_cnt_lsb - prev_pic_order_cnt_lsb > max_pic_order_cnt_lsb / 2 - { - prev_pic_order_cnt_msb - max_pic_order_cnt_lsb - } else { - prev_pic_order_cnt_msb - }; - - let pic_order_cnt = if header.field_pic == h264_reader::nal::slice::FieldPic::Frame - { - let top_field_order_cnt = pic_order_cnt_msb + pic_order_cnt_lsb; - - let bottom_field_order_cnt = top_field_order_cnt + delta_pic_order_cnt_bottom; - - top_field_order_cnt.min(bottom_field_order_cnt) - } else { - pic_order_cnt_msb + pic_order_cnt_lsb - }; + let pic_order_cnt_lsb = pic_order_cnt_lsb as i32; - self.prev_pic_order_cnt_msb = pic_order_cnt_msb; - self.prev_pic_order_cnt_lsb = pic_order_cnt_lsb; + let pic_order_cnt_msb = if pic_order_cnt_lsb < prev_pic_order_cnt_lsb + && prev_pic_order_cnt_lsb - pic_order_cnt_lsb >= max_pic_order_cnt_lsb / 2 + { + prev_pic_order_cnt_msb + max_pic_order_cnt_lsb + } else if pic_order_cnt_lsb > prev_pic_order_cnt_lsb + && pic_order_cnt_lsb - prev_pic_order_cnt_lsb > max_pic_order_cnt_lsb / 2 + { + prev_pic_order_cnt_msb - max_pic_order_cnt_lsb + } else { + prev_pic_order_cnt_msb + }; - pic_order_cnt - } + let pic_order_cnt = if header.field_pic == h264_reader::nal::slice::FieldPic::Frame { + let top_field_order_cnt = pic_order_cnt_msb + pic_order_cnt_lsb; - h264_reader::nal::sps::PicOrderCntType::TypeOne { .. } => { - Err(ReferenceManagementError::PicOrderCntTypeNotSupported(1))? - } + let bottom_field_order_cnt = top_field_order_cnt + delta_pic_order_cnt_bottom; - h264_reader::nal::sps::PicOrderCntType::TypeTwo => match header.dec_ref_pic_marking { - None => 2 * header.frame_num as i32 - 1, - Some(DecRefPicMarking::Idr { .. }) | Some(DecRefPicMarking::SlidingWindow) => { - 2 * header.frame_num as i32 - } - Some(DecRefPicMarking::Adaptive(..)) => { - Err(ReferenceManagementError::AdaptiveMemCtlNotSupported)? - } - }, + top_field_order_cnt.min(bottom_field_order_cnt) + } else { + pic_order_cnt_msb + pic_order_cnt_lsb }; - let pic_order_cnt = [pic_order_cnt; 2]; + self.prev_pic_order_cnt_msb = pic_order_cnt_msb; + self.prev_pic_order_cnt_lsb = pic_order_cnt_lsb; - Ok(DecodeInformation { - reference_list, - header: header.clone(), - slice_indices, - rbsp_bytes, - sps_id: sps.id().id(), - pps_id: pps.pic_parameter_set_id.id(), - picture_info: PictureInfo { - non_existing: false, - used_for_long_term_reference: false, - PicOrderCnt: pic_order_cnt, - FrameNum: header.frame_num, - }, - }) + Ok([pic_order_cnt; 2]) } fn initialize_short_term_reference_picture_list_for_frame( &self, header: &SliceHeader, sps: &SeqParameterSet, - ) -> Result, ParserError> { + ) -> Vec { let mut short_term_reference_list = self .pictures .short_term .iter() .map(|reference| { - Ok(( + ( reference, - reference.decode_picture_numbers(header.frame_num.into(), sps)?, - )) + decode_picture_numbers_for_short_term_ref( + reference.header.frame_num.into(), + header.frame_num.into(), + sps, + ), + ) }) - .collect::, ParserError>>()?; + .collect::>(); short_term_reference_list.sort_by_key(|(_, numbers)| -numbers.PicNum); - let short_term_reference_list = short_term_reference_list + short_term_reference_list .into_iter() .map(|(reference, numbers)| ReferencePictureInfo { id: reference.id, + LongTermPicNum: None, picture_info: PictureInfo { FrameNum: numbers.FrameNum as u16, used_for_long_term_reference: false, @@ -362,52 +647,44 @@ impl ReferenceContext { PicOrderCnt: reference.pic_order_cnt, }, }) - .collect::>(); - - Ok(short_term_reference_list) + .collect() } - fn initialize_long_term_reference_picture_list_for_frame( - &self, - ) -> Result, ReferenceManagementError> { - if !self.pictures.long_term.is_empty() { - panic!("long-term references are not supported!"); - } + fn initialize_long_term_reference_picture_list_for_frame(&self) -> Vec { + let mut long_term_reference_list = self.pictures.long_term.clone(); - Ok(Vec::new()) + long_term_reference_list.sort_by_key(|pic| pic.LongTermFrameIdx); + + long_term_reference_list + .into_iter() + .map(|pic| ReferencePictureInfo { + id: pic.id, + LongTermPicNum: Some(pic.LongTermFrameIdx), + picture_info: PictureInfo { + used_for_long_term_reference: true, + non_existing: false, + FrameNum: pic.header.frame_num, + PicOrderCnt: pic.pic_order_cnt, + }, + }) + .collect() } fn initialize_reference_picture_list_for_frame( &self, header: &SliceHeader, sps: &SeqParameterSet, - pps: &PicParameterSet, - ) -> Result, ParserError> { - let num_ref_idx_l0_active = header - .num_ref_idx_active - .as_ref() - .map(|num| match num { - NumRefIdxActive::P { - num_ref_idx_l0_active_minus1, - } => Ok(*num_ref_idx_l0_active_minus1), - NumRefIdxActive::B { .. } => Err(ReferenceManagementError::BFramesNotSupported), - }) - .unwrap_or(Ok(pps.num_ref_idx_l0_default_active_minus1))? - + 1; - + ) -> Result, ReferenceManagementError> { let short_term_reference_list = - self.initialize_short_term_reference_picture_list_for_frame(header, sps)?; + self.initialize_short_term_reference_picture_list_for_frame(header, sps); - let long_term_reference_list = - self.initialize_long_term_reference_picture_list_for_frame()?; + let long_term_reference_list = self.initialize_long_term_reference_picture_list_for_frame(); - let mut reference_list = short_term_reference_list + let reference_list = short_term_reference_list .into_iter() .chain(long_term_reference_list) .collect::>(); - reference_list.truncate(num_ref_idx_l0_active as usize); - Ok(reference_list) } @@ -436,8 +713,12 @@ impl ReferenceContext { )?; } - ModificationOfPicNums::LongTermRef(_) => { - return Err(ReferenceManagementError::LongTermRefsNotSupported) + ModificationOfPicNums::LongTermRef(long_term_pic_num) => { + self.modify_long_term_reference_picture_list( + reference_list, + *long_term_pic_num, + &mut refIdxL0, + )?; } } } @@ -445,6 +726,50 @@ impl ReferenceContext { Ok(()) } + #[allow(non_snake_case)] + fn modify_long_term_reference_picture_list( + &self, + reference_list: &mut Vec, + picture_to_shift: u32, + refIdxLX: &mut usize, + ) -> Result<(), ReferenceManagementError> { + let shifted_picture_idx = reference_list + .iter() + .enumerate() + .find(|(_, pic)| match pic.LongTermPicNum { + Some(num) => num == picture_to_shift.into(), + None => false, + }) + .map(|(i, _)| i) + .ok_or(ReferenceManagementError::IncorrectData( + format!("picture with LongTermPicNum = {picture_to_shift} is not present in the reference list during modification") + ))?; + + if reference_list[shifted_picture_idx] + .picture_info + .non_existing + { + return Err(ReferenceManagementError::IncorrectData( + "a short-term reference picture marked for shifting in the reference list modification process is marked as non-existing".into() + )); + } + + if !reference_list[shifted_picture_idx] + .picture_info + .used_for_long_term_reference + { + return Err(ReferenceManagementError::IncorrectData( + "a short-term reference picture marked for shifting in the long-term reference list modification process".into() + )); + } + + let shifted_picture = reference_list.remove(shifted_picture_idx); + reference_list.insert(*refIdxLX, shifted_picture); + *refIdxLX += 1; + + Ok(()) + } + #[allow(non_snake_case)] fn modify_short_term_reference_picture_list( &self, @@ -486,7 +811,7 @@ impl ReferenceContext { let shifted_picture_idx = reference_list .iter() .enumerate() - .find(|(_, picture_info)| picture_info.picture_info.FrameNum as i64 == picNumLX) + .find(|(_, picture_info)| decode_picture_numbers_for_short_term_ref(picture_info.picture_info.FrameNum.into(), header.frame_num.into(), sps).PicNum == picNumLX) .map(|(i, _)| i) .ok_or(ReferenceManagementError::IncorrectData( format!("picture with picNumLX = {picNumLX} is not present in the reference list during modification") @@ -525,42 +850,39 @@ struct ShortTermReferencePicture { pic_order_cnt: [i32; 2], } -impl ShortTermReferencePicture { - #[allow(non_snake_case)] - fn decode_picture_numbers( - &self, - current_frame_num: i64, - sps: &SeqParameterSet, - ) -> Result { - if self.header.field_pic != h264_reader::nal::slice::FieldPic::Frame { - return Err(ParserError::FieldsNotSupported); - } - - let MaxFrameNum = sps.max_frame_num(); - - let FrameNum = self.header.frame_num as i64; - - let FrameNumWrap = if FrameNum > current_frame_num { - FrameNum - MaxFrameNum - } else { - FrameNum - }; - - // this assumes we're dealing with a short-term reference frame - let PicNum = FrameNumWrap; - - Ok(ShortTermReferencePictureNumbers { - FrameNum, - FrameNumWrap, - PicNum, - }) +#[allow(non_snake_case)] +fn decode_picture_numbers_for_short_term_ref( + frame_num: i64, + current_frame_num: i64, + sps: &SeqParameterSet, +) -> ShortTermReferencePictureNumbers { + let MaxFrameNum = sps.max_frame_num(); + + let FrameNum = frame_num; + + let FrameNumWrap = if FrameNum > current_frame_num { + FrameNum - MaxFrameNum + } else { + FrameNum + }; + + // this assumes we're dealing with a short-term reference frame + let PicNum = FrameNumWrap; + + ShortTermReferencePictureNumbers { + FrameNum, + FrameNumWrap, + PicNum, } } -#[derive(Debug)] +#[derive(Debug, Clone)] +#[allow(non_snake_case)] struct LongTermReferencePicture { - _header: Arc, - _id: ReferenceId, + header: Arc, + LongTermFrameIdx: u64, + id: ReferenceId, + pic_order_cnt: [i32; 2], } #[allow(non_snake_case)] From 0789069fee0da2470c965c55b8bb5ab0a46c12fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Ka=C5=BAmierczak?= Date: Thu, 24 Oct 2024 11:43:42 +0200 Subject: [PATCH 07/51] error handling --- Cargo.lock | 17 +- compositor_pipeline/Cargo.toml | 1 + .../src/pipeline/output/whip.rs | 342 +++++------------- .../output/whip/establish_peer_connection.rs | 187 ++++++++++ .../output/whip/init_peer_connection.rs | 97 +++++ .../src/pipeline/output/whip/packet_stream.rs | 8 +- .../src/pipeline/output/whip/payloader.rs | 20 +- 7 files changed, 402 insertions(+), 270 deletions(-) create mode 100644 compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs create mode 100644 compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs diff --git a/Cargo.lock b/Cargo.lock index f931dfeb8..62f8d87a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -725,6 +725,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "url", "vk-video", "webrtc", "webrtc-util 0.8.1", @@ -1452,9 +1453,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -2008,9 +2009,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -2894,9 +2895,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pico-args" @@ -4700,9 +4701,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", diff --git a/compositor_pipeline/Cargo.toml b/compositor_pipeline/Cargo.toml index 017d854a6..f04ef9f55 100644 --- a/compositor_pipeline/Cargo.toml +++ b/compositor_pipeline/Cargo.toml @@ -34,6 +34,7 @@ webrtc = "0.11.0" tokio = {workspace = true } serde_json = { workspace = true } serde = { workspace = true } +url = "2.5.2" [target.x86_64-unknown-linux-gnu.dependencies] decklink = { path = "../decklink", optional = true } diff --git a/compositor_pipeline/src/pipeline/output/whip.rs b/compositor_pipeline/src/pipeline/output/whip.rs index ac7652bf3..5c8c75b45 100644 --- a/compositor_pipeline/src/pipeline/output/whip.rs +++ b/compositor_pipeline/src/pipeline/output/whip.rs @@ -1,37 +1,26 @@ use compositor_render::OutputId; use crossbeam_channel::{Receiver, Sender}; -use payloader::Payload; -use reqwest::{header::HeaderMap, Url}; +use establish_peer_connection::connect; +use init_peer_connection::init_pc; +use packet_stream::PacketStream; +use payloader::{Payload, Payloader, PayloadingError}; +use reqwest::{Method, StatusCode, Url}; use std::sync::{atomic::AtomicBool, Arc}; -use tracing::{debug, error, info, span, Level}; +use tracing::{debug, error, span, Level}; +use url::ParseError; use webrtc::{ - api::{ - interceptor_registry::register_default_interceptors, - media_engine::{MediaEngine, MIME_TYPE_H264, MIME_TYPE_OPUS}, - APIBuilder, - }, - ice_transport::{ice_connection_state::RTCIceConnectionState, ice_server::RTCIceServer}, - interceptor::registry::Registry, - peer_connection::{ - configuration::RTCConfiguration, sdp::session_description::RTCSessionDescription, - RTCPeerConnection, - }, - rtcp::payload_feedbacks::picture_loss_indication::PictureLossIndication, - rtp_transceiver::{ - rtp_codec::{RTCRtpCodecCapability, RTCRtpCodecParameters, RTPCodecType}, - rtp_transceiver_direction::RTCRtpTransceiverDirection, - }, + peer_connection::RTCPeerConnection, track::track_local::{track_local_static_rtp::TrackLocalStaticRTP, TrackLocalWriter}, }; use crate::{ error::OutputInitError, event::Event, - pipeline::{types::EncoderOutputEvent, AudioCodec, PipelineCtx, VideoCodec}, + pipeline::{AudioCodec, EncoderOutputEvent, PipelineCtx, VideoCodec}, }; -use self::{packet_stream::PacketStream, payloader::Payloader}; - +mod establish_peer_connection; +mod init_peer_connection; mod packet_stream; mod payloader; @@ -51,8 +40,52 @@ pub struct WhipSenderOptions { #[derive(Debug, thiserror::Error)] pub enum WhipError { - #[error("Missing location header in WHIP response")] + #[error("Bad status in WHIP response\nStatus: {0}\nBody: {1}")] + BadStatus(StatusCode, String), + + #[error("WHIP request failed!\nMethod: {0}\nURL: {1}")] + RequestFailed(Method, Url), + + #[error( + "Unable to get location endpoint, check correctness of WHIP endpoint and your Bearer token" + )] MissingLocationHeader, + + #[error("Invalid endpoint URL: {1}")] + InvalidEndpointUrl(#[source] ParseError, String), + + #[error("Missing Host in endpoint URL")] + MissingHost, + + #[error("Missing port in endpoint URL")] + MissingPort, + + #[error("Failed to create RTC session description: {0}")] + RTCSessionDescriptionError(webrtc::Error), + + #[error("Failed to set local description: {0}")] + LocalDescriptionError(webrtc::Error), + + #[error("Failed to set remote description: {0}")] + RemoteDescriptionError(webrtc::Error), + + #[error("Failed to parse {0} response body: {1}")] + BodyParsingError(String, reqwest::Error), + + #[error("Failed to create offer: {0}")] + OfferCreationError(webrtc::Error), + + #[error(transparent)] + PeerConnectionInitError(#[from] webrtc::Error), + + #[error("Failed to convert ICE candidate to JSON: {0}")] + IceCandidateToJsonError(webrtc::Error), + + #[error(transparent)] + SerdeJsonError(#[from] serde_json::Error), + + #[error(transparent)] + PayloadingError(#[from] PayloadingError), } impl WhipSender { @@ -121,7 +154,20 @@ fn start_whip_sender_thread( ) { tokio_rt.block_on(async { let client = reqwest::Client::new(); - let (peer_connection, video_track, audio_track) = init_pc().await; + let peer_connection: Arc; + let video_track: Arc; + let audio_track: Arc; + match init_pc().await { + Ok((pc, video, audio)) => { + peer_connection = pc; + video_track = video; + audio_track = audio; + } + Err(err) => { + error!("Error occured while initializing peer connection: {err}"); + return; + } + } let whip_session_url = match connect( peer_connection, endpoint_url, @@ -134,7 +180,10 @@ fn start_whip_sender_thread( .await { Ok(val) => val, - Err(_) => return, + Err(err) => { + error!("{err}"); + return; + } }; for chunk in packet_stream { @@ -150,235 +199,28 @@ fn start_whip_sender_thread( }; match chunk { - Payload::Video(bytes) => { - if video_track.write(&bytes).await.is_err() { - error!("Error occurred while writing to video track for session"); + Payload::Video(video_payload) => match video_payload { + Ok(video_bytes) => { + if video_track.write(&video_bytes).await.is_err() { + error!("Error occurred while writing to video track for session"); + } } - } - Payload::Audio(bytes) => { - if audio_track.write(&bytes).await.is_err() { - error!("Error occurred while writing to audio track for session"); + Err(err) => { + error!("Error while reading video bytes: {err}"); } - } + }, + Payload::Audio(audio_payload) => match audio_payload { + Ok(audio_bytes) => { + if audio_track.write(&audio_bytes).await.is_err() { + error!("Error occurred while writing to video track for session"); + } + } + Err(err) => { + error!("Error while reading audio bytes: {err}"); + } + }, } } let _ = client.delete(whip_session_url).send().await; }); } - -async fn init_pc() -> ( - Arc, - Arc, - Arc, -) { - let mut m = MediaEngine::default(); - m.register_default_codecs().unwrap(); - m.register_codec( - RTCRtpCodecParameters { - capability: RTCRtpCodecCapability { - mime_type: MIME_TYPE_H264.to_owned(), - clock_rate: 90000, - channels: 0, - sdp_fmtp_line: "".to_owned(), - rtcp_feedback: vec![], - }, - payload_type: 96, - ..Default::default() - }, - RTPCodecType::Video, - ) - .unwrap(); - m.register_codec( - RTCRtpCodecParameters { - capability: RTCRtpCodecCapability { - mime_type: MIME_TYPE_OPUS.to_owned(), - clock_rate: 48000, - channels: 2, - sdp_fmtp_line: "".to_owned(), - rtcp_feedback: vec![], - }, - payload_type: 111, - ..Default::default() - }, - RTPCodecType::Audio, - ) - .unwrap(); - let mut registry = Registry::new(); - registry = register_default_interceptors(registry, &mut m).unwrap(); - let api = APIBuilder::new() - .with_media_engine(m) - .with_interceptor_registry(registry) - .build(); - - let config = RTCConfiguration { - ice_servers: vec![RTCIceServer { - urls: vec!["stun:stun.l.google.com:19302".to_owned()], - ..Default::default() - }], - ..Default::default() - }; - let peer_connection = Arc::new(api.new_peer_connection(config).await.unwrap()); - let video_track = Arc::new(TrackLocalStaticRTP::new( - RTCRtpCodecCapability { - mime_type: MIME_TYPE_H264.to_owned(), - ..Default::default() - }, - "video".to_owned(), - "webrtc-rs".to_owned(), - )); - let audio_track = Arc::new(TrackLocalStaticRTP::new( - RTCRtpCodecCapability { - mime_type: MIME_TYPE_OPUS.to_owned(), - ..Default::default() - }, - "audio".to_owned(), - "webrtc-rs".to_owned(), - )); - let _ = peer_connection.add_track(video_track.clone()).await; - let _ = peer_connection.add_track(audio_track.clone()).await; - let transceivers = peer_connection.get_transceivers().await; - for transceiver in transceivers { - transceiver - .set_direction(RTCRtpTransceiverDirection::Sendonly) - .await; - } - (peer_connection, video_track, audio_track) -} - -async fn connect( - peer_connection: Arc, - endpoint_url: String, - bearer_token: Option, - should_close: Arc, - tokio_rt: Arc, - client: reqwest::Client, - request_keyframe_sender: Option>, -) -> Result { - peer_connection.on_ice_connection_state_change(Box::new( - move |connection_state: RTCIceConnectionState| { - debug!("Connection State has changed {connection_state}"); - if connection_state == RTCIceConnectionState::Connected { - debug!("ice connected"); - } else if connection_state == RTCIceConnectionState::Failed { - debug!("Done writing media files"); - should_close.store(true, std::sync::atomic::Ordering::Relaxed); - } - Box::pin(async {}) - }, - )); - - if let Some(keyframe_sender) = request_keyframe_sender { - let senders = peer_connection.get_senders().await; - for sender in senders { - let keyframe_sender_clone = keyframe_sender.clone(); - tokio_rt.spawn(async move { - loop { - let packets = &sender.read_rtcp().await.unwrap().0; - for packet in packets { - if packet - .as_any() - .downcast_ref::() - .is_some() - { - if let Err(err) = keyframe_sender_clone.send(()) { - debug!(%err, "Failed to send keyframe request to the encoder."); - }; - } - } - } - }); - } - } - - let offer = peer_connection.create_offer(None).await.unwrap(); - - info!("[WHIP] endpoint url: {}", endpoint_url); - - let mut header_map = HeaderMap::new(); - header_map.append("Content-Type", "application/sdp".parse().unwrap()); - - let bearer_token = bearer_token.map(Arc::new); - - if let Some(token) = bearer_token.clone() { - header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); - } - - let response = client - .post(endpoint_url.clone()) - .headers(header_map) - .body(offer.sdp.clone()) - .send() - .await - .unwrap(); - - info!("[WHIP] response: {:?}", &response); - - let parsed_endpoint_url = Url::parse(&endpoint_url).unwrap(); - - let location_url_path = response.headers() - .get("location") - .and_then(|url| url.to_str().ok()) - .ok_or_else(|| { - error!("Unable to get location endpoint, check correctness of WHIP endpoint and your Bearer token"); - WhipError::MissingLocationHeader - })?; - - let location_url = Url::try_from( - format!( - "{}://{}:{}{}", - parsed_endpoint_url.scheme(), - parsed_endpoint_url.host_str().unwrap(), - parsed_endpoint_url.port().unwrap(), - location_url_path - ) - .as_str(), - ) - .unwrap(); - - let answer = response.bytes().await.unwrap(); - peer_connection.set_local_description(offer).await.unwrap(); - - peer_connection - .set_remote_description( - RTCSessionDescription::answer(std::str::from_utf8(&answer).unwrap().to_string()) - .unwrap(), - ) - .await - .unwrap(); - - let client = Arc::new(client); - - let location1: Url = location_url.clone(); - - peer_connection.on_ice_candidate(Box::new(move |candidate| { - if let Some(candidate) = candidate { - let client_clone = client.clone(); - let location2 = location1.clone(); - let bearer_token1 = bearer_token.clone(); - tokio_rt.spawn(async move { - let ice_candidate = candidate.to_json().unwrap(); - - let mut header_map = HeaderMap::new(); - header_map.append( - "Content-Type", - "application/trickle-ice-sdpfrag".parse().unwrap(), - ); - - if let Some(token) = bearer_token1 { - header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); - } - - let _ = client_clone - .patch(location2) - .headers(header_map) - .body(serde_json::to_string(&ice_candidate).unwrap()) - .send() - .await - .unwrap(); - }); - } - Box::pin(async {}) - })); - - Ok(location_url.clone()) -} diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs new file mode 100644 index 000000000..b6bf55bb9 --- /dev/null +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -0,0 +1,187 @@ +use crossbeam_channel::Sender; + +use super::WhipError; +use reqwest::{header::HeaderMap, Method, StatusCode, Url}; +use std::sync::{atomic::AtomicBool, Arc}; +use tracing::{debug, info}; +use webrtc::{ + ice_transport::ice_connection_state::RTCIceConnectionState, + peer_connection::{sdp::session_description::RTCSessionDescription, RTCPeerConnection}, + rtcp::payload_feedbacks::picture_loss_indication::PictureLossIndication, +}; + +pub async fn connect( + peer_connection: Arc, + endpoint_url: String, + bearer_token: Option, + should_close: Arc, + tokio_rt: Arc, + client: reqwest::Client, + request_keyframe_sender: Option>, +) -> Result { + peer_connection.on_ice_connection_state_change(Box::new( + move |connection_state: RTCIceConnectionState| { + debug!("Connection State has changed {connection_state}"); + if connection_state == RTCIceConnectionState::Connected { + debug!("ice connected"); + } else if connection_state == RTCIceConnectionState::Failed { + debug!("Done writing media files"); + should_close.store(true, std::sync::atomic::Ordering::Relaxed); + } + Box::pin(async {}) + }, + )); + + if let Some(keyframe_sender) = request_keyframe_sender { + let senders = peer_connection.get_senders().await; + for sender in senders { + let keyframe_sender_clone = keyframe_sender.clone(); + tokio_rt.spawn(async move { + loop { + if let Ok((packets, _)) = &sender.read_rtcp().await { + for packet in packets { + if packet + .as_any() + .downcast_ref::() + .is_some() + { + if let Err(err) = keyframe_sender_clone.send(()) { + debug!(%err, "Failed to send keyframe request to the encoder."); + }; + } + } + } else { + debug!("Failed to read RTCP packets from the sender."); + } + } + }); + } + } + + let offer = peer_connection + .create_offer(None) + .await + .map_err(WhipError::OfferCreationError)?; + + let endpoint_url = Url::parse(&endpoint_url) + .map_err(|e| WhipError::InvalidEndpointUrl(e, endpoint_url.clone()))?; + + info!("[WHIP] endpoint url: {}", endpoint_url); + + let mut header_map = HeaderMap::new(); + header_map.append("Content-Type", "application/sdp".parse().unwrap()); + + let bearer_token = bearer_token.map(Arc::new); + + if let Some(token) = bearer_token.clone() { + header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); + } + + let response = match client + .post(endpoint_url.clone()) + .headers(header_map) + .body(offer.sdp.clone()) + .send() + .await + { + Ok(res) => res, + Err(_) => return Err(WhipError::RequestFailed(Method::POST, endpoint_url)), + }; + + if response.status() >= StatusCode::BAD_REQUEST { + let status = response.status(); + let answer = response + .text() + .await + .map_err(|e| WhipError::BodyParsingError("sdp offer".to_string(), e))?; + return Err(WhipError::BadStatus(status, answer)); + } + + info!("[WHIP] response: {:?}", &response); + + let location_url_path = response + .headers() + .get("location") + .and_then(|url| url.to_str().ok()) + .ok_or_else(|| WhipError::MissingLocationHeader)?; + + let scheme = endpoint_url.scheme(); + let host = endpoint_url + .host_str() + .ok_or_else(|| WhipError::MissingHost)?; + + let port = endpoint_url.port().ok_or_else(|| WhipError::MissingPort)?; + + let formatted_url = format!("{}://{}:{}{}", scheme, host, port, location_url_path); + + let location_url = Url::try_from(formatted_url.as_str()) + .map_err(|e| WhipError::InvalidEndpointUrl(e, formatted_url))?; + + peer_connection + .set_local_description(offer) + .await + .map_err(WhipError::LocalDescriptionError)?; + + let answer = response + .text() + .await + .map_err(|e| WhipError::BodyParsingError("sdp offer".to_string(), e))?; + + let rtc_answer = + RTCSessionDescription::answer(answer).map_err(WhipError::RTCSessionDescriptionError)?; + + peer_connection + .set_remote_description(rtc_answer) + .await + .map_err(WhipError::RemoteDescriptionError)?; + + let client = Arc::new(client); + + let location1: Url = location_url.clone(); + + peer_connection.on_ice_candidate(Box::new(move |candidate| { + if let Some(candidate) = candidate { + let client_clone = client.clone(); + let location2 = location1.clone(); + let bearer_token1 = bearer_token.clone(); + tokio_rt.spawn(async move { + let ice_candidate = candidate + .to_json() + .map_err(WhipError::IceCandidateToJsonError)?; + + let mut header_map = HeaderMap::new(); + header_map.append( + "Content-Type", + "application/trickle-ice-sdpfrag".parse().unwrap(), + ); + + if let Some(token) = bearer_token1 { + header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); + } + + let response = match client_clone + .patch(location2.clone()) + .headers(header_map) + .body(serde_json::to_string(&ice_candidate)?) + .send() + .await + { + Ok(res) => res, + Err(_) => return Err(WhipError::RequestFailed(Method::PATCH, location2)), + }; + + if response.status() >= StatusCode::BAD_REQUEST { + let status = response.status(); + let body_str = response.text().await.map_err(|e| { + WhipError::BodyParsingError("Trickle ICE patch".to_string(), e) + })?; + return Err(WhipError::BadStatus(status, body_str)); + }; + Ok(response) + }); + } + Box::pin(async {}) + })); + + Ok(location_url.clone()) +} diff --git a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs new file mode 100644 index 000000000..6f686c963 --- /dev/null +++ b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs @@ -0,0 +1,97 @@ +use super::WhipError; +use std::sync::Arc; +use webrtc::{ + api::{ + interceptor_registry::register_default_interceptors, + media_engine::{MediaEngine, MIME_TYPE_H264, MIME_TYPE_OPUS}, + APIBuilder, + }, + ice_transport::ice_server::RTCIceServer, + interceptor::registry::Registry, + peer_connection::{configuration::RTCConfiguration, RTCPeerConnection}, + rtp_transceiver::{ + rtp_codec::{RTCRtpCodecCapability, RTCRtpCodecParameters, RTPCodecType}, + rtp_transceiver_direction::RTCRtpTransceiverDirection, + }, + track::track_local::track_local_static_rtp::TrackLocalStaticRTP, +}; + +pub async fn init_pc() -> Result< + ( + Arc, + Arc, + Arc, + ), + WhipError, +> { + let mut m = MediaEngine::default(); + m.register_default_codecs()?; + m.register_codec( + RTCRtpCodecParameters { + capability: RTCRtpCodecCapability { + mime_type: MIME_TYPE_H264.to_owned(), + clock_rate: 90000, + channels: 0, + sdp_fmtp_line: "".to_owned(), + rtcp_feedback: vec![], + }, + payload_type: 96, + ..Default::default() + }, + RTPCodecType::Video, + )?; + m.register_codec( + RTCRtpCodecParameters { + capability: RTCRtpCodecCapability { + mime_type: MIME_TYPE_OPUS.to_owned(), + clock_rate: 48000, + channels: 2, + sdp_fmtp_line: "".to_owned(), + rtcp_feedback: vec![], + }, + payload_type: 111, + ..Default::default() + }, + RTPCodecType::Audio, + )?; + let mut registry = Registry::new(); + registry = register_default_interceptors(registry, &mut m)?; + let api = APIBuilder::new() + .with_media_engine(m) + .with_interceptor_registry(registry) + .build(); + + let config = RTCConfiguration { + ice_servers: vec![RTCIceServer { + urls: vec!["stun:stun.l.google.com:19302".to_owned()], + ..Default::default() + }], + ..Default::default() + }; + let peer_connection = Arc::new(api.new_peer_connection(config).await?); + let video_track = Arc::new(TrackLocalStaticRTP::new( + RTCRtpCodecCapability { + mime_type: MIME_TYPE_H264.to_owned(), + ..Default::default() + }, + "video".to_owned(), + "webrtc-rs".to_owned(), + )); + let audio_track = Arc::new(TrackLocalStaticRTP::new( + RTCRtpCodecCapability { + mime_type: MIME_TYPE_OPUS.to_owned(), + ..Default::default() + }, + "audio".to_owned(), + "webrtc-rs".to_owned(), + )); + let _ = peer_connection.add_track(video_track.clone()).await; + let _ = peer_connection.add_track(audio_track.clone()).await; + let transceivers = peer_connection.get_transceivers().await; + for transceiver in transceivers { + transceiver + .set_direction(RTCRtpTransceiverDirection::Sendonly) + .await; + } + Ok((peer_connection, video_track, audio_track)) +} diff --git a/compositor_pipeline/src/pipeline/output/whip/packet_stream.rs b/compositor_pipeline/src/pipeline/output/whip/packet_stream.rs index fa26425d7..ce594c435 100644 --- a/compositor_pipeline/src/pipeline/output/whip/packet_stream.rs +++ b/compositor_pipeline/src/pipeline/output/whip/packet_stream.rs @@ -33,12 +33,12 @@ impl PacketStream { match self.payloader.audio_eos() { Err(PayloadingError::NoAudioPayloader) => (), Err(PayloadingError::AudioEOSAlreadySent) => (), - packet => return Some(Ok(Payload::Audio(packet.unwrap()))), + packet => return Some(Ok(Payload::Audio(packet))), } match self.payloader.video_eos() { Err(PayloadingError::NoVideoPayloader) => (), Err(PayloadingError::VideoEOSAlreadySent) => (), - packet => return Some(Ok(Payload::Video(packet.unwrap()))), + packet => return Some(Ok(Payload::Video(packet))), } return None; }; @@ -46,10 +46,10 @@ impl PacketStream { let encoded_chunk = match packet { EncoderOutputEvent::Data(packet) => packet, EncoderOutputEvent::AudioEOS => { - return Some(Ok(Payload::Audio(self.payloader.audio_eos().unwrap()))); + return Some(Ok(Payload::Audio(self.payloader.audio_eos()))); } EncoderOutputEvent::VideoEOS => { - return Some(Ok(Payload::Video(self.payloader.video_eos().unwrap()))); + return Some(Ok(Payload::Video(self.payloader.video_eos()))); } }; diff --git a/compositor_pipeline/src/pipeline/output/whip/payloader.rs b/compositor_pipeline/src/pipeline/output/whip/payloader.rs index 89cb8d5a3..720dddb32 100644 --- a/compositor_pipeline/src/pipeline/output/whip/payloader.rs +++ b/compositor_pipeline/src/pipeline/output/whip/payloader.rs @@ -99,8 +99,8 @@ enum AudioPayloader { } pub enum Payload { - Video(Bytes), - Audio(Bytes), + Video(Result), + Audio(Result), } impl Payloader { @@ -303,12 +303,16 @@ fn payload( context.next_sequence_number = context.next_sequence_number.wrapping_add(1); match payload_type { - VIDEO_PAYLOAD_TYPE => Ok(Payload::Video( - rtp::packet::Packet { header, payload }.marshal()?, - )), - AUDIO_PAYLOAD_TYPE => Ok(Payload::Audio( - rtp::packet::Packet { header, payload }.marshal()?, - )), + VIDEO_PAYLOAD_TYPE => { + Ok(Payload::Video(Ok( + rtp::packet::Packet { header, payload }.marshal()? + ))) + } + AUDIO_PAYLOAD_TYPE => { + Ok(Payload::Audio(Ok( + rtp::packet::Packet { header, payload }.marshal()? + ))) + } _ => Err(PayloadingError::UnsupportedPayloadType), } }) From fbc597106c6df2824af0ebba194bf802c62f3498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Radkowski?= Date: Fri, 25 Oct 2024 11:03:20 +0200 Subject: [PATCH 08/51] Fix scene update failing if `text` in `Text` component is empty (#836) --- .../src/transformations/text_renderer.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/compositor_render/src/transformations/text_renderer.rs b/compositor_render/src/transformations/text_renderer.rs index e4f9353a2..49e2b84aa 100644 --- a/compositor_render/src/transformations/text_renderer.rs +++ b/compositor_render/src/transformations/text_renderer.rs @@ -74,6 +74,24 @@ impl TextRendererNode { return; } + if self.resolution.width == 0 || self.resolution.height == 0 { + // We can't use zero-sized textures + let target_state = target.ensure_size( + renderer_ctx.wgpu_ctx, + Resolution { + width: 1, + height: 1, + }, + ); + + target_state + .rgba_texture() + .upload(renderer_ctx.wgpu_ctx, &[0; 4]); + + self.was_rendered = true; + return; + } + let text_renderer = renderer_ctx.text_renderer_ctx; let font_system = &mut text_renderer.font_system.lock().unwrap(); let swash_cache = &mut text_renderer.swash_cache.lock().unwrap(); From e2c23723422741aa18d9a7e359f2dc936186c0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Radkowski?= Date: Fri, 25 Oct 2024 12:17:54 +0200 Subject: [PATCH 09/51] [ts-sdk] Make react sdk run on browser (#776) --- .../browser-render/src/index.ts | 1 + .../browser-render/src/renderer.ts | 5 - ts/@live-compositor/core/src/api.ts | 6 +- ts/@live-compositor/core/src/api/input.ts | 14 +- ts/@live-compositor/core/src/api/output.ts | 53 +- ts/@live-compositor/core/src/compositor.ts | 11 +- ts/@live-compositor/core/src/index.ts | 2 + ts/@live-compositor/core/src/output.ts | 11 +- ts/@live-compositor/web-wasm/.eslintignore | 1 + ts/@live-compositor/web-wasm/.eslintrc.json | 5 + ts/@live-compositor/web-wasm/package.json | 27 + .../web-wasm/src/compositor.ts | 86 + .../web-wasm/src/eventSender.ts | 62 + ts/@live-compositor/web-wasm/src/index.ts | 4 + .../web-wasm/src/input/decoder/h264Decoder.ts | 53 + .../web-wasm/src/input/input.ts | 60 + .../web-wasm/src/input/mp4/demuxer.ts | 86 + .../web-wasm/src/input}/mp4/mp4box.d.ts | 2 +- .../web-wasm/src/input/mp4/source.ts | 64 + .../web-wasm/src/input/registerInput.ts | 15 + .../web-wasm/src/input/source.ts | 20 + .../web-wasm/src/manager/wasmInstance.ts | 158 ++ .../web-wasm/src/output/canvas.ts | 15 + .../web-wasm/src/output/output.ts | 22 + .../web-wasm/src/output/registerOutput.ts | 29 + .../web-wasm/src/output/sink.ts | 5 + ts/@live-compositor/web-wasm/src/queue.ts | 93 + ts/@live-compositor/web-wasm/src/renderers.ts | 3 + ts/@live-compositor/web-wasm/tsconfig.json | 9 + ts/examples/vite-browser-render/.gitignore | 1 + ts/examples/vite-browser-render/package.json | 4 +- ts/examples/vite-browser-render/src/App.css | 3 + ts/examples/vite-browser-render/src/App.tsx | 9 +- .../src/examples/Counter.tsx | 31 +- .../src/examples/MP4Player.tsx | 204 +- .../src/examples/mp4/decoder.ts | 97 - .../vite-browser-render/src/examples/utils.ts | 28 - ts/live-compositor/src/index.ts | 8 +- ts/live-compositor/src/types/registerInput.ts | 4 - .../src/types/registerOutput.ts | 20 +- ts/package-lock.json | 2151 +++++++++-------- ts/package.json | 3 +- 42 files changed, 2205 insertions(+), 1280 deletions(-) create mode 100644 ts/@live-compositor/web-wasm/.eslintignore create mode 100644 ts/@live-compositor/web-wasm/.eslintrc.json create mode 100644 ts/@live-compositor/web-wasm/package.json create mode 100644 ts/@live-compositor/web-wasm/src/compositor.ts create mode 100644 ts/@live-compositor/web-wasm/src/eventSender.ts create mode 100644 ts/@live-compositor/web-wasm/src/index.ts create mode 100644 ts/@live-compositor/web-wasm/src/input/decoder/h264Decoder.ts create mode 100644 ts/@live-compositor/web-wasm/src/input/input.ts create mode 100644 ts/@live-compositor/web-wasm/src/input/mp4/demuxer.ts rename ts/{examples/vite-browser-render/src/examples => @live-compositor/web-wasm/src/input}/mp4/mp4box.d.ts (97%) create mode 100644 ts/@live-compositor/web-wasm/src/input/mp4/source.ts create mode 100644 ts/@live-compositor/web-wasm/src/input/registerInput.ts create mode 100644 ts/@live-compositor/web-wasm/src/input/source.ts create mode 100644 ts/@live-compositor/web-wasm/src/manager/wasmInstance.ts create mode 100644 ts/@live-compositor/web-wasm/src/output/canvas.ts create mode 100644 ts/@live-compositor/web-wasm/src/output/output.ts create mode 100644 ts/@live-compositor/web-wasm/src/output/registerOutput.ts create mode 100644 ts/@live-compositor/web-wasm/src/output/sink.ts create mode 100644 ts/@live-compositor/web-wasm/src/queue.ts create mode 100644 ts/@live-compositor/web-wasm/src/renderers.ts create mode 100644 ts/@live-compositor/web-wasm/tsconfig.json delete mode 100644 ts/examples/vite-browser-render/src/examples/mp4/decoder.ts delete mode 100644 ts/examples/vite-browser-render/src/examples/utils.ts diff --git a/ts/@live-compositor/browser-render/src/index.ts b/ts/@live-compositor/browser-render/src/index.ts index e6fb704ba..2b260c61c 100644 --- a/ts/@live-compositor/browser-render/src/index.ts +++ b/ts/@live-compositor/browser-render/src/index.ts @@ -1,2 +1,3 @@ export { loadWasmModule } from './wasm'; export * from './renderer'; +export * from './api'; diff --git a/ts/@live-compositor/browser-render/src/renderer.ts b/ts/@live-compositor/browser-render/src/renderer.ts index a621f7b73..b69f657bf 100644 --- a/ts/@live-compositor/browser-render/src/renderer.ts +++ b/ts/@live-compositor/browser-render/src/renderer.ts @@ -8,11 +8,6 @@ export type RendererOptions = { streamFallbackTimeoutMs: number; }; -export type Framerate = { - num: number; - den: number; -}; - export type FrameSet = { ptsMs: number; frames: { [id: string]: Frame }; diff --git a/ts/@live-compositor/core/src/api.ts b/ts/@live-compositor/core/src/api.ts index 8340d8fc6..5e99adf53 100644 --- a/ts/@live-compositor/core/src/api.ts +++ b/ts/@live-compositor/core/src/api.ts @@ -1,5 +1,7 @@ import { Api } from 'live-compositor'; import { CompositorManager } from './compositorManager.js'; +import { RegisterOutputRequest } from './api/output.js'; +import { RegisterInputRequest } from './api/input.js'; export { Api }; @@ -24,7 +26,7 @@ export class ApiClient { }); } - public async registerOutput(outptuId: string, request: Api.RegisterOutput): Promise { + public async registerOutput(outptuId: string, request: RegisterOutputRequest): Promise { return this.serverManager.sendRequest({ method: 'POST', route: `/api/output/${encodeURIComponent(outptuId)}/register`, @@ -40,7 +42,7 @@ export class ApiClient { }); } - public async registerInput(inputId: string, request: Api.RegisterInput): Promise { + public async registerInput(inputId: string, request: RegisterInputRequest): Promise { return this.serverManager.sendRequest({ method: 'POST', route: `/api/input/${encodeURIComponent(inputId)}/register`, diff --git a/ts/@live-compositor/core/src/api/input.ts b/ts/@live-compositor/core/src/api/input.ts index 8d74a208f..792ba7128 100644 --- a/ts/@live-compositor/core/src/api/input.ts +++ b/ts/@live-compositor/core/src/api/input.ts @@ -1,7 +1,13 @@ import { Api } from '../api.js'; -import { RegisterInput, Inputs } from 'live-compositor'; +import { RegisterMp4Input, RegisterRtpInput, Inputs } from 'live-compositor'; -export function intoRegisterInput(input: RegisterInput): Api.RegisterInput { +export type RegisterInputRequest = Api.RegisterInput; + +export type RegisterInput = + | ({ type: 'rtp_stream' } & RegisterRtpInput) + | ({ type: 'mp4' } & RegisterMp4Input); + +export function intoRegisterInput(input: RegisterInput): RegisterInputRequest { if (input.type === 'mp4') { return intoMp4RegisterInput(input); } else if (input.type === 'rtp_stream') { @@ -11,7 +17,7 @@ export function intoRegisterInput(input: RegisterInput): Api.RegisterInput { } } -function intoMp4RegisterInput(input: Inputs.RegisterMp4Input): Api.RegisterInput { +function intoMp4RegisterInput(input: Inputs.RegisterMp4Input): RegisterInputRequest { return { type: 'mp4', url: input.url, @@ -22,7 +28,7 @@ function intoMp4RegisterInput(input: Inputs.RegisterMp4Input): Api.RegisterInput }; } -function intoRtpRegisterInput(input: Inputs.RegisterRtpInput): Api.RegisterInput { +function intoRtpRegisterInput(input: Inputs.RegisterRtpInput): RegisterInputRequest { return { type: 'rtp_stream', port: input.port, diff --git a/ts/@live-compositor/core/src/api/output.ts b/ts/@live-compositor/core/src/api/output.ts index e2a7125f8..1a913bd2e 100644 --- a/ts/@live-compositor/core/src/api/output.ts +++ b/ts/@live-compositor/core/src/api/output.ts @@ -1,22 +1,51 @@ -import { RegisterOutput, Api, Outputs } from 'live-compositor'; +import { + Api, + Outputs, + RegisterRtpOutput, + RegisterMp4Output, + RegisterCanvasOutput, +} from 'live-compositor'; + +export type RegisterOutputRequest = Api.RegisterOutput | RegisterCanvasOutputRequest; + +export type RegisterCanvasOutputRequest = { + type: 'canvas'; + video: OutputCanvasVideoOptions; +}; + +export type OutputCanvasVideoOptions = { + resolution: Api.Resolution; + /** + * HTMLCanvasElement + */ + canvas: any; + initial: Api.Video; +}; + +export type RegisterOutput = + | ({ type: 'rtp_stream' } & RegisterRtpOutput) + | ({ type: 'mp4' } & RegisterMp4Output) + | ({ type: 'canvas' } & RegisterCanvasOutput); export function intoRegisterOutput( output: RegisterOutput, initial: { video?: Api.Video; audio?: Api.Audio } -): Api.RegisterOutput { +): RegisterOutputRequest { if (output.type === 'rtp_stream') { return intoRegisterRtpOutput(output, initial); } else if (output.type === 'mp4') { return intoRegisterMp4Output(output, initial); + } else if (output.type === 'canvas') { + return intoRegisterCanvasOutput(output, initial); } else { - throw new Error(`Unknown input type ${(output as any).type}`); + throw new Error(`Unknown output type ${(output as any).type}`); } } function intoRegisterRtpOutput( output: Outputs.RegisterRtpOutput, initial: { video?: Api.Video; audio?: Api.Audio } -): Api.RegisterOutput { +): RegisterOutputRequest { return { type: 'rtp_stream', port: output.port, @@ -30,7 +59,7 @@ function intoRegisterRtpOutput( function intoRegisterMp4Output( output: Outputs.RegisterMp4Output, initial: { video?: Api.Video; audio?: Api.Audio } -): Api.RegisterOutput { +): RegisterOutputRequest { return { type: 'mp4', path: output.serverPath, @@ -39,6 +68,20 @@ function intoRegisterMp4Output( }; } +function intoRegisterCanvasOutput( + output: Outputs.RegisterCanvasOutput, + initial: { video?: Api.Video; _audio?: Api.Audio } +): RegisterOutputRequest { + return { + type: 'canvas', + video: { + resolution: output.video.resolution, + canvas: output.video.canvas, + initial: initial.video!, + }, + }; +} + function intoOutputVideoOptions( video: Outputs.RtpVideoOptions | Outputs.Mp4VideoOptions, initial: Api.Video diff --git a/ts/@live-compositor/core/src/compositor.ts b/ts/@live-compositor/core/src/compositor.ts index b4f9ee9b4..f257e8e8b 100644 --- a/ts/@live-compositor/core/src/compositor.ts +++ b/ts/@live-compositor/core/src/compositor.ts @@ -1,14 +1,9 @@ -import { - _liveCompositorInternals, - RegisterInput, - RegisterOutput, - Renderers, -} from 'live-compositor'; +import { _liveCompositorInternals, Renderers } from 'live-compositor'; import { ApiClient } from './api.js'; import Output from './output.js'; import { CompositorManager } from './compositorManager.js'; -import { intoRegisterOutput } from './api/output.js'; -import { intoRegisterInput } from './api/input.js'; +import { intoRegisterOutput, RegisterOutput } from './api/output.js'; +import { intoRegisterInput, RegisterInput } from './api/input.js'; import { onCompositorEvent } from './event.js'; import { intoRegisterImage, intoRegisterWebRenderer } from './api/renderer.js'; diff --git a/ts/@live-compositor/core/src/index.ts b/ts/@live-compositor/core/src/index.ts index 0c2f6703d..fb0b860af 100644 --- a/ts/@live-compositor/core/src/index.ts +++ b/ts/@live-compositor/core/src/index.ts @@ -1,3 +1,5 @@ export { ApiClient, ApiRequest } from './api.js'; export { LiveCompositor } from './compositor.js'; export { CompositorManager } from './compositorManager.js'; +export { RegisterInputRequest, RegisterInput } from './api/input.js'; +export { RegisterOutputRequest, RegisterOutput } from './api/output.js'; diff --git a/ts/@live-compositor/core/src/output.ts b/ts/@live-compositor/core/src/output.ts index bad2aa7b6..b97e95717 100644 --- a/ts/@live-compositor/core/src/output.ts +++ b/ts/@live-compositor/core/src/output.ts @@ -1,8 +1,8 @@ -import { _liveCompositorInternals, RegisterOutput, View, Outputs } from 'live-compositor'; +import { _liveCompositorInternals, View, Outputs } from 'live-compositor'; import React, { useSyncExternalStore } from 'react'; import { ApiClient, Api } from './api.js'; import Renderer from './renderer.js'; -import { intoAudioInputsConfiguration } from './api/output.js'; +import { intoAudioInputsConfiguration, RegisterOutput } from './api/output.js'; import { throttle } from './utils.js'; type OutputContext = _liveCompositorInternals.OutputContext; @@ -33,12 +33,13 @@ class Output { this.shouldUpdateWhenReady = true; }; - if (registerRequest.audio) { - this.initialAudioConfig = registerRequest.audio.initial ?? { inputs: [] }; + const hasAudio = 'audio' in registerRequest && !!registerRequest.audio; + if (hasAudio) { + this.initialAudioConfig = registerRequest.audio!.initial ?? { inputs: [] }; } const onUpdate = () => this.throttledUpdate(); - this.outputCtx = new _liveCompositorInternals.OutputContext(onUpdate, !!registerRequest.audio); + this.outputCtx = new _liveCompositorInternals.OutputContext(onUpdate, hasAudio); if (registerRequest.video) { const rootElement = React.createElement(OutputRootComponent, { diff --git a/ts/@live-compositor/web-wasm/.eslintignore b/ts/@live-compositor/web-wasm/.eslintignore new file mode 100644 index 000000000..1521c8b76 --- /dev/null +++ b/ts/@live-compositor/web-wasm/.eslintignore @@ -0,0 +1 @@ +dist diff --git a/ts/@live-compositor/web-wasm/.eslintrc.json b/ts/@live-compositor/web-wasm/.eslintrc.json new file mode 100644 index 000000000..ed5ec9dbf --- /dev/null +++ b/ts/@live-compositor/web-wasm/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "../../.eslintrc.base.json" + ] +} diff --git a/ts/@live-compositor/web-wasm/package.json b/ts/@live-compositor/web-wasm/package.json new file mode 100644 index 000000000..10b05c804 --- /dev/null +++ b/ts/@live-compositor/web-wasm/package.json @@ -0,0 +1,27 @@ +{ + "name": "@live-compositor/web-wasm", + "version": "0.1.0-rc.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "watch": "tsc --watch --preserveWatchOutput", + "build": "tsc", + "clean": "rimraf dist", + "prepublishOnly": "npm run clean && npm run build" + }, + "author": "", + "license": "MIT", + "files": [ + "/dist" + ], + "dependencies": { + "@datastructures-js/queue": "^4.2.3", + "@live-compositor/browser-render": "0.1.0-rc.4", + "@live-compositor/core": "0.1.0", + "live-compositor": "^0.1.0", + "mp4box": "^0.5.2", + "path-parser": "^6.1.0" + } +} diff --git a/ts/@live-compositor/web-wasm/src/compositor.ts b/ts/@live-compositor/web-wasm/src/compositor.ts new file mode 100644 index 000000000..40ade2f38 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/compositor.ts @@ -0,0 +1,86 @@ +import { Renderer } from '@live-compositor/browser-render'; +import { LiveCompositor as CoreLiveCompositor } from '@live-compositor/core'; +import WasmInstance from './manager/wasmInstance'; +import { intoRegisterOutput, RegisterOutput } from './output/registerOutput'; +import { intoRegisterInput, RegisterInput } from './input/registerInput'; +import { RegisterImage } from './renderers'; + +export type LiveCompositorOptions = { + framerate?: Framerate; + streamFallbackTimeoutMs?: number; +}; + +export type Framerate = { + num: number; + den: number; +}; + +export default class LiveCompositor { + private coreCompositor?: CoreLiveCompositor; + private instance?: WasmInstance; + private renderer?: Renderer; + private options: LiveCompositorOptions; + + public constructor(options: LiveCompositorOptions) { + this.options = options; + } + + /* + * Initializes LiveCompositor instance. It needs to be called before any resource is registered. + * Outputs won't produce any results until `start()` is called. + */ + public async init(): Promise { + this.renderer = await Renderer.create({ + streamFallbackTimeoutMs: this.options.streamFallbackTimeoutMs ?? 500, + }); + this.instance = new WasmInstance({ + renderer: this.renderer!, + framerate: this.options.framerate ?? { num: 30, den: 1 }, + }); + this.coreCompositor = new CoreLiveCompositor(this.instance!); + + await this.coreCompositor!.init(); + } + + public async registerOutput(outputId: string, request: RegisterOutput): Promise { + await this.coreCompositor!.registerOutput(outputId, intoRegisterOutput(request)); + } + + public async unregisterOutput(outputId: string): Promise { + await this.coreCompositor!.unregisterOutput(outputId); + } + + public async registerInput(inputId: string, request: RegisterInput): Promise { + await this.coreCompositor!.registerInput(inputId, intoRegisterInput(request)); + } + + public async unregisterInput(inputId: string): Promise { + await this.coreCompositor!.unregisterInput(inputId); + } + + public async registerImage(imageId: string, request: RegisterImage): Promise { + await this.coreCompositor!.registerImage(imageId, request); + } + + public async unregisterImage(imageId: string): Promise { + await this.coreCompositor!.unregisterImage(imageId); + } + + public async registerFont(fontUrl: string): Promise { + await this.renderer!.registerFont(fontUrl); + } + + /** + * Starts processing pipeline. Any previously registered output will start producing video data. + */ + public async start(): Promise { + await this.coreCompositor!.start(); + } + + /** + * Stops processing pipeline. + */ + public stop(): void { + this.instance!.stop(); + } +} diff --git a/ts/@live-compositor/web-wasm/src/eventSender.ts b/ts/@live-compositor/web-wasm/src/eventSender.ts new file mode 100644 index 000000000..048850760 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/eventSender.ts @@ -0,0 +1,62 @@ +import { CompositorEvent, CompositorEventType } from 'live-compositor'; + +export class EventSender { + private eventCallback?: (event: object) => void; + + public setEventCallback(eventCallback: (event: object) => void) { + this.eventCallback = eventCallback; + } + + public sendEvent(event: CompositorEvent) { + if (!this.eventCallback) { + console.warn(`Failed to send event: ${event}`); + return; + } + + this.eventCallback!(toWebSocketMessage(event)); + } +} + +function toWebSocketMessage(event: CompositorEvent): WebSocketMessage { + if (event.type == CompositorEventType.OUTPUT_DONE) { + return { + type: event.type, + output_id: event.outputId, + }; + } + + return { + type: event.type, + input_id: event.inputId, + }; +} + +export type WebSocketMessage = + | { + type: CompositorEventType.AUDIO_INPUT_DELIVERED; + input_id: string; + } + | { + type: CompositorEventType.VIDEO_INPUT_DELIVERED; + input_id: string; + } + | { + type: CompositorEventType.AUDIO_INPUT_PLAYING; + input_id: string; + } + | { + type: CompositorEventType.VIDEO_INPUT_PLAYING; + input_id: string; + } + | { + type: CompositorEventType.AUDIO_INPUT_EOS; + input_id: string; + } + | { + type: CompositorEventType.VIDEO_INPUT_EOS; + input_id: string; + } + | { + type: CompositorEventType.OUTPUT_DONE; + output_id: string; + }; diff --git a/ts/@live-compositor/web-wasm/src/index.ts b/ts/@live-compositor/web-wasm/src/index.ts new file mode 100644 index 000000000..4c5a74f2c --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/index.ts @@ -0,0 +1,4 @@ +import WasmInstance from './manager/wasmInstance'; +import LiveCompositor from './compositor'; + +export { WasmInstance, LiveCompositor }; diff --git a/ts/@live-compositor/web-wasm/src/input/decoder/h264Decoder.ts b/ts/@live-compositor/web-wasm/src/input/decoder/h264Decoder.ts new file mode 100644 index 000000000..a7d48f071 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/input/decoder/h264Decoder.ts @@ -0,0 +1,53 @@ +import { Queue } from '@datastructures-js/queue'; + +const MAX_DECODED_FRAMES = 3; + +export class H264Decoder { + private chunks: Queue; + private frames: Queue; + private decoder: VideoDecoder; + + public constructor() { + this.chunks = new Queue(); + this.frames = new Queue(); + // TODO(noituri): Use web workers + this.decoder = new VideoDecoder({ + output: frame => { + this.frames.push(frame); + }, + error: error => { + console.error(`MP4Decoder error: ${error}`); + }, + }); + } + + public configure(config: VideoDecoderConfig) { + this.decoder.configure(config); + } + + public enqueueChunk(chunk: EncodedVideoChunk) { + this.chunks.push(chunk); + this.decodeChunks(); + } + + /** + * Returns decoded video frames. Frames have to be manually freed from memory + */ + public getFrame(): VideoFrame | undefined { + this.decodeChunks(); + return this.frames.pop(); + } + + private decodeChunks() { + while ( + this.frames.size() < MAX_DECODED_FRAMES && + this.decoder.decodeQueueSize < MAX_DECODED_FRAMES + ) { + const chunk = this.chunks.pop(); + if (!chunk) { + break; + } + this.decoder.decode(chunk); + } + } +} diff --git a/ts/@live-compositor/web-wasm/src/input/input.ts b/ts/@live-compositor/web-wasm/src/input/input.ts new file mode 100644 index 000000000..1069caaa0 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/input/input.ts @@ -0,0 +1,60 @@ +import { Frame, InputId } from '@live-compositor/browser-render'; +import { CompositorEventType } from 'live-compositor'; +import { EventSender } from '../eventSender'; +import InputSource from './source'; + +/** + * Represents frame produced by decoder. + * `InputFrame` has to be manually freed from the memory by calling `free()` method. Once freed it no longer can be used. + * `Queue` on tick pulls `InputFrame` for each input and once render finishes, manually frees `InputFrame`s. + */ +export type InputFrame = Frame & { + /** + * Frees `InputFrame` from memory. `InputFrame` can not be used after `free()`. + */ + free: () => void; +}; + +export type InputState = 'waiting_for_start' | 'buffering' | 'playing' | 'finished'; + +export class Input { + private id: InputId; + private source: InputSource; + private state: InputState; + private eventSender: EventSender; + + public constructor(id: InputId, source: InputSource, eventSender: EventSender) { + this.id = id; + this.state = 'waiting_for_start'; + this.source = source; + this.eventSender = eventSender; + } + + public start() { + if (this.state !== 'waiting_for_start') { + console.warn(`Tried to start an already started input "${this.id}"`); + return; + } + this.source.start(); + this.state = 'buffering'; + this.eventSender.sendEvent({ + type: CompositorEventType.VIDEO_INPUT_DELIVERED, + inputId: this.id, + }); + } + + public async getFrame(): Promise { + const frame = await this.source.getFrame(); + // TODO(noituri): Handle this better + if (frame && this.state === 'buffering') { + this.state = 'playing'; + this.eventSender.sendEvent({ + type: CompositorEventType.VIDEO_INPUT_PLAYING, + inputId: this.id, + }); + } + // TODO(noituri): Handle EOS + + return frame; + } +} diff --git a/ts/@live-compositor/web-wasm/src/input/mp4/demuxer.ts b/ts/@live-compositor/web-wasm/src/input/mp4/demuxer.ts new file mode 100644 index 000000000..f78a6bc44 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/input/mp4/demuxer.ts @@ -0,0 +1,86 @@ +import MP4Box, { DataStream, MP4ArrayBuffer, MP4File, MP4Info, Sample } from 'mp4box'; + +export type OnConfig = (config: VideoDecoderConfig) => void; + +export type OnChunk = (chunk: EncodedVideoChunk) => void; + +export class MP4Demuxer { + private file: MP4File; + private fileOffset: number; + private onConfig: OnConfig; + private onChunk: OnChunk; + + public constructor(props: { onConfig: OnConfig; onChunk: OnChunk }) { + this.file = MP4Box.createFile(); + this.file.onReady = info => this.onReady(info); + this.file.onSamples = (_id, _user, samples) => this.onSamples(samples); + this.file.onError = (error: string) => { + console.error(`MP4Demuxer error: ${error}`); + }; + this.fileOffset = 0; + + this.onConfig = props.onConfig; + this.onChunk = props.onChunk; + } + + public demux(data: ArrayBuffer) { + const mp4Data = data as MP4ArrayBuffer; + mp4Data.fileStart = this.fileOffset; + this.fileOffset += mp4Data.byteLength; + + this.file.appendBuffer(mp4Data); + } + + public flush() { + this.file.flush(); + } + + private onReady(info: MP4Info) { + if (info.videoTracks.length == 0) { + throw new Error('No video tracks'); + } + + const videoTrack = info.videoTracks[0]; + const codecDescription = this.getCodecDescription(videoTrack.id); + this.onConfig({ + codec: videoTrack.codec, + codedWidth: videoTrack.video.width, + codedHeight: videoTrack.video.height, + description: codecDescription, + }); + + this.file.setExtractionOptions(videoTrack.id); + this.file.start(); + } + + private onSamples(samples: Sample[]) { + for (const sample of samples) { + const chunk = new EncodedVideoChunk({ + type: sample.is_sync ? 'key' : 'delta', + timestamp: (sample.cts * 1_000_000) / sample.timescale, + duration: (sample.duration * 1_000_000) / sample.timescale, + data: sample.data, + }); + + this.onChunk(chunk); + } + } + + private getCodecDescription(trackId: number): Uint8Array { + const track = this.file.getTrackById(trackId); + if (!track) { + throw new Error('Track does not exist'); + } + + for (const entry of track.mdia.minf.stbl.stsd.entries) { + const box = entry.avcC || entry.hvcC || entry.vpcC || entry.av1C; + if (box) { + const stream = new DataStream(undefined, 0, DataStream.BIG_ENDIAN); + box.write(stream); + return new Uint8Array(stream.buffer, 8); + } + } + + throw new Error('Codec description not found'); + } +} diff --git a/ts/examples/vite-browser-render/src/examples/mp4/mp4box.d.ts b/ts/@live-compositor/web-wasm/src/input/mp4/mp4box.d.ts similarity index 97% rename from ts/examples/vite-browser-render/src/examples/mp4/mp4box.d.ts rename to ts/@live-compositor/web-wasm/src/input/mp4/mp4box.d.ts index 4e902b553..5859feb47 100644 --- a/ts/examples/vite-browser-render/src/examples/mp4/mp4box.d.ts +++ b/ts/@live-compositor/web-wasm/src/input/mp4/mp4box.d.ts @@ -14,7 +14,7 @@ declare module 'mp4box' { onError?: (e: string) => void; onSamples?: (id: number, user: object, samples: Sample[]) => void; - getTrackById(id: number): BoxParser.trakBox | undefined; + getTrackById(id: number): TrakBox | undefined; appendBuffer(data: MP4ArrayBuffer): number; start(): void; diff --git a/ts/@live-compositor/web-wasm/src/input/mp4/source.ts b/ts/@live-compositor/web-wasm/src/input/mp4/source.ts new file mode 100644 index 000000000..42e9d48da --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/input/mp4/source.ts @@ -0,0 +1,64 @@ +import { FrameFormat } from '@live-compositor/browser-render'; +import { MP4Demuxer } from './demuxer'; +import { H264Decoder } from '../decoder/h264Decoder'; +import { InputFrame } from '../input'; +import InputSource from '../source'; + +export default class MP4Source implements InputSource { + private fileUrl: string; + private fileData?: ArrayBuffer; + private demuxer: MP4Demuxer; + private decoder: H264Decoder; + private frameFormat: VideoPixelFormat; + + public constructor(fileUrl: string) { + this.fileUrl = fileUrl; + this.demuxer = new MP4Demuxer({ + onConfig: config => this.decoder.configure(config), + onChunk: chunk => this.decoder.enqueueChunk(chunk), + }); + this.decoder = new H264Decoder(); + + // Safari does not support conversion to RGBA + // Chrome does not support conversion to YUV + const isSafari = !!(window as any).safari; + this.frameFormat = isSafari ? 'I420' : 'RGBA'; + } + + public async init(): Promise { + const resp = await fetch(this.fileUrl); + this.fileData = await resp.arrayBuffer(); + } + + public start(): void { + if (!this.fileData) { + throw new Error('MP4Source has to be initialized first before processing can be started'); + } + + this.demuxer.demux(this.fileData); + this.demuxer.flush(); + } + + public async getFrame(): Promise { + const frame = this.decoder.getFrame(); + if (!frame) { + return undefined; + } + + const options = { + format: this.frameFormat, + }; + const buffer = new Uint8ClampedArray(frame.allocationSize(options as VideoFrameCopyToOptions)); + await frame.copyTo(buffer, options as VideoFrameCopyToOptions); + + return { + resolution: { + width: frame.displayWidth, + height: frame.displayHeight, + }, + format: this.frameFormat == 'I420' ? FrameFormat.YUV_BYTES : FrameFormat.RGBA_BYTES, + data: buffer, + free: () => frame.close(), + }; + } +} diff --git a/ts/@live-compositor/web-wasm/src/input/registerInput.ts b/ts/@live-compositor/web-wasm/src/input/registerInput.ts new file mode 100644 index 000000000..1e0693593 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/input/registerInput.ts @@ -0,0 +1,15 @@ +import { RegisterInput as InternalRegisterInput } from '@live-compositor/core'; + +export type RegisterInput = { type: 'mp4' } & RegisterMP4Input; + +export type RegisterMP4Input = { + url: string; +}; + +export function intoRegisterInput(input: RegisterInput): InternalRegisterInput { + if (input.type === 'mp4') { + return { type: 'mp4', url: input.url }; + } else { + throw new Error(`Unknown input type ${(input as any).type}`); + } +} diff --git a/ts/@live-compositor/web-wasm/src/input/source.ts b/ts/@live-compositor/web-wasm/src/input/source.ts new file mode 100644 index 000000000..47dac36b0 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/input/source.ts @@ -0,0 +1,20 @@ +import { RegisterInputRequest } from '@live-compositor/core'; +import { InputFrame } from './input'; +import MP4Source from './mp4/source'; + +export default interface InputSource { + init(): Promise; + /** + * Starts input processing. `init()` has to be called beforehand. + */ + start(): void; + getFrame(): Promise; +} + +export function sourceFromRequest(request: RegisterInputRequest): InputSource { + if (request.type === 'mp4') { + return new MP4Source(request.url!); + } else { + throw new Error(`Unknown input type ${(request as any).type}`); + } +} diff --git a/ts/@live-compositor/web-wasm/src/manager/wasmInstance.ts b/ts/@live-compositor/web-wasm/src/manager/wasmInstance.ts new file mode 100644 index 000000000..da18d3778 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/manager/wasmInstance.ts @@ -0,0 +1,158 @@ +import { + ApiRequest, + CompositorManager, + RegisterInputRequest, + RegisterOutputRequest, +} from '@live-compositor/core'; +import { Renderer, Component, ImageSpec } from '@live-compositor/browser-render'; +import { Api } from 'live-compositor'; +import { Path } from 'path-parser'; +import { Queue, StopQueueFn } from '../queue'; +import { Input } from '../input/input'; +import { EventSender } from '../eventSender'; +import { Framerate } from '../compositor'; +import { Output } from '../output/output'; +import { sourceFromRequest } from '../input/source'; + +export type OnRegisterCallback = (event: object) => void; + +const apiPath = new Path('/api/:type/:id/:operation'); +const apiStartPath = new Path('/api/start'); + +class WasmInstance implements CompositorManager { + private renderer: Renderer; + private queue: Queue; + private eventSender: EventSender; + private stopQueue?: StopQueueFn; + + public constructor(props: { renderer: Renderer; framerate: Framerate }) { + this.renderer = props.renderer; + this.queue = new Queue(props.framerate, props.renderer); + this.eventSender = new EventSender(); + } + + public async setupInstance(): Promise {} + + public async sendRequest(request: ApiRequest): Promise { + const route = apiPath.test(request.route); + if (!route) { + if (apiStartPath.test(request.route)) { + this.start(); + } + return {}; + } + + if (route.type == 'input') { + await this.handleInputRequest(route.id, route.operation, request.body); + } else if (route.type === 'output') { + this.handleOutputRequest(route.id, route.operation, request.body); + } else if (route.type === 'image') { + await this.handleImageRequest(route.id, route.operation, request.body); + } else if (route.type === 'shader') { + throw new Error('Shaders are not supported'); + } else if (route.type === 'web-renderer') { + throw new Error('Web renderers are not supported'); + } + + return {}; + } + + public registerEventListener(cb: (event: unknown) => void): void { + this.eventSender.setEventCallback(cb); + } + + private start() { + if (this.stopQueue) { + throw new Error('Compositor is already running'); + } + this.stopQueue = this.queue.start(); + } + + public stop() { + // TODO(noituri): Clean all remaining `InputFrame`s + if (this.stopQueue) { + this.stopQueue(); + this.stopQueue = undefined; + } + } + + private async handleInputRequest( + inputId: string, + operation: string, + body?: object + ): Promise { + if (operation === 'register') { + await this.registerInput(inputId, body! as RegisterInputRequest); + } else if (operation === 'unregister') { + this.queue.removeInput(inputId); + this.renderer.unregisterInput(inputId); + } + } + + private handleOutputRequest(outputId: string, operation: string, body?: object) { + if (operation === 'register') { + this.registerOutput(outputId, body! as RegisterOutputRequest); + } else if (operation === 'unregister') { + this.queue.removeOutput(outputId); + this.renderer.unregisterOutput(outputId); + } else if (operation === 'update') { + this.updateScene(outputId, body! as Api.UpdateOutputRequest); + } + } + + private async handleImageRequest( + imageId: string, + operation: string, + body?: object + ): Promise { + if (operation === 'register') { + await this.renderer.registerImage(imageId, body as ImageSpec); + } else if (operation === 'unregister') { + this.renderer.unregisterImage(imageId); + } + } + + private async registerInput(inputId: string, request: RegisterInputRequest): Promise { + const inputSource = sourceFromRequest(request); + await inputSource.init(); + + const input = new Input(inputId, inputSource, this.eventSender); + // `addInput` will throw an exception if input already exists + this.queue.addInput(inputId, input); + this.renderer.registerInput(inputId); + input.start(); + } + + private registerOutput(outputId: string, request: RegisterOutputRequest) { + if (request.video) { + const output = new Output(request); + this.queue.addOutput(outputId, output); + try { + // `updateScene` implicitly registers the output. + // In case of an error, the output has to be manually cleaned up from the renderer. + this.renderer.updateScene( + outputId, + request.video.resolution, + request.video.initial.root as Component + ); + } catch (e) { + this.queue.removeOutput(outputId); + this.renderer.unregisterOutput(outputId); + throw e; + } + } + } + + private updateScene(outputId: string, request: Api.UpdateOutputRequest) { + if (!request.video) { + return; + } + const output = this.queue.getOutput(outputId); + if (!output) { + throw `Unknown output "${outputId}"`; + } + this.renderer.updateScene(outputId, output.resolution, request.video.root as Component); + } +} + +export default WasmInstance; diff --git a/ts/@live-compositor/web-wasm/src/output/canvas.ts b/ts/@live-compositor/web-wasm/src/output/canvas.ts new file mode 100644 index 000000000..3def53a6c --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/output/canvas.ts @@ -0,0 +1,15 @@ +import { Frame } from '@live-compositor/browser-render'; +import { OutputSink } from './sink'; + +export default class CanvasSink implements OutputSink { + private ctx: CanvasRenderingContext2D; + + public constructor(canvas: HTMLCanvasElement) { + this.ctx = canvas.getContext('2d')!; + } + + public async send(frame: Frame): Promise { + const resolution = frame.resolution; + this.ctx.putImageData(new ImageData(frame.data, resolution.width, resolution.height), 0, 0); + } +} diff --git a/ts/@live-compositor/web-wasm/src/output/output.ts b/ts/@live-compositor/web-wasm/src/output/output.ts new file mode 100644 index 000000000..0a9682486 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/output/output.ts @@ -0,0 +1,22 @@ +import { Frame, Resolution } from '@live-compositor/browser-render'; +import { OutputSink } from './sink'; +import CanvasSink from './canvas'; +import { RegisterOutputRequest } from '@live-compositor/core'; + +export class Output { + private sink: OutputSink; + public readonly resolution: Resolution; + + public constructor(request: RegisterOutputRequest) { + if (request.type === 'canvas') { + this.sink = new CanvasSink(request.video.canvas); + } else { + throw new Error(`Unknown output type ${(request as any).type}`); + } + this.resolution = request.video.resolution; + } + + public async send(frame: Frame): Promise { + await this.sink.send(frame); + } +} diff --git a/ts/@live-compositor/web-wasm/src/output/registerOutput.ts b/ts/@live-compositor/web-wasm/src/output/registerOutput.ts new file mode 100644 index 000000000..87d37b1d8 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/output/registerOutput.ts @@ -0,0 +1,29 @@ +import { Resolution } from '@live-compositor/browser-render'; +import { RegisterOutput as InternalRegisterOutput } from '@live-compositor/core'; + +export type RegisterOutput = { type: 'canvas' } & RegisterCanvasOutput; + +export type RegisterCanvasOutput = { + resolution: Resolution; + canvas: HTMLCanvasElement; + root: React.ReactElement; +}; + +export function intoRegisterOutput(output: RegisterOutput): InternalRegisterOutput { + if (output.type === 'canvas') { + return fromRegisterCanvasOutput(output); + } else { + throw new Error(`Unknown output type ${(output as any).type}`); + } +} + +function fromRegisterCanvasOutput(output: RegisterCanvasOutput): InternalRegisterOutput { + return { + type: 'canvas', + video: { + resolution: output.resolution, + canvas: output.canvas, + root: output.root, + }, + }; +} diff --git a/ts/@live-compositor/web-wasm/src/output/sink.ts b/ts/@live-compositor/web-wasm/src/output/sink.ts new file mode 100644 index 000000000..8d7677d55 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/output/sink.ts @@ -0,0 +1,5 @@ +import { Frame } from '@live-compositor/browser-render'; + +export interface OutputSink { + send(frame: Frame): Promise; +} diff --git a/ts/@live-compositor/web-wasm/src/queue.ts b/ts/@live-compositor/web-wasm/src/queue.ts new file mode 100644 index 000000000..b15e2f482 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/queue.ts @@ -0,0 +1,93 @@ +import { FrameSet, InputId, OutputId, Renderer } from '@live-compositor/browser-render'; +import { Framerate } from './compositor'; +import { Input, InputFrame } from './input/input'; +import { Output } from './output/output'; + +export type StopQueueFn = () => void; + +export class Queue { + private inputs: Record = {}; + private outputs: Record = {}; + private renderer: Renderer; + private framerate: Framerate; + private currentPts: number; + + public constructor(framerate: Framerate, renderer: Renderer) { + this.renderer = renderer; + this.framerate = framerate; + this.currentPts = 0; + } + + public start(): StopQueueFn { + const tickDuration = (1000 * this.framerate.den) / this.framerate.num; + const queueInterval = setInterval(async () => { + await this.onTick(); + this.currentPts += tickDuration; + }, tickDuration); + + return () => clearInterval(queueInterval); + } + + public addInput(inputId: InputId, input: Input) { + if (this.inputs[inputId]) { + throw `Input "${inputId}" already exists`; + } + this.inputs[inputId] = input; + } + + public removeInput(inputId: InputId) { + delete this.inputs[inputId]; + } + + public getInput(inputId: InputId): Input | undefined { + return this.inputs[inputId]; + } + + public addOutput(outputId: OutputId, output: Output) { + if (this.outputs[outputId]) { + throw `Output "${outputId}" already exists`; + } + this.outputs[outputId] = output; + } + + public removeOutput(outputId: OutputId) { + delete this.outputs[outputId]; + } + + public getOutput(outputId: OutputId): Output | undefined { + return this.outputs[outputId]; + } + + private async onTick() { + const inputs = await this.getInputFrames(); + const outputs = this.renderer.render({ + ptsMs: this.currentPts, + frames: inputs, + }); + this.sendOutputs(outputs); + + for (const input of Object.values(inputs)) { + input.free(); + } + } + + private async getInputFrames(): Promise> { + const pendingFrames = Object.entries(this.inputs).map(async ([inputId, input]) => [ + inputId, + await input.getFrame(), + ]); + const frames = await Promise.all(pendingFrames); + return Object.fromEntries(frames.filter(([_inputId, frame]) => !!frame)); + } + + private sendOutputs(outputs: FrameSet) { + for (const [outputId, frame] of Object.entries(outputs.frames)) { + const output = this.outputs[outputId]; + if (!output) { + console.warn(`Output "${outputId}" not found`); + continue; + } + void output.send(frame); + } + } +} diff --git a/ts/@live-compositor/web-wasm/src/renderers.ts b/ts/@live-compositor/web-wasm/src/renderers.ts new file mode 100644 index 000000000..dd5db0cb8 --- /dev/null +++ b/ts/@live-compositor/web-wasm/src/renderers.ts @@ -0,0 +1,3 @@ +import { Renderers } from 'live-compositor'; + +export type RegisterImage = Required>; diff --git a/ts/@live-compositor/web-wasm/tsconfig.json b/ts/@live-compositor/web-wasm/tsconfig.json new file mode 100644 index 000000000..91458fd4f --- /dev/null +++ b/ts/@live-compositor/web-wasm/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "module": "ESNext", + "moduleResolution": "bundler", + "target": "ESNext" + } +} diff --git a/ts/examples/vite-browser-render/.gitignore b/ts/examples/vite-browser-render/.gitignore index 1f05e5163..c0468f536 100644 --- a/ts/examples/vite-browser-render/.gitignore +++ b/ts/examples/vite-browser-render/.gitignore @@ -11,6 +11,7 @@ node_modules dist dist-ssr *.local +*.tsbuildinfo # Editor directories and files .vscode/* diff --git a/ts/examples/vite-browser-render/package.json b/ts/examples/vite-browser-render/package.json index f558dbad2..5790d75ea 100644 --- a/ts/examples/vite-browser-render/package.json +++ b/ts/examples/vite-browser-render/package.json @@ -11,8 +11,8 @@ "preview": "vite preview" }, "dependencies": { - "@live-compositor/browser-render": "^0.1.0-rc.4", - "mp4box": "^0.5.2", + "@live-compositor/browser-render": "0.1.0-rc.4", + "@live-compositor/web-wasm": "0.1.0-rc.0", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/ts/examples/vite-browser-render/src/App.css b/ts/examples/vite-browser-render/src/App.css index 11c2ca5f6..4beee6d83 100644 --- a/ts/examples/vite-browser-render/src/App.css +++ b/ts/examples/vite-browser-render/src/App.css @@ -6,6 +6,8 @@ } .card { + display: flex; + flex-direction: column; padding: 2em; } @@ -17,3 +19,4 @@ .examples-tabs button { margin: 5px; } + diff --git a/ts/examples/vite-browser-render/src/App.tsx b/ts/examples/vite-browser-render/src/App.tsx index 139510364..1e2b754ca 100644 --- a/ts/examples/vite-browser-render/src/App.tsx +++ b/ts/examples/vite-browser-render/src/App.tsx @@ -3,12 +3,11 @@ import './App.css'; import Counter from './examples/Counter'; import MP4Player from './examples/MP4Player'; -const EXAMPLES = { - 'counter': , - 'mp4': -}; - function App() { + const EXAMPLES = { + 'counter': , + 'mp4': , + }; const [currentExample, setCurrentExample] = useState('counter'); return ( diff --git a/ts/examples/vite-browser-render/src/examples/Counter.tsx b/ts/examples/vite-browser-render/src/examples/Counter.tsx index 49647411a..cfcdcaf4a 100644 --- a/ts/examples/vite-browser-render/src/examples/Counter.tsx +++ b/ts/examples/vite-browser-render/src/examples/Counter.tsx @@ -1,6 +1,5 @@ - import { useEffect, useRef, useState } from 'react'; -import { useRenderer } from './utils'; +import { loadWasmModule, Renderer } from '@live-compositor/browser-render'; function Counter() { const canvasRef = useRef(null); @@ -14,7 +13,7 @@ function Counter() { renderer.updateScene( 'output', - { width: 256, height: 256 }, + { width: 300, height: 300 }, { type: 'view', children: [ @@ -70,4 +69,30 @@ function Counter() { ); } +function useRenderer(): Renderer | null { + const [renderer, setRenderer] = useState(null); + useEffect(() => { + const setupRenderer = async () => { + await loadWasmModule('./assets/live-compositor.wasm'); + const renderer = await Renderer.create({ + streamFallbackTimeoutMs: 500, + }); + + await renderer.registerImage('img', { + asset_type: 'gif', + url: 'https://media.tenor.com/eFPFHSN4rJ8AAAAM/example.gif', + }); + await renderer.registerFont( + 'https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9a6Vc.ttf' + ); + + setRenderer(renderer); + }; + + setupRenderer().catch(err => console.error(err)); + }, []); + + return renderer; +} + export default Counter; diff --git a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx index 7e17ab609..6c6eb12dc 100644 --- a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx +++ b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx @@ -1,139 +1,20 @@ -import { MP4ArrayBuffer } from 'mp4box'; -import { MP4Decoder } from './mp4/decoder'; -import { FrameFormat, FrameSet } from '@live-compositor/browser-render'; -import { useEffect, useRef } from 'react'; -import { useRenderer } from './utils'; +import { useCallback, useEffect, useState } from 'react'; +import { LiveCompositor } from '@live-compositor/web-wasm'; +import { InputStream, Text, useInputStreams, View } from 'live-compositor'; const BUNNY_URL = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'; function MP4Player() { - const canvasRef = useRef(null); - const renderer = useRenderer(); + const [compositor, canvasRef] = useCompositor(); useEffect(() => { - if (renderer == null) { + if (compositor == null) { return; } - renderer.registerInput('bunny_video'); - renderer.updateScene( - 'output', - { - width: 1280, - height: 720, - }, - { - type: 'view', - background_color_rgba: '#000000FF', - children: [ - { - type: 'view', - top: 300, - left: 500, - children: [ - { - type: 'text', - font_size: 30, - font_family: 'Noto Sans', - text: 'Loading MP4 file', - align: 'right', - }, - ], - }, - ], - } - ); - - const decoder = new MP4Decoder(); - fetch(BUNNY_URL) - .then(resp => resp.arrayBuffer()) - .then(videoData => { - renderer.updateScene( - 'output', - { - width: 1280, - height: 720, - }, - { - type: 'view', - width: 1280, - height: 720, - background_color_rgba: '#000000FF', - children: [ - { - type: 'input_stream', - input_id: 'bunny_video', - }, - { - type: 'view', - width: 230, - height: 40, - background_color_rgba: '#000000FF', - bottom: 20, - left: 500, - children: [ - { - type: 'text', - font_size: 30, - font_family: 'Noto Sans', - text: 'Playing MP4 file', - align: 'center', - }, - ], - }, - ], - } - ); - - decoder.decode(videoData as MP4ArrayBuffer); - }); - - const canvas = canvasRef!.current!; - const ctx = canvas.getContext('2d'); - - let pts = 0; - const renderInterval = setInterval(async () => { - const inputs: FrameSet = { - ptsMs: pts, - frames: {}, - }; - - const frame = decoder.nextFrame(); - if (frame) { - const frameOptions = { - format: 'RGBA', - }; - const buffer = new Uint8ClampedArray( - frame.allocationSize(frameOptions as VideoFrameCopyToOptions) - ); - await frame.copyTo(buffer, frameOptions as VideoFrameCopyToOptions); - - inputs.frames['bunny_video'] = { - resolution: { - width: frame.displayWidth, - height: frame.displayHeight, - }, - format: FrameFormat.RGBA_BYTES, - data: buffer, - }; - } - - const outputs = renderer.render(inputs); - const output = outputs.frames['output']; - ctx!.putImageData( - new ImageData(output.data, output.resolution.width, output.resolution.height), - 0, - 0 - ); - - if (frame) { - frame.close(); - } - pts += 30; - }, 30); - - return () => clearInterval(renderInterval); - }, [renderer]) + void compositor.start(); + return () => compositor.stop(); + }, [compositor]) return ( <> @@ -144,4 +25,73 @@ function MP4Player() { ); } +function Scene() { + const inputs = useInputStreams(); + const inputState = inputs['bunny_video']?.videoState; + + if (inputState !== 'playing') { + return ( + + + + Loading MP4 file + + + + ); + } + + return ( + + + + + Playing MP4 file + + + + ); +} + +function useCompositor(): [LiveCompositor | undefined, (canvas: HTMLCanvasElement) => void] { + const [compositor, setCompositor] = useState(undefined); + const canvasRef = useCallback((canvas: HTMLCanvasElement) => { + if (!canvas) { + return; + } + + const setupCompositor = async () => { + const compositor = new LiveCompositor({ + framerate: { + num: 30, + den: 1, + }, + streamFallbackTimeoutMs: 500, + }); + + await compositor.init(); + + setCompositor(compositor); + + await compositor.registerFont( + 'https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9a6Vc.ttf' + ); + void compositor.registerInput('bunny_video', { type: 'mp4', url: BUNNY_URL }); + await compositor.registerOutput('output', { + type: 'canvas', + canvas: canvas, + resolution: { + width: 1280, + height: 720, + }, + root: , + }); + } + + setupCompositor(); + }, []) + + return [compositor, canvasRef]; +} + export default MP4Player; diff --git a/ts/examples/vite-browser-render/src/examples/mp4/decoder.ts b/ts/examples/vite-browser-render/src/examples/mp4/decoder.ts deleted file mode 100644 index a63fe2973..000000000 --- a/ts/examples/vite-browser-render/src/examples/mp4/decoder.ts +++ /dev/null @@ -1,97 +0,0 @@ -import MP4Box, { DataStream, MP4ArrayBuffer, MP4File, MP4Info, Sample, TrakBox } from "mp4box"; - -const MAX_FRAMEBUFFER_SIZE = 3; - -export class MP4Decoder { - private file: MP4File; - private chunks: EncodedVideoChunk[] = []; - private frames: VideoFrame[] = []; - private decoder: VideoDecoder; - - public constructor() { - this.file = MP4Box.createFile(); - this.decoder = new VideoDecoder({ - output: frame => { - this.frames.push(frame); - }, - error: error => { - console.error(`VideoDecoder Error: ${error}`); - }, - }); - - this.file.onReady = info => this.onReady(info); - this.file.onSamples = (id, user, info) => this.onSamples(id, user, info); - this.file.onError = (error: string) => { - console.error(`MP4 Parser Error: ${error}`); - }; - } - - public decode(videoData: MP4ArrayBuffer) { - videoData.fileStart = 0; - this.file.appendBuffer(videoData); - this.file.flush(); - } - - public nextFrame(): VideoFrame | undefined { - this.enqueueNextChunks(); - - return this.frames.shift(); - } - - private enqueueNextChunks() { - while (this.decoder.decodeQueueSize < MAX_FRAMEBUFFER_SIZE && this.frames.length < MAX_FRAMEBUFFER_SIZE) { - const chunk = this.chunks.shift(); - if (!chunk) { - return null; - } - - this.decoder.decode(chunk); - } - } - - private onReady(info: MP4Info) { - const videoTrack = info.videoTracks[0]; - console.log(`Using codec: ${videoTrack.codec}`); - - const trak = this.file.getTrackById(videoTrack.id); - const description = getCodecDescription(trak); - if (!description) { - console.error('Codec description not found'); - return; - } - - this.decoder.configure({ - codec: videoTrack.codec, - codedWidth: videoTrack.video.width, - codedHeight: videoTrack.video.height, - description: description, - }); - - this.file.setExtractionOptions(videoTrack.id); - this.file.start(); - } - - private onSamples(_id: number, _user: object, samples: Sample[]) { - for (const sample of samples) { - const chunk = new EncodedVideoChunk({ - type: sample.is_sync ? 'key' : 'delta', - timestamp: (sample.cts * 1_000_000) / sample.timescale, - duration: (sample.duration * 1_000_000) / sample.timescale, - data: sample.data, - }); - - this.chunks.push(chunk); - } - } -} - -function getCodecDescription(trak: TrakBox) { - for (const entry of trak.mdia.minf.stbl.stsd.entries) { - const box = entry.avcC || entry.hvcC || entry.vpcC || entry.av1C; - if (box) { - const stream = new DataStream(undefined, 0, DataStream.BIG_ENDIAN); - box.write(stream); - return new Uint8Array(stream.buffer, 8); - } - } -} diff --git a/ts/examples/vite-browser-render/src/examples/utils.ts b/ts/examples/vite-browser-render/src/examples/utils.ts deleted file mode 100644 index 8a8dd02ff..000000000 --- a/ts/examples/vite-browser-render/src/examples/utils.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { loadWasmModule, Renderer } from "@live-compositor/browser-render"; -import { useEffect, useState } from "react"; - -export function useRenderer(): Renderer | null { - const [renderer, setRenderer] = useState(null); - useEffect(() => { - const setupRenderer = async () => { - await loadWasmModule('./assets/live-compositor.wasm'); - const renderer = await Renderer.create({ - streamFallbackTimeoutMs: 500, - }); - - await renderer.registerImage('img', { - asset_type: 'gif', - url: 'https://media.tenor.com/eFPFHSN4rJ8AAAAM/example.gif', - }); - await renderer.registerFont( - 'https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9a6Vc.ttf' - ); - - setRenderer(renderer); - }; - - setupRenderer().catch(err => console.error(err)); - }, []); - - return renderer; -} diff --git a/ts/live-compositor/src/index.ts b/ts/live-compositor/src/index.ts index 15bd4cbfc..73df9f7b1 100644 --- a/ts/live-compositor/src/index.ts +++ b/ts/live-compositor/src/index.ts @@ -10,8 +10,12 @@ import { EasingFunction, Transition } from './components/common.js'; import { useAudioInput, useInputStreams } from './hooks.js'; import { CompositorEvent, CompositorEventType } from './types/events.js'; -export { RegisterInput } from './types/registerInput.js'; -export { RegisterOutput } from './types/registerOutput.js'; +export { RegisterRtpInput, RegisterMp4Input } from './types/registerInput.js'; +export { + RegisterRtpOutput, + RegisterMp4Output, + RegisterCanvasOutput, +} from './types/registerOutput.js'; export * as Inputs from './types/registerInput.js'; export * as Outputs from './types/registerOutput.js'; diff --git a/ts/live-compositor/src/types/registerInput.ts b/ts/live-compositor/src/types/registerInput.ts index e0d0b38bb..faffa7d23 100644 --- a/ts/live-compositor/src/types/registerInput.ts +++ b/ts/live-compositor/src/types/registerInput.ts @@ -1,9 +1,5 @@ import * as Api from '../api.js'; -export type RegisterInput = - | ({ type: 'rtp_stream' } & RegisterRtpInput) - | ({ type: 'mp4' } & RegisterMp4Input); - export type RegisterRtpInput = { /** * UDP port or port range on which the compositor should listen for the stream. diff --git a/ts/live-compositor/src/types/registerOutput.ts b/ts/live-compositor/src/types/registerOutput.ts index 620c9428e..22e653031 100644 --- a/ts/live-compositor/src/types/registerOutput.ts +++ b/ts/live-compositor/src/types/registerOutput.ts @@ -1,10 +1,6 @@ import React from 'react'; import * as Api from '../api.js'; -export type RegisterOutput = - | ({ type: 'rtp_stream' } & RegisterRtpOutput) - | ({ type: 'mp4' } & RegisterMp4Output); - export type RegisterRtpOutput = { /** * Depends on the value of the `transport_protocol` field: @@ -39,6 +35,10 @@ export type RegisterMp4Output = { audio?: Mp4AudioOptions; }; +export type RegisterCanvasOutput = { + video: OutputCanvasVideoOptions; +}; + export type RtpVideoOptions = { /** * Output resolution in pixels. @@ -73,6 +73,18 @@ export type Mp4VideoOptions = { root: React.ReactElement; }; +export type OutputCanvasVideoOptions = { + /** + * Output resolution in pixels. + */ + resolution: Api.Resolution; + /** + * HTMLCanvasElement + */ + canvas: any; + root: React.ReactElement; +}; + export type RtpVideoEncoderOptions = { type: 'ffmpeg_h264'; /** diff --git a/ts/package-lock.json b/ts/package-lock.json index d69507e6a..9315e68ee 100644 --- a/ts/package-lock.json +++ b/ts/package-lock.json @@ -11,6 +11,7 @@ "live-compositor", "@live-compositor/core", "@live-compositor/node", + "@live-compositor/web-wasm", "@live-compositor/browser-render", "examples/node-examples", "examples/vite-browser-render", @@ -80,52 +81,10 @@ "@types/ws": "^8.5.12" } }, - "@live-compositor/node/node_modules/chownr": { - "version": "3.0.0", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "@live-compositor/node/node_modules/minizlib": { - "version": "3.0.1", - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "@live-compositor/node/node_modules/mkdirp": { - "version": "3.0.1", - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "@live-compositor/node/node_modules/rimraf": { - "version": "5.0.10", - "license": "ISC", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "@live-compositor/node/node_modules/tar": { "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", @@ -139,11 +98,16 @@ "node": ">=18" } }, - "@live-compositor/node/node_modules/yallist": { - "version": "5.0.0", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" + "@live-compositor/web-wasm": { + "version": "0.1.0-rc.0", + "license": "MIT", + "dependencies": { + "@datastructures-js/queue": "^4.2.3", + "@live-compositor/browser-render": "0.1.0-rc.4", + "@live-compositor/core": "0.1.0", + "live-compositor": "^0.1.0", + "mp4box": "^0.5.2", + "path-parser": "^6.1.0" } }, "create-live-compositor": { @@ -212,8 +176,8 @@ "name": "example", "version": "1.0.0", "dependencies": { - "@live-compositor/browser-render": "^0.1.0-rc.4", - "mp4box": "^0.5.2", + "@live-compositor/browser-render": "0.1.0-rc.4", + "@live-compositor/web-wasm": "0.1.0-rc.0", "react": "^18.3.1", "react-dom": "^18.3.1" }, @@ -232,91 +196,33 @@ "vite-plugin-static-copy": "^1.0.6" } }, - "examples/vite-browser-render/node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "examples/vite-browser-render/node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "examples/vite-browser-render/node_modules/@eslint/js": { - "version": "9.12.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "examples/vite-browser-render/node_modules/@eslint/plugin-kit": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz", - "integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "examples/vite-browser-render/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "examples/vite-browser-render/node_modules/eslint": { - "version": "9.10.0", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", + "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.10.0", - "@eslint/plugin-kit": "^0.1.0", + "@eslint/js": "9.13.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -326,13 +232,11 @@ "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { @@ -353,103 +257,6 @@ } } }, - "examples/vite-browser-render/node_modules/eslint-scope": { - "version": "8.1.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "examples/vite-browser-render/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "examples/vite-browser-render/node_modules/eslint/node_modules/@eslint/js": { - "version": "9.10.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "examples/vite-browser-render/node_modules/espree": { - "version": "10.2.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "examples/vite-browser-render/node_modules/file-entry-cache": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "examples/vite-browser-render/node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "examples/vite-browser-render/node_modules/globals": { - "version": "15.11.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "examples/vite-browser-render/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "live-compositor": { "version": "0.1.0", "license": "MIT", @@ -475,9 +282,9 @@ } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.0.tgz", - "integrity": "sha512-pRrmXMCwnmrkS3MLgAIW5dXRzeTv6GLjkjb4HmxNnvAKXN1Nfzp4KmGADBQvlVUcqi+a5D+hfGDLLnd5NnYxog==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz", + "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", "dev": true, "license": "MIT", "dependencies": { @@ -507,9 +314,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz", - "integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", + "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", "dev": true, "license": "MIT", "engines": { @@ -517,9 +324,9 @@ } }, "node_modules/@babel/core": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz", - "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", + "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", "dev": true, "license": "MIT", "dependencies": { @@ -529,10 +336,10 @@ "@babel/helper-compilation-targets": "^7.25.7", "@babel/helper-module-transforms": "^7.25.7", "@babel/helpers": "^7.25.7", - "@babel/parser": "^7.25.7", + "@babel/parser": "^7.25.8", "@babel/template": "^7.25.7", "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7", + "@babel/types": "^7.25.8", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -547,19 +354,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -603,16 +397,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -623,13 +407,6 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, "node_modules/@babel/helper-module-imports": { "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", @@ -826,13 +603,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz", - "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.7" + "@babel/types": "^7.25.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -918,9 +695,9 @@ } }, "node_modules/@babel/types": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz", - "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", "dev": true, "license": "MIT", "dependencies": { @@ -954,10 +731,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@datastructures-js/queue": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@datastructures-js/queue/-/queue-4.2.3.tgz", + "integrity": "sha512-GWVMorC/xi2V2ta+Z/CPgPGHL2ZJozcj48g7y2nIX5GIGZGRrbShSHgvMViJwHJurUzJYOdIdRZnWDRrROFwJA==", + "license": "MIT" + }, "node_modules/@emnapi/core": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.0.tgz", - "integrity": "sha512-9hRqVlhwqBqCoToZ3hFcNVqL+uyHV06Y47ax4UB8L6XgVRqYz7MFnfessojo6+5TK89pKwJnpophwjTMOeKI9Q==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz", + "integrity": "sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==", "dev": true, "license": "MIT", "dependencies": { @@ -966,9 +749,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.0.tgz", - "integrity": "sha512-XMBySMuNZs3DM96xcJmLW4EfGnf+uGmFNjzpehMjuX5PLB5j87ar2Zc4e3PVeZ3I5g3tYtAqskB28manlF69Zw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", "dev": true, "license": "MIT", "dependencies": { @@ -1392,6 +1175,19 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { "version": "4.11.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", @@ -1417,41 +1213,27 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@eslint/core": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "Apache-2.0", "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -1459,44 +1241,33 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", + "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/object-schema": { @@ -1510,9 +1281,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz", + "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1522,44 +1293,44 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@humanfs/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", + "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", "dev": true, "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@humanfs/node": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", + "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "brace-expansion": "^1.1.7" + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { - "node": "*" + "node": ">=10.10.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -1652,6 +1423,18 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", @@ -1813,17 +1596,6 @@ "node": ">=18.0.0" } }, - "node_modules/@lerna/create/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/@lerna/create/node_modules/chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -1848,51 +1620,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@lerna/create/node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@lerna/create/node_modules/glob/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@lerna/create/node_modules/glob/node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@lerna/create/node_modules/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", @@ -1906,16 +1633,6 @@ "node": "*" } }, - "node_modules/@lerna/create/node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, "node_modules/@lerna/create/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -1926,25 +1643,6 @@ "node": ">=8" } }, - "node_modules/@lerna/create/node_modules/rimraf": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", - "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^9.2.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@lerna/create/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -1967,19 +1665,6 @@ "node": ">=8" } }, - "node_modules/@lerna/create/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@live-compositor/browser-render": { "resolved": "@live-compositor/browser-render", "link": true @@ -1992,6 +1677,10 @@ "resolved": "@live-compositor/node", "link": true }, + "node_modules/@live-compositor/web-wasm": { + "resolved": "@live-compositor/web-wasm", + "link": true + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", @@ -2069,6 +1758,13 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@npmcli/agent/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, + "license": "ISC" + }, "node_modules/@npmcli/arborist": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.5.4.tgz", @@ -2119,6 +1815,39 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@npmcli/arborist/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/arborist/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, + "license": "ISC" + }, + "node_modules/@npmcli/arborist/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@npmcli/fs": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", @@ -2173,6 +1902,13 @@ "node": ">=16" } }, + "node_modules/@npmcli/git/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, + "license": "ISC" + }, "node_modules/@npmcli/git/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -2222,6 +1958,32 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/map-workspaces/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@npmcli/metavuln-calculator": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-7.1.1.tgz", @@ -2385,23 +2147,23 @@ } }, "node_modules/@nrwl/devkit": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.8.4.tgz", - "integrity": "sha512-OoIqDjj2mWzLs3aSF6w5OiC2xywYi/jBxHc7t7Lyi56Vc4dQq8vJMELa9WtG6qH0k05fF7N+jAoKlfvLgbbEFA==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.8.6.tgz", + "integrity": "sha512-F6+4Lv2hSS+02H7aqa+jYIHzbmip7082DF9/NkNtUAEqLUi8STsbung0nchaR1Tjg20E+BZujEsZgTC3GJegLQ==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "19.8.4" + "@nx/devkit": "19.8.6" } }, "node_modules/@nrwl/tao": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.8.4.tgz", - "integrity": "sha512-03/+QZ4/6HmKbEmvzCutLI1XIclBspNYtiVHmGPRWuwhnZViqYfnyl8J7RWVdFEoKKA5fhJqpg7e28aGuoMBvQ==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.8.6.tgz", + "integrity": "sha512-ibxGL7aDpNARgPegXQ8HAocemZ1WvZE5+NHkXDs7jSmnSt9qaXIKE1dXotDTqp3TqCirlje1/RMMTqzCl2oExQ==", "dev": true, "license": "MIT", "dependencies": { - "nx": "19.8.4", + "nx": "19.8.6", "tslib": "^2.3.0" }, "bin": { @@ -2409,13 +2171,13 @@ } }, "node_modules/@nx/devkit": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.8.4.tgz", - "integrity": "sha512-FPFT8gVDFRSEmU0n7nRkT4Rnqy7OMznfPXLfDZtVuzEi5Cl6ftG3UBUvCgJcJFCYJVAZAUuv6vRSRarHd51XFQ==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.8.6.tgz", + "integrity": "sha512-8NAdnqwzki3srj2sAImWQ9cQiq79NqwqVqx/XOdg0XHR6siugn+sAAXWpM3xJVdv4uRbcyz7BO1GWYxMW0AOYA==", "dev": true, "license": "MIT", "dependencies": { - "@nrwl/devkit": "19.8.4", + "@nrwl/devkit": "19.8.6", "ejs": "^3.1.7", "enquirer": "~2.3.6", "ignore": "^5.0.4", @@ -2426,7 +2188,17 @@ "yargs-parser": "21.1.1" }, "peerDependencies": { - "nx": ">= 17 <= 20" + "nx": ">= 19 <= 21" + } + }, + "node_modules/@nx/devkit/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/@nx/devkit/node_modules/minimatch": { @@ -2446,9 +2218,9 @@ } }, "node_modules/@nx/nx-darwin-arm64": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.8.4.tgz", - "integrity": "sha512-mbSGt63hYcVCSQ54kpHl0lFqr5CsbkGJ4L3liWE30Da7vXZJwUBr9f+b9DnQ64IZzlu6vAhNcaiYQXa9lAk0yQ==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.8.6.tgz", + "integrity": "sha512-lzFV07gUgvy07lPtRFJFhlQdcR0qNTPPq7/ZB+3alwUIDdAn706ZVzf6apCJWOBIgNFKbAQiy/du0zmuKPSzXA==", "cpu": [ "arm64" ], @@ -2463,9 +2235,9 @@ } }, "node_modules/@nx/nx-darwin-x64": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.8.4.tgz", - "integrity": "sha512-lTcXUCXNvqHdLmrNCOyDF+u6pDx209Ew7nSR47sQPvkycIHYi0gvgk0yndFn1Swah0lP4OxWg7rzAfmOlZd6ew==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.8.6.tgz", + "integrity": "sha512-1ZmOXwJva14jCcTHM8jmsEBp33CCLng/tXK8/554ACwL3Kk4kbtdLfUjM/VEMZ3v3c1D7cJWxyYfTav5meumxg==", "cpu": [ "x64" ], @@ -2480,9 +2252,9 @@ } }, "node_modules/@nx/nx-freebsd-x64": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.8.4.tgz", - "integrity": "sha512-4BUplOxPZeUwlUNfzHHMmebNVgDFW/jNX6TWRS+jINwOHnpWLkLFAXu27G80/S3OaniVCzEQklXO9b+1UsdgXw==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.8.6.tgz", + "integrity": "sha512-1a681ZqSS05H1pC6JG3ae0BLhnxGtISkCigl9R6W5NeyFLBgP+Y4BLh+H9cCAlKzzLwiKWWRmhbxvjpnlhzB+w==", "cpu": [ "x64" ], @@ -2497,9 +2269,9 @@ } }, "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.8.4.tgz", - "integrity": "sha512-Wahul8oz9huEm/Jv3wud5IGWdZxkGG4tdJm9i5TV5wxfUMAWbKU9v2nzZZins452UYESWvwvDkiuBPZqSto3qw==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.8.6.tgz", + "integrity": "sha512-qGztEgbEjMsFr9IjedQXJNmXLHCpSldW/sEtXoVZ8tXIzGr86GXbv+mLdZSZHrlJaNOq0y2K6XpVd2UH4ndwnQ==", "cpu": [ "arm" ], @@ -2514,9 +2286,9 @@ } }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.8.4.tgz", - "integrity": "sha512-L0RVCZkNAtZDplLT7uJV7M9cXxq2Fxw+8ex3eb9XSp7eyLeFO21T0R6vTouJ42E/PEvGApCAcyGqtnyPNMZFfw==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.8.6.tgz", + "integrity": "sha512-rSwsEISx5odXkg1kjXBZ6kjXCnM3fnAA+8YU1muRr7PmhUfM/zuCnNYcwmjtCRc7rRYBKzxmyE3T95fGK/NOIg==", "cpu": [ "arm64" ], @@ -2531,9 +2303,9 @@ } }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.8.4.tgz", - "integrity": "sha512-0q8r8I8WCsY3xowDI2j109SCUSkFns/BJ40aCfRh9hhrtaIIc5qXUw2YFTjxUZNcRJXx9j9+hTe9jBkUSIGvCw==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.8.6.tgz", + "integrity": "sha512-7rW21+uFj5KJx3z/HXhl6PUcp8+mQ8r/nUGbS59HjmMdVMZDd7PZKUVJF9Tu1ESproOCYSeJbOVk4WGiHtbF9Q==", "cpu": [ "arm64" ], @@ -2548,9 +2320,9 @@ } }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.8.4.tgz", - "integrity": "sha512-XcRBNe0ws7KB0PMcUlpQqzzjjxMP8VdqirBz7CfB2XQ8xKmP3370p0cDvqs/4oKDHK4PCkmvVFX60tzakutylA==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.8.6.tgz", + "integrity": "sha512-2/5WDr2wwWyvbqlB//ICWS5q3rRF4GyNX2NOp/tVkmh1RfDhH0ZAVZ/oJ7QvE1mKLQh0AM7bQBHsF5ikmMhUXw==", "cpu": [ "x64" ], @@ -2565,9 +2337,9 @@ } }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.8.4.tgz", - "integrity": "sha512-JB4tAuZBCF0yqSnKF3pHXa0b7LA3ebi3Bw08QmMr//ON4aU+eXURGBuj9XvULD2prY+gpBrvf+MsG1XJAHL6Zg==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.8.6.tgz", + "integrity": "sha512-G3UIMk+C090WR/btOaJCrBgRa7gjTj6ZBHinFceO7rii8r3D1SiN5cW1Njd1pV2K7IjJaSTuRtd9c1eLcIj9rQ==", "cpu": [ "x64" ], @@ -2582,9 +2354,9 @@ } }, "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.8.4.tgz", - "integrity": "sha512-WvQag/pN9ofRWRDvOZxj3jvJoTetlvV1uyirnDrhupRgi+Fj67OlGGt2zVUHaXFGEa1MfCEG6Vhk6152m4KyaQ==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.8.6.tgz", + "integrity": "sha512-8dfUstJkN2ChbIcj3TfcHgWyJy0b9za+3gU9IvZm82P9EeDCjEGoE/ld9VALGa+2UnX2Ve5BqlWGTD8BqYTeCA==", "cpu": [ "arm64" ], @@ -2599,9 +2371,9 @@ } }, "node_modules/@nx/nx-win32-x64-msvc": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.8.4.tgz", - "integrity": "sha512-//JntLrN3L7WL/WgP3D0FE34caYTPcG/GIMBguC9w7YDyTlEikLgLbobjdCPz+2f9OWGvIZbJgGmtHNjnETM/g==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.8.6.tgz", + "integrity": "sha512-kbWDZGD9kwP60UykTnfMR1hOUMDK0evXb5EnF4MAf4o18+b5KSzHyaL2TyNl+3s6lYdtZ2kYC679R+eJErKG8w==", "cpu": [ "x64" ], @@ -3246,6 +3018,32 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@tufjs/models/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", @@ -3396,9 +3194,9 @@ } }, "node_modules/@types/lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==", + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.12.tgz", + "integrity": "sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==", "dev": true, "license": "MIT" }, @@ -3424,9 +3222,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.16.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.11.tgz", - "integrity": "sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==", + "version": "20.16.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.13.tgz", + "integrity": "sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==", "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -3494,9 +3292,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3705,6 +3503,32 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/utils": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", @@ -3746,6 +3570,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -3754,9 +3591,9 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-react": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz", - "integrity": "sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz", + "integrity": "sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==", "dev": true, "license": "MIT", "dependencies": { @@ -3861,10 +3698,19 @@ "node": ">= 0.6" } }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3972,19 +3818,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -4336,6 +4169,45 @@ "follow-redirects": "^1.14.8" } }, + "node_modules/binary-install/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/binary-install/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -4388,12 +4260,14 @@ "license": "MIT" }, "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==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -4517,6 +4391,13 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/cacache/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, + "license": "ISC" + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -4575,9 +4456,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001667", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", - "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", "dev": true, "funding": [ { @@ -4611,18 +4492,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -4669,13 +4538,12 @@ } }, "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "license": "ISC", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/ci-info": { @@ -4972,6 +4840,22 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -5078,6 +4962,13 @@ "node": ">=10" } }, + "node_modules/conventional-changelog-core/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/conventional-changelog-preset-loader": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-3.0.0.tgz", @@ -5643,9 +5534,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.35", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz", - "integrity": "sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A==", + "version": "1.5.41", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", + "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", "dev": true, "license": "ISC" }, @@ -6160,17 +6051,6 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -6194,19 +6074,6 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -6262,9 +6129,9 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz", - "integrity": "sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg==", + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.13.tgz", + "integrity": "sha512-f1EppwrpJRWmqDTyvAyomFVDYRtrS7iTEqv3nokETnMiMzs2SSTmKRTACce4O2p4jYyowiSMvpdwC/RLcMFhuQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -6272,72 +6139,226 @@ } }, "node_modules/eslint-scope": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/eslint/node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/eslint/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "*" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/eslint/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": "*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -6648,16 +6669,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/filelist": { @@ -6670,6 +6691,16 @@ "minimatch": "^5.0.1" } }, + "node_modules/filelist/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/filelist/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -6757,18 +6788,17 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -7129,6 +7159,13 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/get-pkg-repo/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/get-pkg-repo/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -7338,17 +7375,38 @@ "node": ">=10.13.0" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, + "node_modules/glob/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==", "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "15.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", + "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7552,6 +7610,13 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/hosted-git-info/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, + "license": "ISC" + }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -7669,6 +7734,32 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/ignore-walk/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -8377,30 +8468,6 @@ "node": ">=10" } }, - "node_modules/jake/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/jest-diff": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", @@ -8546,16 +8613,16 @@ "license": "ISC" }, "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsonc-parser": { @@ -8733,96 +8800,40 @@ "wide-align": "1.1.5", "write-file-atomic": "5.0.1", "write-pkg": "4.0.0", - "yargs": "17.7.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "lerna": "dist/cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/lerna/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/lerna/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/lerna/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, - "license": "MIT" - }, - "node_modules/lerna/node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" + "yargs": "17.7.2", + "yargs-parser": "21.1.1" }, - "engines": { - "node": ">=16 || 14 >=14.17" + "bin": { + "lerna": "dist/cli.js" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/lerna/node_modules/glob/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==", + "node_modules/lerna/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/lerna/node_modules/glob/node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/lerna/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, + "license": "MIT" + }, "node_modules/lerna/node_modules/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", @@ -8836,16 +8847,6 @@ "node": "*" } }, - "node_modules/lerna/node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, "node_modules/lerna/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -8856,25 +8857,6 @@ "node": ">=8" } }, - "node_modules/lerna/node_modules/rimraf": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", - "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^9.2.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/lerna/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -8897,19 +8879,6 @@ "node": ">=8" } }, - "node_modules/lerna/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -9081,15 +9050,26 @@ } }, "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==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lru-cache/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "version": "0.30.12", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", "dev": true, "license": "MIT", "dependencies": { @@ -9385,6 +9365,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/meow/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/meow/node_modules/yargs-parser": { "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", @@ -9498,18 +9485,16 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/minimist": { @@ -9577,6 +9562,40 @@ "encoding": "^0.1.13" } }, + "node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -9603,6 +9622,13 @@ "node": ">=8" } }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -9629,6 +9655,13 @@ "node": ">=8" } }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", @@ -9655,44 +9688,54 @@ "node": ">=8" } }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, + "license": "ISC" + }, + "node_modules/minizlib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz", + "integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==", "license": "MIT", "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "minipass": "^7.0.4", + "rimraf": "^5.0.5" }, "engines": { - "node": ">= 8" + "node": ">= 18" } }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, + "node_modules/minizlib/node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "license": "ISC", "dependencies": { - "yallist": "^4.0.0" + "glob": "^10.3.7" }, - "engines": { - "node": ">=8" + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "license": "MIT", "bin": { - "mkdirp": "bin/cmd.js" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/modify-values": { @@ -9747,30 +9790,6 @@ "node": ">=8" } }, - "node_modules/multimatch/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/multimatch/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -9805,9 +9824,10 @@ "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -10028,29 +10048,63 @@ "semver": "^7.3.5" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz", + "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^2.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/npm-registry-fetch": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz", - "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==", + "node_modules/npm-registry-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "license": "ISC", "dependencies": { - "@npmcli/redact": "^2.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^13.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minizlib": "^2.1.2", - "npm-package-arg": "^11.0.0", - "proc-log": "^4.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=8" } }, + "node_modules/npm-registry-fetch/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -10065,15 +10119,15 @@ } }, "node_modules/nx": { - "version": "19.8.4", - "resolved": "https://registry.npmjs.org/nx/-/nx-19.8.4.tgz", - "integrity": "sha512-fc833c3UKo6kuoG4z0kSKet17yWym3VzcQ+yPWYspxxxd8GFVVk42+9wieyVQDi9YqtKZQ6PdQfSEPm59/M7SA==", + "version": "19.8.6", + "resolved": "https://registry.npmjs.org/nx/-/nx-19.8.6.tgz", + "integrity": "sha512-VkEbXoCil4UnSDOJP5OcIKZgI13hKsFlQNf6oKhUHCYWoEHvVqpvabMv/ZY9mGG78skvqAorzn85BS3evlt0Cw==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@napi-rs/wasm-runtime": "0.2.4", - "@nrwl/tao": "19.8.4", + "@nrwl/tao": "19.8.6", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "3.0.0-rc.46", "@zkochan/js-yaml": "0.0.7", @@ -10112,16 +10166,16 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.8.4", - "@nx/nx-darwin-x64": "19.8.4", - "@nx/nx-freebsd-x64": "19.8.4", - "@nx/nx-linux-arm-gnueabihf": "19.8.4", - "@nx/nx-linux-arm64-gnu": "19.8.4", - "@nx/nx-linux-arm64-musl": "19.8.4", - "@nx/nx-linux-x64-gnu": "19.8.4", - "@nx/nx-linux-x64-musl": "19.8.4", - "@nx/nx-win32-arm64-msvc": "19.8.4", - "@nx/nx-win32-x64-msvc": "19.8.4" + "@nx/nx-darwin-arm64": "19.8.6", + "@nx/nx-darwin-x64": "19.8.6", + "@nx/nx-freebsd-x64": "19.8.6", + "@nx/nx-linux-arm-gnueabihf": "19.8.6", + "@nx/nx-linux-arm64-gnu": "19.8.6", + "@nx/nx-linux-arm64-musl": "19.8.6", + "@nx/nx-linux-x64-gnu": "19.8.6", + "@nx/nx-linux-x64-musl": "19.8.6", + "@nx/nx-win32-arm64-msvc": "19.8.6", + "@nx/nx-win32-x64-msvc": "19.8.6" }, "peerDependencies": { "@swc-node/register": "^1.8.0", @@ -10136,6 +10190,16 @@ } } }, + "node_modules/nx/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/nx/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -10143,19 +10207,6 @@ "dev": true, "license": "MIT" }, - "node_modules/nx/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/nx/node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", @@ -10747,6 +10798,22 @@ "dev": true, "license": "MIT" }, + "node_modules/path-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/path-parser/-/path-parser-6.1.0.tgz", + "integrity": "sha512-nAB6J73z2rFcQP+870OHhpkHFj5kO4rPLc2Ol4Y3Ale7F6Hk1/cPKp7cQ8RznKF8FOSvu+YR9Xc6Gafk7DlpYA==", + "license": "MIT", + "dependencies": { + "search-params": "3.0.0", + "tslib": "^1.10.0" + } + }, + "node_modules/path-parser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -10763,6 +10830,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/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==", + "license": "ISC" + }, "node_modules/path-to-regexp": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", @@ -10780,9 +10853,9 @@ } }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, @@ -11677,66 +11750,77 @@ } }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", "dev": true, "license": "ISC", "dependencies": { - "glob": "^7.1.3" + "glob": "^9.2.0" }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" } }, "node_modules/rollup": { @@ -12007,6 +12091,12 @@ "loose-envify": "^1.1.0" } }, + "node_modules/search-params": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/search-params/-/search-params-3.0.0.tgz", + "integrity": "sha512-8CYNl/bjkEhXWbDTU/K7c2jQtrnqEffIPyOLMqygW/7/b+ym8UtQumcAZjOfMLjZKR6AxK5tOr9fChbQZCzPqg==", + "license": "MIT" + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -12616,19 +12706,15 @@ } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=8" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -12706,6 +12792,16 @@ "node": ">=6" } }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -12742,6 +12838,53 @@ "node": ">=8" } }, + "node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", @@ -12982,6 +13125,19 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/tsconfig-paths/node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -12993,9 +13149,9 @@ } }, "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", "dev": true, "license": "0BSD" }, @@ -13028,9 +13184,9 @@ } }, "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -13151,15 +13307,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.1.tgz", - "integrity": "sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.10.0.tgz", + "integrity": "sha512-YIu230PeN7z9zpu/EtqCIuRVHPs4iSlqW6TEvjbyDAE3MZsSl2RXBo+5ag+lbABCG8sFM1WVKEXhlQ8Ml8A3Fw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.8.1", - "@typescript-eslint/parser": "8.8.1", - "@typescript-eslint/utils": "8.8.1" + "@typescript-eslint/eslint-plugin": "8.10.0", + "@typescript-eslint/parser": "8.10.0", + "@typescript-eslint/utils": "8.10.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -13175,17 +13331,17 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", - "integrity": "sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.10.0.tgz", + "integrity": "sha512-phuB3hoP7FFKbRXxjl+DRlQDuJqhpOnm5MmtROXyWi3uS/Xg2ZXqiQfcG2BJHiN4QKyzdOJi3NEn/qTnjUlkmQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/type-utils": "8.8.1", - "@typescript-eslint/utils": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", + "@typescript-eslint/scope-manager": "8.10.0", + "@typescript-eslint/type-utils": "8.10.0", + "@typescript-eslint/utils": "8.10.0", + "@typescript-eslint/visitor-keys": "8.10.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -13209,16 +13365,16 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.1.tgz", - "integrity": "sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.10.0.tgz", + "integrity": "sha512-E24l90SxuJhytWJ0pTQydFT46Nk0Z+bsLKo/L8rtQSL93rQ6byd1V/QbDpHUTdLPOMsBCcYXZweADNCfOCmOAg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/typescript-estree": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", + "@typescript-eslint/scope-manager": "8.10.0", + "@typescript-eslint/types": "8.10.0", + "@typescript-eslint/typescript-estree": "8.10.0", + "@typescript-eslint/visitor-keys": "8.10.0", "debug": "^4.3.4" }, "engines": { @@ -13238,14 +13394,14 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz", - "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.10.0.tgz", + "integrity": "sha512-AgCaEjhfql9MDKjMUxWvH7HjLeBqMCBfIaBbzzIcBbQPZE7CPh1m6FF+L75NUMJFMLYhCywJXIDEMa3//1A0dw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1" + "@typescript-eslint/types": "8.10.0", + "@typescript-eslint/visitor-keys": "8.10.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -13256,14 +13412,14 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz", - "integrity": "sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.10.0.tgz", + "integrity": "sha512-PCpUOpyQSpxBn230yIcK+LeCQaXuxrgCm2Zk1S+PTIRJsEfU6nJ0TtwyH8pIwPK/vJoA+7TZtzyAJSGBz+s/dg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.8.1", - "@typescript-eslint/utils": "8.8.1", + "@typescript-eslint/typescript-estree": "8.10.0", + "@typescript-eslint/utils": "8.10.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -13281,9 +13437,9 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz", - "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.10.0.tgz", + "integrity": "sha512-k/E48uzsfJCRRbGLapdZgrX52csmWJ2rcowwPvOZ8lwPUv3xW6CcFeJAXgx4uJm+Ge4+a4tFOkdYvSpxhRhg1w==", "dev": true, "license": "MIT", "engines": { @@ -13295,14 +13451,14 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz", - "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.10.0.tgz", + "integrity": "sha512-3OE0nlcOHaMvQ8Xu5gAfME3/tWVDpb/HxtpUZ1WeOAksZ/h/gwrBzCklaGzwZT97/lBbbxJ16dMA98JMEngW4w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", + "@typescript-eslint/types": "8.10.0", + "@typescript-eslint/visitor-keys": "8.10.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -13324,16 +13480,16 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz", - "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.10.0.tgz", + "integrity": "sha512-Oq4uZ7JFr9d1ZunE/QKy5egcDRXT/FrS2z/nlxzPua2VHFtmMvFNDvpq1m/hq0ra+T52aUezfcjGRIB7vNJF9w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/typescript-estree": "8.8.1" + "@typescript-eslint/scope-manager": "8.10.0", + "@typescript-eslint/types": "8.10.0", + "@typescript-eslint/typescript-estree": "8.10.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -13347,13 +13503,13 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz", - "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.10.0.tgz", + "integrity": "sha512-k8nekgqwr7FadWk548Lfph6V3r9OVqjzAIVskE7orMZR23cGJjAOVazsZSJW+ElyjfTM4wx/1g88Mi70DDtG9A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/types": "8.10.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -13364,6 +13520,45 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/typescript-eslint/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/typescript-eslint/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", @@ -13578,9 +13773,9 @@ } }, "node_modules/vite": { - "version": "5.4.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", - "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", + "version": "5.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz", + "integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==", "dev": true, "license": "MIT", "dependencies": { @@ -14057,11 +14252,13 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } }, "node_modules/yargs": { "version": "17.7.2", diff --git a/ts/package.json b/ts/package.json index 58950a5ea..013a641d1 100644 --- a/ts/package.json +++ b/ts/package.json @@ -6,7 +6,7 @@ "lint": "lerna run lint", "lint:fix": "lerna run lint -- --fix", "build": "lerna run build --concurrency=1", - "build:sdk": "lerna run build --concurrency 1 --scope @live-compositor/core --scope @live-compositor/node --scope live-compositor", + "build:sdk": "lerna run build --concurrency 1 --scope @live-compositor/core --scope @live-compositor/node --scope @live-compositor/web --scope live-compositor", "build:all": "npm run -w @live-compositor/browser-render build-wasm && npm run build", "typecheck": "lerna run typecheck", "clean": "lerna run clean", @@ -17,6 +17,7 @@ "live-compositor", "@live-compositor/core", "@live-compositor/node", + "@live-compositor/web-wasm", "@live-compositor/browser-render", "examples/node-examples", "examples/vite-browser-render", From 4d9f1b297d8bd83ec177f0ca1306863ece74685e Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Mon, 28 Oct 2024 10:12:43 +0100 Subject: [PATCH 10/51] Switch to SRGB textures + add padding to outptu texture (#839) --- .../transformations/layout/apply_layouts.wgsl | 2 +- .../src/transformations/layout/params.rs | 22 ++++++++++++------- .../src/transformations/text_renderer.rs | 2 +- compositor_render/src/wgpu/common_pipeline.rs | 2 +- .../wgpu/format/interleaved_yuv_to_rgba.rs | 2 +- .../src/wgpu/format/nv12_to_rgba.rs | 2 +- .../src/wgpu/format/planar_yuv_to_rgba.rs | 2 +- .../src/wgpu/format/planar_yuv_to_rgba.wgsl | 11 +++++++++- .../src/wgpu/format/rgba_to_yuv.wgsl | 21 +++++++++++++----- compositor_render/src/wgpu/texture/base.rs | 2 +- compositor_render/src/wgpu/texture/bgra.rs | 2 +- .../src/wgpu/texture/interleaved_yuv422.rs | 2 +- compositor_render/src/wgpu/texture/rgba.rs | 2 +- compositor_web/Cargo.toml | 3 +++ compositor_web/src/wasm/input_uploader.rs | 4 ++-- .../examples/raw_channel_input.rs | 4 ++-- snapshot_tests/snapshots | 2 +- 17 files changed, 57 insertions(+), 30 deletions(-) diff --git a/compositor_render/src/transformations/layout/apply_layouts.wgsl b/compositor_render/src/transformations/layout/apply_layouts.wgsl index c24e8a772..deeb135b8 100644 --- a/compositor_render/src/transformations/layout/apply_layouts.wgsl +++ b/compositor_render/src/transformations/layout/apply_layouts.wgsl @@ -76,7 +76,7 @@ struct LayoutInfo { @group(0) @binding(0) var texture: texture_2d; -@group(1) @binding(0) var output_resolution: vec2; +@group(1) @binding(0) var output_resolution: vec4; @group(1) @binding(1) var texture_params: array; @group(1) @binding(2) var color_params: array; @group(1) @binding(3) var box_shadow_params: array; diff --git a/compositor_render/src/transformations/layout/params.rs b/compositor_render/src/transformations/layout/params.rs index f9eafbdeb..1acad221a 100644 --- a/compositor_render/src/transformations/layout/params.rs +++ b/compositor_render/src/transformations/layout/params.rs @@ -45,7 +45,7 @@ pub struct ParamsBindGroups { impl ParamsBindGroups { pub fn new(ctx: &WgpuCtx) -> ParamsBindGroups { - let output_resolution_buffer = create_buffer(ctx, 8); + let output_resolution_buffer = create_buffer(ctx, 16); let texture_params_buffer = create_buffer(ctx, TEXTURE_PARAMS_BUFFER_SIZE); let color_params_buffer = create_buffer(ctx, COLOR_PARAMS_SIZE); let box_shadow_params_buffer = create_buffer(ctx, BOX_SHADOW_PARAMS_SIZE); @@ -358,14 +358,20 @@ fn borders_radius_to_bytes(border_radius: BorderRadius) -> [u8; 16] { fn color_to_bytes(color: RGBAColor) -> [u8; 16] { let RGBAColor(r, g, b, a) = color; - fn color_from_u8(color: u8) -> [u8; 4] { - (color as f32 / 255.0).to_le_bytes() - } let mut result = [0u8; 16]; - result[0..4].copy_from_slice(&color_from_u8(r)); - result[4..8].copy_from_slice(&color_from_u8(g)); - result[8..12].copy_from_slice(&color_from_u8(b)); - result[12..16].copy_from_slice(&color_from_u8(a)); + result[0..4].copy_from_slice(&srgb_to_linear(r).to_le_bytes()); + result[4..8].copy_from_slice(&srgb_to_linear(g).to_le_bytes()); + result[8..12].copy_from_slice(&srgb_to_linear(b).to_le_bytes()); + result[12..16].copy_from_slice(&(a as f32 / 255.0).to_le_bytes()); result } + +fn srgb_to_linear(color: u8) -> f32 { + let color = color as f32 / 255.0; + if color < 0.04045 { + color / 12.92 + } else { + f32::powf((color + 0.055) / 1.055, 2.4) + } +} diff --git a/compositor_render/src/transformations/text_renderer.rs b/compositor_render/src/transformations/text_renderer.rs index e4f9353a2..45520edcc 100644 --- a/compositor_render/src/transformations/text_renderer.rs +++ b/compositor_render/src/transformations/text_renderer.rs @@ -82,7 +82,7 @@ impl TextRendererNode { let mut viewport = glyphon::Viewport::new(&renderer_ctx.wgpu_ctx.device, cache); viewport.update(&renderer_ctx.wgpu_ctx.queue, self.resolution.into()); - let swapchain_format = TextureFormat::Rgba8Unorm; + let swapchain_format = TextureFormat::Rgba8UnormSrgb; let mut atlas = TextAtlas::new( &renderer_ctx.wgpu_ctx.device, &renderer_ctx.wgpu_ctx.queue, diff --git a/compositor_render/src/wgpu/common_pipeline.rs b/compositor_render/src/wgpu/common_pipeline.rs index bf373deeb..5c22de2cd 100644 --- a/compositor_render/src/wgpu/common_pipeline.rs +++ b/compositor_render/src/wgpu/common_pipeline.rs @@ -118,7 +118,7 @@ pub fn create_render_pipeline( module: shader_module, entry_point: crate::wgpu::common_pipeline::FRAGMENT_ENTRYPOINT_NAME, targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, + format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), blend: Some(wgpu::BlendState::ALPHA_BLENDING), })], diff --git a/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs b/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs index 821ad2fa7..5b7e9b909 100644 --- a/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs +++ b/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs @@ -42,7 +42,7 @@ impl InterleavedYuv422ToRgbaConverter { module: &shader_module, entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, + format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), blend: None, })], diff --git a/compositor_render/src/wgpu/format/nv12_to_rgba.rs b/compositor_render/src/wgpu/format/nv12_to_rgba.rs index ea8686c7b..dddcb5091 100644 --- a/compositor_render/src/wgpu/format/nv12_to_rgba.rs +++ b/compositor_render/src/wgpu/format/nv12_to_rgba.rs @@ -41,7 +41,7 @@ impl Nv12ToRgbaConverter { module: &shader_module, entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, + format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), blend: None, })], diff --git a/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs b/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs index 6eb070f2d..79fed53a8 100644 --- a/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs +++ b/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs @@ -47,7 +47,7 @@ impl PlanarYuvToRgbaConverter { module: &shader_module, entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, + format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), blend: None, })], diff --git a/compositor_render/src/wgpu/format/planar_yuv_to_rgba.wgsl b/compositor_render/src/wgpu/format/planar_yuv_to_rgba.wgsl index 3b774312b..588f02cd1 100644 --- a/compositor_render/src/wgpu/format/planar_yuv_to_rgba.wgsl +++ b/compositor_render/src/wgpu/format/planar_yuv_to_rgba.wgsl @@ -32,6 +32,14 @@ struct PushConstantParams { var params: PushConstantParams; +fn srgb_to_linear(srgb: vec3) -> vec3 { + let cutoff = step(srgb, vec3(0.04045)); + let higher = pow((srgb + vec3(0.055))/vec3(1.055), vec3(2.4)); + let lower = srgb/vec3(12.92); + + return mix(higher, lower, cutoff); +} + @fragment fn fs_main(input: VertexOutput) -> @location(0) vec4 { var y = textureSample(y_texture, sampler_, input.tex_coords).x; @@ -50,5 +58,6 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { let g = y - 0.34414 * (u - 128.0 / 255.0) - 0.71414 * (v - 128.0 / 255.0); let b = y + 1.77200 * (u - 128.0 / 255.0); - return vec4(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0), 1.0); + let srgb = vec3(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0)); + return vec4(srgb_to_linear(srgb), 1.0); } diff --git a/compositor_render/src/wgpu/format/rgba_to_yuv.wgsl b/compositor_render/src/wgpu/format/rgba_to_yuv.wgsl index 126eb1987..7fe4ff104 100644 --- a/compositor_render/src/wgpu/format/rgba_to_yuv.wgsl +++ b/compositor_render/src/wgpu/format/rgba_to_yuv.wgsl @@ -23,26 +23,35 @@ fn vs_main(input: VertexInput) -> VertexOutput { var plane_selector: u32; +fn linear_to_srgb(linear: vec3) -> vec3 { + let cutoff = step(linear, vec3(0.0031308)); + let higher = vec3(1.055)*pow(linear, vec3(1.0/2.4)) - vec3(0.055); + let lower = linear * vec3(12.92); + + return mix(higher, lower, cutoff); +} + @fragment fn fs_main(input: VertexOutput) -> @location(0) f32 { - let color = textureSample(texture, sampler_, input.tex_coords); - var conversion_weights: vec4; + let linear = textureSample(texture, sampler_, input.tex_coords); + let color = linear_to_srgb(linear.rgb); + var conversion_weights: vec3; var conversion_bias: f32; if(plane_selector == 0u) { // Y - conversion_weights = vec4(0.299, 0.587, 0.114, 0.0); + conversion_weights = vec3(0.299, 0.587, 0.114); conversion_bias = 0.0; } else if(plane_selector == 1u) { // U - conversion_weights = vec4(-0.168736, -0.331264, 0.5, 0.0); + conversion_weights = vec3(-0.168736, -0.331264, 0.5); conversion_bias = 128.0 / 255.0; } else if(plane_selector == 2u) { // V - conversion_weights = vec4(0.5, -0.418688, -0.081312, 0.0); + conversion_weights = vec3(0.5, -0.418688, -0.081312); conversion_bias = 128.0 / 255.0; } else { - conversion_weights = vec4(); + conversion_weights = vec3(); } return clamp(dot(color, conversion_weights) + conversion_bias, 0.0, 1.0); diff --git a/compositor_render/src/wgpu/texture/base.rs b/compositor_render/src/wgpu/texture/base.rs index 8cb6e415b..edd9f3f2e 100644 --- a/compositor_render/src/wgpu/texture/base.rs +++ b/compositor_render/src/wgpu/texture/base.rs @@ -94,7 +94,7 @@ impl Texture { height: 1, depth_or_array_layers: 1, }, - wgpu::TextureFormat::Rgba8Unorm, + wgpu::TextureFormat::Rgba8UnormSrgb, wgpu::TextureUsages::TEXTURE_BINDING, ) } diff --git a/compositor_render/src/wgpu/texture/bgra.rs b/compositor_render/src/wgpu/texture/bgra.rs index 00ed62648..99c444375 100644 --- a/compositor_render/src/wgpu/texture/bgra.rs +++ b/compositor_render/src/wgpu/texture/bgra.rs @@ -15,7 +15,7 @@ impl BGRATexture { height: resolution.height as u32, depth_or_array_layers: 1, }, - wgpu::TextureFormat::Rgba8Unorm, + wgpu::TextureFormat::Rgba8UnormSrgb, wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING, )) } diff --git a/compositor_render/src/wgpu/texture/interleaved_yuv422.rs b/compositor_render/src/wgpu/texture/interleaved_yuv422.rs index f9631aa2e..f6956222d 100644 --- a/compositor_render/src/wgpu/texture/interleaved_yuv422.rs +++ b/compositor_render/src/wgpu/texture/interleaved_yuv422.rs @@ -27,7 +27,7 @@ impl InterleavedYuv422Texture { // g - y1 // b - v // a - y2 - wgpu::TextureFormat::Rgba8Unorm, + wgpu::TextureFormat::Rgba8UnormSrgb, wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC diff --git a/compositor_render/src/wgpu/texture/rgba.rs b/compositor_render/src/wgpu/texture/rgba.rs index 26b399d22..e7c146253 100644 --- a/compositor_render/src/wgpu/texture/rgba.rs +++ b/compositor_render/src/wgpu/texture/rgba.rs @@ -18,7 +18,7 @@ impl RGBATexture { height: resolution.height as u32, depth_or_array_layers: 1, }, - wgpu::TextureFormat::Rgba8Unorm, + wgpu::TextureFormat::Rgba8UnormSrgb, wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC diff --git a/compositor_web/Cargo.toml b/compositor_web/Cargo.toml index 9c39d284e..1ae49f2f9 100644 --- a/compositor_web/Cargo.toml +++ b/compositor_web/Cargo.toml @@ -36,3 +36,6 @@ glyphon = { workspace = true } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2", features = ["js"] } + +[package.metadata.wasm-pack.profile.release] +wasm-opt = true diff --git a/compositor_web/src/wasm/input_uploader.rs b/compositor_web/src/wasm/input_uploader.rs index dec959680..66aa5df6a 100644 --- a/compositor_web/src/wasm/input_uploader.rs +++ b/compositor_web/src/wasm/input_uploader.rs @@ -97,8 +97,8 @@ impl InputUploader { mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8Unorm, - view_formats: &[wgpu::TextureFormat::Rgba8Unorm], + format: wgpu::TextureFormat::Rgba8UnormSrgb, + view_formats: &[wgpu::TextureFormat::Rgba8UnormSrgb], usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC diff --git a/integration_tests/examples/raw_channel_input.rs b/integration_tests/examples/raw_channel_input.rs index 2fec88abd..2be806adf 100644 --- a/integration_tests/examples/raw_channel_input.rs +++ b/integration_tests/examples/raw_channel_input.rs @@ -204,12 +204,12 @@ fn create_texture(index: usize, device: &wgpu::Device, queue: &wgpu::Queue) -> A mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8Unorm, + format: wgpu::TextureFormat::Rgba8UnormSrgb, usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::TEXTURE_BINDING, - view_formats: &[wgpu::TextureFormat::Rgba8Unorm], + view_formats: &[wgpu::TextureFormat::Rgba8UnormSrgb], }); queue.write_texture( diff --git a/snapshot_tests/snapshots b/snapshot_tests/snapshots index ac634ad38..f00123f1a 160000 --- a/snapshot_tests/snapshots +++ b/snapshot_tests/snapshots @@ -1 +1 @@ -Subproject commit ac634ad382cc6e6417167db3c768fe750e9b0240 +Subproject commit f00123f1a4b6c6e643beb22e7836bf605f2e6c93 From e0c12a51d48a3fa60d527588d1e62e843f224852 Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Tue, 29 Oct 2024 12:12:34 +0100 Subject: [PATCH 11/51] [docs] Disable auto-deploy (#841) --- .github/workflows/deploy_docs.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index 8956a12d3..487bad26a 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -2,13 +2,6 @@ name: deploy to gh-pages on: workflow_dispatch: {} - push: - branches: [master] - paths: - - "docs/**" - - "schemas/**" - - "generate/src/bin/generate_from_types/**" - - ".github/workflows/deploy_docs.yml" permissions: contents: write From 3412ce729964015753afda0912798ab226e09c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Radkowski?= Date: Tue, 29 Oct 2024 12:31:48 +0100 Subject: [PATCH 12/51] [tests] Change expected bitrate in offline processing test (#835) --- integration_tests/src/tests/offline_processing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_tests/src/tests/offline_processing.rs b/integration_tests/src/tests/offline_processing.rs index 1b96bd824..fd964b694 100644 --- a/integration_tests/src/tests/offline_processing.rs +++ b/integration_tests/src/tests/offline_processing.rs @@ -123,7 +123,7 @@ pub fn offline_processing() -> Result<()> { if !(1.9..=2.1).contains(&duration) { return Err(anyhow!("Invalid duration: {}", duration)); } - if !(930_000..=1_008_200).contains(&bit_rate) { + if !(1_000_000..=1_015_000).contains(&bit_rate) { return Err(anyhow!("Invalid bit rate: {}", bit_rate)); } From 1fd3d93814f3765f711f0d2038b80f974c63a613 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Tue, 29 Oct 2024 17:07:22 +0100 Subject: [PATCH 13/51] review fixes --- compositor_pipeline/src/pipeline/encoder.rs | 6 +- .../src/pipeline/encoder/ffmpeg_h264.rs | 2 +- compositor_pipeline/src/pipeline/output.rs | 2 +- .../src/pipeline/output/whip.rs | 159 +++++++++--------- .../output/whip/establish_peer_connection.rs | 101 ++++++----- 5 files changed, 142 insertions(+), 128 deletions(-) diff --git a/compositor_pipeline/src/pipeline/encoder.rs b/compositor_pipeline/src/pipeline/encoder.rs index 35cc64ece..1e6f8eca0 100644 --- a/compositor_pipeline/src/pipeline/encoder.rs +++ b/compositor_pipeline/src/pipeline/encoder.rs @@ -100,9 +100,9 @@ impl Encoder { } } - pub fn request_keyframe(&self) -> Option> { + pub fn keyframe_request_sender(&self) -> Option> { match self.video.as_ref() { - Some(VideoEncoder::H264(encoder)) => Some(encoder.request_keyframe().clone()), + Some(VideoEncoder::H264(encoder)) => Some(encoder.keyframe_request_sender().clone()), None => { error!("Non video encoder received keyframe request."); None @@ -150,7 +150,7 @@ impl VideoEncoder { pub fn request_keyframe(&self) -> Sender<()> { match self { - Self::H264(encoder) => encoder.request_keyframe(), + Self::H264(encoder) => encoder.keyframe_request_sender(), } } } diff --git a/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs b/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs index e2266224a..c7bb467ce 100644 --- a/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs +++ b/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs @@ -148,7 +148,7 @@ impl LibavH264Encoder { self.resolution } - pub fn request_keyframe(&self) -> crossbeam_channel::Sender<()> { + pub fn keyframe_request_sender(&self) -> crossbeam_channel::Sender<()> { self.keyframe_req_sender.clone() } } diff --git a/compositor_pipeline/src/pipeline/output.rs b/compositor_pipeline/src/pipeline/output.rs index 6b07e881a..f5c84b02d 100644 --- a/compositor_pipeline/src/pipeline/output.rs +++ b/compositor_pipeline/src/pipeline/output.rs @@ -126,7 +126,7 @@ impl OutputOptionsExt> for OutputOptions { output_id, whip_options.clone(), packets, - encoder.request_keyframe(), + encoder.keyframe_request_sender(), ctx, ) .map_err(|e| RegisterOutputError::OutputError(output_id.clone(), e))?; diff --git a/compositor_pipeline/src/pipeline/output/whip.rs b/compositor_pipeline/src/pipeline/output/whip.rs index 5c8c75b45..08b0c4b8a 100644 --- a/compositor_pipeline/src/pipeline/output/whip.rs +++ b/compositor_pipeline/src/pipeline/output/whip.rs @@ -6,7 +6,7 @@ use packet_stream::PacketStream; use payloader::{Payload, Payloader, PayloadingError}; use reqwest::{Method, StatusCode, Url}; use std::sync::{atomic::AtomicBool, Arc}; -use tracing::{debug, error, span, Level}; +use tracing::{debug, error, span, Instrument, Level}; use url::ParseError; use webrtc::{ peer_connection::RTCPeerConnection, @@ -106,29 +106,31 @@ impl WhipSender { let should_close2 = should_close.clone(); let event_emitter = pipeline_ctx.event_emitter.clone(); let request_keyframe_sender = request_keyframe_sender.clone(); + let tokio_rt = pipeline_ctx.tokio_rt.clone(); + let tokio_rt_clone = tokio_rt.clone(); + let output_id_clone = output_id.clone(); - std::thread::Builder::new() - .name(format!("WHIP sender for output {}", output_id)) - .spawn(move || { - let _span = span!( - Level::INFO, - "WHIP sender", - output_id = output_id.to_string() - ) - .entered(); - start_whip_sender_thread( + tokio_rt.spawn( + async move { + run_whip_sender_thread( endpoint_url, bearer_token, should_close2, packet_stream, request_keyframe_sender, - tokio_rt, - ); - event_emitter.emit(Event::OutputDone(output_id)); + tokio_rt_clone, + ) + .await; + event_emitter.emit(Event::OutputDone(output_id_clone)); debug!("Closing WHIP sender thread.") - }) - .unwrap(); + } + .instrument(span!( + Level::INFO, + "WHIP sender", + output_id = output_id.to_string() + )), + ); Ok(Self { connection_options: options, @@ -144,7 +146,7 @@ impl Drop for WhipSender { } } -fn start_whip_sender_thread( +async fn run_whip_sender_thread( endpoint_url: String, bearer_token: Option, should_close: Arc, @@ -152,75 +154,74 @@ fn start_whip_sender_thread( request_keyframe_sender: Option>, tokio_rt: Arc, ) { - tokio_rt.block_on(async { - let client = reqwest::Client::new(); - let peer_connection: Arc; - let video_track: Arc; - let audio_track: Arc; - match init_pc().await { - Ok((pc, video, audio)) => { - peer_connection = pc; - video_track = video; - audio_track = audio; - } - Err(err) => { - error!("Error occured while initializing peer connection: {err}"); - return; - } + let client = reqwest::Client::new(); + let peer_connection: Arc; + let video_track: Arc; + let audio_track: Arc; + match init_pc().await { + Ok((pc, video, audio)) => { + peer_connection = pc; + video_track = video; + audio_track = audio; + } + Err(err) => { + error!("Error occured while initializing peer connection: {err}"); + return; + } + } + let whip_session_url = match connect( + peer_connection, + endpoint_url, + bearer_token, + should_close.clone(), + tokio_rt, + client.clone(), + request_keyframe_sender, + ) + .await + { + Ok(val) => val, + Err(err) => { + error!("{err}"); + return; + } + }; + + for chunk in packet_stream { + if should_close.load(std::sync::atomic::Ordering::Relaxed) { + break; } - let whip_session_url = match connect( - peer_connection, - endpoint_url, - bearer_token, - should_close.clone(), - tokio_rt.clone(), - client.clone(), - request_keyframe_sender, - ) - .await - { - Ok(val) => val, + let chunk = match chunk { + Ok(chunk) => chunk, Err(err) => { - error!("{err}"); - return; + error!("Failed to payload a packet: {}", err); + continue; } }; - for chunk in packet_stream { - if should_close.load(std::sync::atomic::Ordering::Relaxed) { - break; - } - let chunk = match chunk { - Ok(chunk) => chunk, + match chunk { + Payload::Video(video_payload) => match video_payload { + Ok(video_bytes) => { + if video_track.write(&video_bytes).await.is_err() { + error!("Error occurred while writing to video track for session"); + } + } Err(err) => { - error!("Failed to payload a packet: {}", err); - continue; + error!("Error while reading video bytes: {err}"); } - }; - - match chunk { - Payload::Video(video_payload) => match video_payload { - Ok(video_bytes) => { - if video_track.write(&video_bytes).await.is_err() { - error!("Error occurred while writing to video track for session"); - } - } - Err(err) => { - error!("Error while reading video bytes: {err}"); - } - }, - Payload::Audio(audio_payload) => match audio_payload { - Ok(audio_bytes) => { - if audio_track.write(&audio_bytes).await.is_err() { - error!("Error occurred while writing to video track for session"); - } - } - Err(err) => { - error!("Error while reading audio bytes: {err}"); + }, + Payload::Audio(audio_payload) => match audio_payload { + Ok(audio_bytes) => { + if audio_track.write(&audio_bytes).await.is_err() { + error!("Error occurred while writing to video track for session"); } - }, - } + } + Err(err) => { + error!("Error while reading audio bytes: {err}"); + } + }, } - let _ = client.delete(whip_session_url).send().await; - }); + } + let _ = client.delete(whip_session_url).send().await; + // }); } diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs index b6bf55bb9..b7c35ce3f 100644 --- a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -1,11 +1,11 @@ use crossbeam_channel::Sender; use super::WhipError; -use reqwest::{header::HeaderMap, Method, StatusCode, Url}; +use reqwest::{header::HeaderMap, Client, Method, StatusCode, Url}; use std::sync::{atomic::AtomicBool, Arc}; -use tracing::{debug, info}; +use tracing::{debug, error, info}; use webrtc::{ - ice_transport::ice_connection_state::RTCIceConnectionState, + ice_transport::{ice_candidate::RTCIceCandidate, ice_connection_state::RTCIceConnectionState}, peer_connection::{sdp::session_description::RTCSessionDescription, RTCPeerConnection}, rtcp::payload_feedbacks::picture_loss_indication::PictureLossIndication, }; @@ -21,11 +21,11 @@ pub async fn connect( ) -> Result { peer_connection.on_ice_connection_state_change(Box::new( move |connection_state: RTCIceConnectionState| { - debug!("Connection State has changed {connection_state}"); + debug!("Connection State has changed {connection_state}."); if connection_state == RTCIceConnectionState::Connected { - debug!("ice connected"); + debug!("Ice connected."); } else if connection_state == RTCIceConnectionState::Failed { - debug!("Done writing media files"); + debug!("Ice connection failed."); should_close.store(true, std::sync::atomic::Ordering::Relaxed); } Box::pin(async {}) @@ -66,7 +66,7 @@ pub async fn connect( let endpoint_url = Url::parse(&endpoint_url) .map_err(|e| WhipError::InvalidEndpointUrl(e, endpoint_url.clone()))?; - info!("[WHIP] endpoint url: {}", endpoint_url); + info!("Endpoint url: {}", endpoint_url); let mut header_map = HeaderMap::new(); header_map.append("Content-Type", "application/sdp".parse().unwrap()); @@ -97,8 +97,6 @@ pub async fn connect( return Err(WhipError::BadStatus(status, answer)); } - info!("[WHIP] response: {:?}", &response); - let location_url_path = response .headers() .get("location") @@ -137,47 +135,20 @@ pub async fn connect( let client = Arc::new(client); - let location1: Url = location_url.clone(); + let location_clone: Url = location_url.clone(); peer_connection.on_ice_candidate(Box::new(move |candidate| { if let Some(candidate) = candidate { let client_clone = client.clone(); - let location2 = location1.clone(); - let bearer_token1 = bearer_token.clone(); + let location_clone = location_clone.clone(); + let bearer_token_clone = bearer_token.clone(); tokio_rt.spawn(async move { - let ice_candidate = candidate - .to_json() - .map_err(WhipError::IceCandidateToJsonError)?; - - let mut header_map = HeaderMap::new(); - header_map.append( - "Content-Type", - "application/trickle-ice-sdpfrag".parse().unwrap(), - ); - - if let Some(token) = bearer_token1 { - header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); - } - - let response = match client_clone - .patch(location2.clone()) - .headers(header_map) - .body(serde_json::to_string(&ice_candidate)?) - .send() - .await + if let Err(err) = + handle_candidate(candidate, bearer_token_clone, client_clone, location_clone) + .await { - Ok(res) => res, - Err(_) => return Err(WhipError::RequestFailed(Method::PATCH, location2)), - }; - - if response.status() >= StatusCode::BAD_REQUEST { - let status = response.status(); - let body_str = response.text().await.map_err(|e| { - WhipError::BodyParsingError("Trickle ICE patch".to_string(), e) - })?; - return Err(WhipError::BadStatus(status, body_str)); - }; - Ok(response) + error!("{err}"); + } }); } Box::pin(async {}) @@ -185,3 +156,45 @@ pub async fn connect( Ok(location_url.clone()) } + +async fn handle_candidate( + candidate: RTCIceCandidate, + bearer_token: Option>, + client: Arc, + location: Url, +) -> Result<(), WhipError> { + let ice_candidate = candidate + .to_json() + .map_err(WhipError::IceCandidateToJsonError)?; + + let mut header_map = HeaderMap::new(); + header_map.append( + "Content-Type", + "application/trickle-ice-sdpfrag".parse().unwrap(), + ); + + if let Some(token) = bearer_token { + header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); + } + + let response = match client + .patch(location.clone()) + .headers(header_map) + .body(serde_json::to_string(&ice_candidate)?) + .send() + .await + { + Ok(res) => res, + Err(_) => return Err(WhipError::RequestFailed(Method::PATCH, location)), + }; + + if response.status() >= StatusCode::BAD_REQUEST { + let status = response.status(); + let body_str = response + .text() + .await + .map_err(|e| WhipError::BodyParsingError("Trickle ICE patch".to_string(), e))?; + return Err(WhipError::BadStatus(status, body_str)); + }; + Ok(()) +} From 0a4aae80c38304f3424f507c248546d4add2020a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Kraso=C5=84?= <45288762+BrtqKr@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:27:36 +0100 Subject: [PATCH 14/51] [ts-sdk][demos] Set up pnpm workspaces, update eslint config, update ts config (#830) --- .github/workflows/demos_check.yml | 22 +- .github/workflows/lint.yml | 5 + .github/workflows/ts_sdk_check.yml | 24 +- .vscode/settings.json | 10 +- demos/.eslintrc.json | 28 - demos/.prettierrc | 9 - demos/.prettierrc.js | 9 + demos/1-videoconferencing/index.tsx | 1 + demos/2-tv_broadcast/index.tsx | 12 +- demos/eslint.config.js | 86 + demos/package-lock.json | 4383 ----- demos/package.json | 29 +- demos/pnpm-lock.yaml | 3379 ++++ demos/tsconfig.json | 22 +- demos/utils/ffmpeg.ts | 11 +- demos/utils/utils.ts | 7 +- docs/.prettierrc.js | 11 + ts/.eslintrc.base.json | 49 - ts/.npmrc | 2 + ts/.prettierrc | 9 - ts/.prettierrc.js | 9 + .../browser-render/.eslintignore | 2 - .../browser-render/.eslintrc.json | 5 - .../browser-render/package.json | 4 +- ts/@live-compositor/browser-render/src/api.ts | 2 +- .../browser-render/src/renderer.ts | 2 +- .../browser-render/tsconfig.json | 7 +- ts/@live-compositor/core/.eslintignore | 2 - ts/@live-compositor/core/.eslintrc.json | 5 - ts/@live-compositor/core/package.json | 10 +- ts/@live-compositor/core/src/api.ts | 6 +- ts/@live-compositor/core/src/api/input.ts | 4 +- ts/@live-compositor/core/src/api/output.ts | 2 +- ts/@live-compositor/core/src/api/renderer.ts | 4 +- ts/@live-compositor/core/src/compositor.ts | 11 +- .../core/src/compositorManager.ts | 2 +- ts/@live-compositor/core/src/event.ts | 3 +- ts/@live-compositor/core/src/output.ts | 17 +- ts/@live-compositor/core/src/renderer.ts | 7 +- ts/@live-compositor/core/tsconfig.cjs.json | 1 + ts/@live-compositor/core/tsconfig.json | 2 +- ts/@live-compositor/node/.eslintignore | 1 - ts/@live-compositor/node/.eslintrc.json | 5 - ts/@live-compositor/node/package.json | 4 +- ts/@live-compositor/node/src/fetch.ts | 2 +- ts/@live-compositor/node/src/index.ts | 3 +- .../node/src/manager/existingInstance.ts | 2 +- .../src/manager/locallySpawnedInstance.ts | 4 +- ts/@live-compositor/node/src/spawn.ts | 3 +- ts/@live-compositor/node/tsconfig.json | 2 +- ts/@live-compositor/web-wasm/.eslintignore | 1 - ts/@live-compositor/web-wasm/.eslintrc.json | 5 - ts/@live-compositor/web-wasm/package.json | 11 +- .../web-wasm/src/compositor.ts | 8 +- .../web-wasm/src/eventSender.ts | 3 +- .../web-wasm/src/input/input.ts | 6 +- .../web-wasm/src/input/mp4/demuxer.ts | 3 +- .../web-wasm/src/input/mp4/source.ts | 4 +- .../web-wasm/src/input/registerInput.ts | 2 +- .../web-wasm/src/input/source.ts | 4 +- .../web-wasm/src/manager/wasmInstance.ts | 11 +- .../web-wasm/src/output/canvas.ts | 4 +- .../web-wasm/src/output/output.ts | 6 +- .../web-wasm/src/output/registerOutput.ts | 7 +- .../web-wasm/src/output/sink.ts | 2 +- ts/@live-compositor/web-wasm/src/queue.ts | 8 +- ts/@live-compositor/web-wasm/src/renderers.ts | 2 +- ts/@live-compositor/web-wasm/tsconfig.json | 2 +- ts/create-live-compositor/.eslintignore | 2 - ts/create-live-compositor/.eslintrc.json | 5 - ts/create-live-compositor/package.json | 4 +- .../src/createNodeProject.ts | 2 +- ts/create-live-compositor/src/options.ts | 5 +- ts/create-live-compositor/src/template.ts | 2 +- .../src/utils/prompts.ts | 5 +- ts/create-live-compositor/src/utils/spawn.ts | 3 +- .../src/utils/workingdir.ts | 2 +- .../node-express-zustand/package.json | 10 +- .../src/liveCompositorFfplayHelper.ts | 3 +- .../node-express-zustand/src/routes.ts | 3 +- .../templates/node-minimal/package.json | 7 +- .../templates/node-minimal/src/index.tsx | 4 +- .../src/liveCompositorFfplayHelper.ts | 3 +- ts/create-live-compositor/tsconfig.json | 6 +- ts/eslint.config.js | 102 + ts/examples/README.md | 4 +- ts/examples/node-examples/.eslintignore | 1 - ts/examples/node-examples/.eslintrc.json | 5 - ts/examples/node-examples/package.json | 13 +- .../node-examples/src/dynamic-outputs.tsx | 4 +- ts/examples/node-examples/src/utils.ts | 15 +- ts/examples/node-examples/tsconfig.json | 2 +- .../vite-browser-render/eslint.config.js | 25 - ts/examples/vite-browser-render/package.json | 13 +- ts/examples/vite-browser-render/src/App.tsx | 14 +- .../src/examples/Counter.tsx | 1 - .../src/examples/MP4Player.tsx | 9 +- .../src/examples/mp4/decoder.ts | 102 + .../vite-browser-render/src/examples/utils.ts | 28 + .../ts-declarations/mp4box.d.ts | 112 + .../vite-browser-render/tsconfig.app.json | 2 +- .../vite-browser-render/vite.config.ts | 5 +- ts/live-compositor/.eslintignore | 2 - ts/live-compositor/.eslintrc.json | 5 - ts/live-compositor/package.json | 6 +- ts/live-compositor/src/component.ts | 7 +- ts/live-compositor/src/components/Image.ts | 5 +- .../src/components/InputStream.ts | 5 +- ts/live-compositor/src/components/Rescaler.ts | 10 +- ts/live-compositor/src/components/Shader.ts | 5 +- ts/live-compositor/src/components/Text.ts | 5 +- ts/live-compositor/src/components/Tiles.ts | 8 +- ts/live-compositor/src/components/View.ts | 8 +- ts/live-compositor/src/components/WebView.ts | 5 +- ts/live-compositor/src/components/common.ts | 2 +- .../src/context/instanceContextStore.ts | 2 +- .../src/context/outputContext.ts | 2 +- ts/live-compositor/src/hooks.ts | 4 +- ts/live-compositor/src/types/registerInput.ts | 2 +- .../src/types/registerOutput.ts | 4 +- .../src/types/registerRenderer.ts | 2 +- ts/live-compositor/tsconfig.json | 2 +- ts/package-lock.json | 14365 ---------------- ts/package.json | 49 +- ts/pnpm-lock.yaml | 4895 ++++++ ts/pnpm-workspace.yaml | 11 + ts/{tsconfig.base.json => tsconfig.json} | 0 127 files changed, 9067 insertions(+), 19197 deletions(-) delete mode 100644 demos/.eslintrc.json delete mode 100644 demos/.prettierrc create mode 100644 demos/.prettierrc.js create mode 100644 demos/eslint.config.js delete mode 100644 demos/package-lock.json create mode 100644 demos/pnpm-lock.yaml create mode 100644 docs/.prettierrc.js delete mode 100644 ts/.eslintrc.base.json create mode 100644 ts/.npmrc delete mode 100644 ts/.prettierrc create mode 100644 ts/.prettierrc.js delete mode 100644 ts/@live-compositor/browser-render/.eslintignore delete mode 100644 ts/@live-compositor/browser-render/.eslintrc.json delete mode 100644 ts/@live-compositor/core/.eslintignore delete mode 100644 ts/@live-compositor/core/.eslintrc.json delete mode 100644 ts/@live-compositor/node/.eslintignore delete mode 100644 ts/@live-compositor/node/.eslintrc.json delete mode 100644 ts/@live-compositor/web-wasm/.eslintignore delete mode 100644 ts/@live-compositor/web-wasm/.eslintrc.json delete mode 100644 ts/create-live-compositor/.eslintignore delete mode 100644 ts/create-live-compositor/.eslintrc.json create mode 100644 ts/eslint.config.js delete mode 100644 ts/examples/node-examples/.eslintignore delete mode 100644 ts/examples/node-examples/.eslintrc.json delete mode 100644 ts/examples/vite-browser-render/eslint.config.js create mode 100644 ts/examples/vite-browser-render/src/examples/mp4/decoder.ts create mode 100644 ts/examples/vite-browser-render/src/examples/utils.ts create mode 100644 ts/examples/vite-browser-render/ts-declarations/mp4box.d.ts delete mode 100644 ts/live-compositor/.eslintignore delete mode 100644 ts/live-compositor/.eslintrc.json delete mode 100644 ts/package-lock.json create mode 100644 ts/pnpm-lock.yaml create mode 100644 ts/pnpm-workspace.yaml rename ts/{tsconfig.base.json => tsconfig.json} (100%) diff --git a/.github/workflows/demos_check.yml b/.github/workflows/demos_check.yml index 0d1dd7e9a..5c05d27dc 100644 --- a/.github/workflows/demos_check.yml +++ b/.github/workflows/demos_check.yml @@ -24,28 +24,24 @@ jobs: with: submodules: "true" + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + - name: Setup Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: "20" - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - ${{ runner.os }}- - - name: Install project dependencies working-directory: ./demos - run: npm ci + run: pnpm install --frozen-lockfile - name: Lint code working-directory: ./demos - run: npm run lint + run: pnpm run lint - name: Typecheck code working-directory: ./demos - run: npm run typecheck + run: pnpm run typecheck diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5772cde4f..6bff07b7a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,6 +29,11 @@ jobs: with: components: rustfmt, clippy + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + - name: ๐Ÿ›  Setup Node.JS uses: actions/setup-node@v4 with: diff --git a/.github/workflows/ts_sdk_check.yml b/.github/workflows/ts_sdk_check.yml index f784491db..f42397c9b 100644 --- a/.github/workflows/ts_sdk_check.yml +++ b/.github/workflows/ts_sdk_check.yml @@ -22,32 +22,28 @@ jobs: - name: Checkout repo uses: actions/checkout@v2 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + - name: Setup Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: "20" - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - ${{ runner.os }}- - - name: Install project dependencies working-directory: ./ts - run: npm install + run: pnpm install --frozen-lockfile - name: Build working-directory: ./ts - run: npm run build:all + run: pnpm run build:all - name: Lint code working-directory: ./ts - run: npm run lint + run: pnpm run lint - name: Typecheck code working-directory: ./ts - run: npm run typecheck + run: pnpm run typecheck diff --git a/.vscode/settings.json b/.vscode/settings.json index 0348ca7fe..3684f4007 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,13 @@ "url": "./schemas/scene.schema.json" } ], - "eslint.workingDirectories": [{ "mode": "auto" }] + "eslint.workingDirectories": [ + { "directory": "./demos", "changeProcessCWD": true }, + { "directory": "./ts", "changeProcessCWD": true }, + { "directory": "./docs", "changeProcessCWD": true } + ], + "prettier.requireConfig": true, + "prettier.configPath": "", + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" } diff --git a/demos/.eslintrc.json b/demos/.eslintrc.json deleted file mode 100644 index fc0d40cca..000000000 --- a/demos/.eslintrc.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "env": { - "node": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:import/recommended", - "plugin:import/typescript", - "prettier" - ], - "plugins": [ - "prettier" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": [ - "tsconfig.json" - ] - }, - "rules": { - "prettier/prettier": ["error"], - "@typescript-eslint/no-explicit-any": [0, {}], - "@typescript-eslint/no-floating-promises": "error", - "no-constant-condition": [0] - } -} diff --git a/demos/.prettierrc b/demos/.prettierrc deleted file mode 100644 index 58660ea94..000000000 --- a/demos/.prettierrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "printWidth": 100, - "tabWidth": 2, - "singleQuote": true, - "bracketSameLine": true, - "trailingComma": "es5", - "arrowParens": "avoid", - "endOfLine": "auto" -} diff --git a/demos/.prettierrc.js b/demos/.prettierrc.js new file mode 100644 index 000000000..74da53f68 --- /dev/null +++ b/demos/.prettierrc.js @@ -0,0 +1,9 @@ +export default { + printWidth: 100, + tabWidth: 2, + singleQuote: true, + bracketSameLine: true, + trailingComma: 'es5', + arrowParens: 'avoid', + endOfLine: 'auto', +}; diff --git a/demos/1-videoconferencing/index.tsx b/demos/1-videoconferencing/index.tsx index cdbbeddb9..ef9e480e4 100644 --- a/demos/1-videoconferencing/index.tsx +++ b/demos/1-videoconferencing/index.tsx @@ -34,6 +34,7 @@ function App() { }, 2000); return () => clearTimeout(timeout); }, [counter]); + return ; } diff --git a/demos/2-tv_broadcast/index.tsx b/demos/2-tv_broadcast/index.tsx index c01b50277..12f081d3f 100644 --- a/demos/2-tv_broadcast/index.tsx +++ b/demos/2-tv_broadcast/index.tsx @@ -2,16 +2,8 @@ import { ffmpegSendVideoFromMp4 } from '../utils/ffmpeg'; import { downloadAsync } from '../utils/utils'; import fs from 'fs-extra'; import path from 'path'; -import { - View, - Image, - Text, - Rescaler, - Shader, - InputStream, - Transition, - useInputStreams, -} from 'live-compositor'; +import type { Transition } from 'live-compositor'; +import { View, Image, Text, Rescaler, Shader, InputStream, useInputStreams } from 'live-compositor'; import LiveCompositor from '@live-compositor/node'; import { useEffect, useState } from 'react'; import { gstStartPlayer } from '../utils/gst'; diff --git a/demos/eslint.config.js b/demos/eslint.config.js new file mode 100644 index 000000000..17af4d26d --- /dev/null +++ b/demos/eslint.config.js @@ -0,0 +1,86 @@ +import globals from 'globals'; + +import eslintRecommended from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +import pluginImport from 'eslint-plugin-import'; +import pluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; +import { plugin as tsEslintPlugin } from 'typescript-eslint'; +import reactHooks from 'eslint-plugin-react-hooks'; +import tsParser from '@typescript-eslint/parser'; + +export default [ + eslintRecommended.configs.recommended, + pluginImport.flatConfigs.recommended, + pluginPrettierRecommended, + eslintConfigPrettier, + { + files: ['**/*.{js,jsx,ts,tsx}'], + ignores: ['.prettierrc.js'], + plugins: { + '@typescript-eslint': tsEslintPlugin, + }, + languageOptions: { + parser: tsParser, + parserOptions: { + project: 'tsconfig.json', + }, + ecmaVersion: 'latest', + sourceType: 'module', + globals: { + ...globals.browser, + ...globals.node, + }, + }, + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + typescript: { + alwaysTryTypes: true, + project: 'tsconfig.json', + }, + }, + }, + rules: { + 'prettier/prettier': ['error'], + 'import/no-unresolved': 'error', + '@typescript-eslint/no-explicit-any': [0, {}], + '@typescript-eslint/no-floating-promises': ['error'], + 'no-constant-condition': [0], + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true, + vars: 'local', + }, + ], + '@typescript-eslint/consistent-type-imports': [ + 'error', + { + prefer: 'type-imports', + }, + ], + }, + }, + { + files: ['**/*.{ts,tsx}'], + plugins: { + 'react-hooks': reactHooks, + }, + rules: { + ...reactHooks.configs.recommended.rules, + }, + }, + { + ignores: ['eslint.config.js', '**/generated/**/*', '**/*.d.ts'], + }, +]; diff --git a/demos/package-lock.json b/demos/package-lock.json deleted file mode 100644 index 231b5975f..000000000 --- a/demos/package-lock.json +++ /dev/null @@ -1,4383 +0,0 @@ -{ - "name": "live_compositor_demos", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "live_compositor_demos", - "version": "1.0.0", - "license": "BUSL-1.1", - "dependencies": { - "@live-compositor/node": "^0.1.0", - "@types/fs-extra": "^11.0.2", - "@types/node": "^20.12.11", - "@types/node-fetch": "^2.6.11", - "@typescript-eslint/eslint-plugin": "^6.7.3", - "@typescript-eslint/parser": "^6.7.3", - "chalk": "^4.1.2", - "eslint": "^8.50.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-prettier": "^5.0.0", - "fs-extra": "^11.1.1", - "json-schema-to-typescript": "^14.0.4", - "live-compositor": "^0.1.0", - "node-fetch": "^2.7.0", - "node-popup": "^0.1.14", - "prettier": "^3.0.3", - "react": "^18.3.1", - "ts-node": "^10.9.1", - "typescript": "^5.2.2" - }, - "devDependencies": { - "@types/react": "^18.3.9" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.6.1", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.6.1.tgz", - "integrity": "sha512-DxjgKBCoyReu4p5HMvpmgSOfRhhBcuf5V5soDDRgOTZMwsA4KSFzol1abFZgiCTE11L2kKGca5Md9GwDdXVBwQ==", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "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", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/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==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" - }, - "node_modules/@live-compositor/core": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@live-compositor/core/-/core-0.1.0.tgz", - "integrity": "sha512-0ZqPH3kS1krO633j9930Wr/lBBNj6kdmwsEeOkmatgt9aApzcYTk6rxb2awdn4Oh5JcmDtVBf1zrLzgAT9iwcQ==", - "dependencies": { - "react-reconciler": "0.29.2" - }, - "peerDependencies": { - "live-compositor": "^0.1.0" - } - }, - "node_modules/@live-compositor/node": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@live-compositor/node/-/node-0.1.0.tgz", - "integrity": "sha512-Wdnq5cyWE2rEDy12IVue+98hsrigZtDnZlWrbDLPT29/ERCl2eSFeOSlnAaZvLqw26xmeNAVkjpBXqMjI1O3bg==", - "dependencies": { - "@live-compositor/core": "^0.1.0", - "fs-extra": "^11.2.0", - "node-fetch": "^2.6.7", - "tar": "^7.4.3", - "uuid": "^10.0.0", - "ws": "^8.18.0" - } - }, - "node_modules/@live-compositor/node/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" - }, - "node_modules/@types/fs-extra": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", - "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", - "dependencies": { - "@types/jsonfile": "*", - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - }, - "node_modules/@types/jsonfile": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", - "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/lodash": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.1.tgz", - "integrity": "sha512-X+2qazGS3jxLAIz5JDXDzglAF3KpijdhFxlf/V1+hEsOUc+HnWi81L/uv/EvGuV90WY+7mPGFCUDGfQC3Gj95Q==" - }, - "node_modules/@types/node": { - "version": "20.12.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", - "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.3.9", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.9.tgz", - "integrity": "sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "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==" - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==" - }, - "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==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/carlo": { - "version": "0.9.43", - "resolved": "https://registry.npmjs.org/carlo/-/carlo-0.9.43.tgz", - "integrity": "sha512-m3kCI4ZxYKCGmOoBNnu/Bq+FMZpfYV2P8qWuOcVa2HuxBgS5afG5Efw9D8v7IUhCc+4ox2Eag1BN9ERtGPr7Vg==", - "dependencies": { - "debug": "^4.1.0", - "puppeteer-core": "^1.9.0" - }, - "engines": { - "node": ">=7.6.0" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "engines": { - "node": ">=18" - } - }, - "node_modules/cli-color": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", - "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.64", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.10" - } - }, - "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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "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==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "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 - }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "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==" - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", - "dependencies": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - } - }, - "node_modules/extract-zip/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/extract-zip/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "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==" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "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==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, - "node_modules/json-schema-to-typescript": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-14.0.4.tgz", - "integrity": "sha512-covPOp3hrbD+oEcMvDxP5Rh6xNZj7lOTZkXAeQoDyu1PuEl1A6oRZ3Sy05HN11vXXmdJ6gLh5P3Qz0mgMPTzzw==", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^11.5.5", - "@types/json-schema": "^7.0.15", - "@types/lodash": "^4.17.0", - "cli-color": "^2.0.4", - "glob": "^10.3.12", - "is-glob": "^4.0.3", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "mkdirp": "^3.0.1", - "mz": "^2.7.0", - "node-fetch": "^3.3.2", - "prettier": "^3.2.5" - }, - "bin": { - "json2ts": "dist/src/cli.js" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/json-schema-to-typescript/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - }, - "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/live-compositor": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/live-compositor/-/live-compositor-0.1.0.tgz", - "integrity": "sha512-TAScLUrHcSBAkAzQPsfyqvZ3EDHyETABKnp6E0uY7x1Zsqj+Xz4RkoOPB2cBJDORpSUkQUtj6pbchKUSXQ4Mnw==", - "peerDependencies": { - "react": "*" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "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", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "node_modules/memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minizlib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz", - "integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/minizlib/node_modules/rimraf": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", - "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-popup": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/node-popup/-/node-popup-0.1.14.tgz", - "integrity": "sha512-zmFaETuJn87rKY8Ib7IQVyBDcg9Uh7/GnPLFyPeCU1Tx5KA7Z2SBAs2kdhUBFiMElUzQwqllBRJoikpOf4ee2Q==", - "dependencies": { - "carlo": "0.9.43" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/puppeteer-core": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-1.20.0.tgz", - "integrity": "sha512-akoSCMDVv6BFd/4+dtW6mVgdaRQhy/cmkGzXcx9HAXZqnY9zXYbsfoXMiMpwt3+53U9zFGSjgvsi0mDKNJLfqg==", - "hasInstallScript": true, - "dependencies": { - "debug": "^4.1.0", - "extract-zip": "^1.6.6", - "https-proxy-agent": "^2.2.1", - "mime": "^2.0.3", - "progress": "^2.0.1", - "proxy-from-env": "^1.0.0", - "rimraf": "^2.6.1", - "ws": "^6.1.0" - }, - "engines": { - "node": ">=6.4.0" - } - }, - "node_modules/puppeteer-core/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/puppeteer-core/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/puppeteer-core/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/puppeteer-core/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-reconciler": { - "version": "0.29.2", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.2.tgz", - "integrity": "sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "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==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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==" - }, - "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==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tar": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", - "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "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==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "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==" - }, - "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==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/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==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/ws": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", - "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", - "dependencies": { - "async-limiter": "~1.0.0" - } - }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "engines": { - "node": ">=18" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/demos/package.json b/demos/package.json index dcb838a5c..3d9bad87c 100644 --- a/demos/package.json +++ b/demos/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "Demos for LiveCompositor - media server for low latency video and audio mixing/composing", "main": "index.js", + "type": "module", "scripts": { "lint": "eslint .", "typecheck": "tsc --noEmit", @@ -25,26 +26,30 @@ "dependencies": { "@live-compositor/node": "^0.1.0", "@types/fs-extra": "^11.0.2", - "@types/node": "^20.12.11", "@types/node-fetch": "^2.6.11", - "@typescript-eslint/eslint-plugin": "^6.7.3", - "@typescript-eslint/parser": "^6.7.3", "chalk": "^4.1.2", - "eslint": "^8.50.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-prettier": "^5.0.0", "fs-extra": "^11.1.1", "json-schema-to-typescript": "^14.0.4", "live-compositor": "^0.1.0", "node-fetch": "^2.7.0", "node-popup": "^0.1.14", - "prettier": "^3.0.3", - "react": "^18.3.1", - "ts-node": "^10.9.1", - "typescript": "^5.2.2" + "react": "^18.3.1" }, "devDependencies": { - "@types/react": "^18.3.9" + "@types/node": "^20.12.11", + "@types/react": "^18.3.9", + "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/parser": "^8.8.1", + "eslint": "^9.12.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-react-hooks": "^5.0.0", + "globals": "^15.11.0", + "prettier": "^3.3.3", + "ts-node": "^10.9.1", + "typescript": "^5.5.3", + "typescript-eslint": "8.8.1" } } diff --git a/demos/pnpm-lock.yaml b/demos/pnpm-lock.yaml new file mode 100644 index 000000000..9978fb598 --- /dev/null +++ b/demos/pnpm-lock.yaml @@ -0,0 +1,3379 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@live-compositor/node': + specifier: ^0.1.0 + version: 0.1.0(live-compositor@0.1.0(react@18.3.1))(react@18.3.1) + '@types/fs-extra': + specifier: ^11.0.2 + version: 11.0.4 + '@types/node-fetch': + specifier: ^2.6.11 + version: 2.6.11 + chalk: + specifier: ^4.1.2 + version: 4.1.2 + fs-extra: + specifier: ^11.1.1 + version: 11.2.0 + json-schema-to-typescript: + specifier: ^14.0.4 + version: 14.1.0 + live-compositor: + specifier: ^0.1.0 + version: 0.1.0(react@18.3.1) + node-fetch: + specifier: ^2.7.0 + version: 2.7.0 + node-popup: + specifier: ^0.1.14 + version: 0.1.14 + react: + specifier: ^18.3.1 + version: 18.3.1 + devDependencies: + '@types/node': + specifier: ^20.12.11 + version: 20.16.11 + '@types/react': + specifier: ^18.3.9 + version: 18.3.11 + '@typescript-eslint/eslint-plugin': + specifier: ^8.8.1 + version: 8.9.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/parser': + specifier: ^8.8.1 + version: 8.9.0(eslint@9.12.0)(typescript@5.6.3) + eslint: + specifier: ^9.12.0 + version: 9.12.0 + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.0(eslint@9.12.0) + eslint-import-resolver-typescript: + specifier: ^3.6.3 + version: 3.6.3(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@9.12.0) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.31.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0) + eslint-plugin-prettier: + specifier: ^5.2.1 + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.12.0))(eslint@9.12.0)(prettier@3.3.3) + eslint-plugin-react-hooks: + specifier: ^5.0.0 + version: 5.0.0(eslint@9.12.0) + globals: + specifier: ^15.11.0 + version: 15.11.0 + prettier: + specifier: ^3.3.3 + version: 3.3.3 + ts-node: + specifier: ^10.9.1 + version: 10.9.2(@types/node@20.16.11)(typescript@5.6.3) + typescript: + specifier: ^5.5.3 + version: 5.6.3 + typescript-eslint: + specifier: 8.8.1 + version: 8.8.1(eslint@9.12.0)(typescript@5.6.3) + +packages: + + '@apidevtools/json-schema-ref-parser@11.7.2': + resolution: {integrity: sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==} + engines: {node: '>= 16'} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.11.1': + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.18.0': + resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.6.0': + resolution: {integrity: sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.1.0': + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.12.0': + resolution: {integrity: sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.4': + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.0': + resolution: {integrity: sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.0': + resolution: {integrity: sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.5': + resolution: {integrity: sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@live-compositor/core@0.1.0': + resolution: {integrity: sha512-0ZqPH3kS1krO633j9930Wr/lBBNj6kdmwsEeOkmatgt9aApzcYTk6rxb2awdn4Oh5JcmDtVBf1zrLzgAT9iwcQ==} + peerDependencies: + live-compositor: ^0.1.0 + + '@live-compositor/node@0.1.0': + resolution: {integrity: sha512-Wdnq5cyWE2rEDy12IVue+98hsrigZtDnZlWrbDLPT29/ERCl2eSFeOSlnAaZvLqw26xmeNAVkjpBXqMjI1O3bg==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/fs-extra@11.0.4': + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/jsonfile@6.1.4': + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + + '@types/lodash@4.17.10': + resolution: {integrity: sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==} + + '@types/node-fetch@2.6.11': + resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} + + '@types/node@20.16.11': + resolution: {integrity: sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==} + + '@types/prop-types@15.7.13': + resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} + + '@types/react@18.3.11': + resolution: {integrity: sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==} + + '@typescript-eslint/eslint-plugin@8.8.1': + resolution: {integrity: sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/eslint-plugin@8.9.0': + resolution: {integrity: sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@8.8.1': + resolution: {integrity: sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@8.9.0': + resolution: {integrity: sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@8.8.1': + resolution: {integrity: sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/scope-manager@8.9.0': + resolution: {integrity: sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.8.1': + resolution: {integrity: sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/type-utils@8.9.0': + resolution: {integrity: sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@8.8.1': + resolution: {integrity: sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/types@8.9.0': + resolution: {integrity: sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.8.1': + resolution: {integrity: sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@8.9.0': + resolution: {integrity: sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@8.8.1': + resolution: {integrity: sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + + '@typescript-eslint/utils@8.9.0': + resolution: {integrity: sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + + '@typescript-eslint/visitor-keys@8.8.1': + resolution: {integrity: sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/visitor-keys@8.9.0': + resolution: {integrity: sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.13.0: + resolution: {integrity: sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@4.3.0: + resolution: {integrity: sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==} + engines: {node: '>= 4.0.0'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + async-limiter@1.0.1: + resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + carlo@0.9.43: + resolution: {integrity: sha512-m3kCI4ZxYKCGmOoBNnu/Bq+FMZpfYV2P8qWuOcVa2HuxBgS5afG5Efw9D8v7IUhCc+4ox2Eag1BN9ERtGPr7Vg==} + engines: {node: '>=7.6.0'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + cli-color@2.0.4: + resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} + engines: {node: '>=0.10'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + d@1.0.2: + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} + engines: {node: '>=0.12'} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} + engines: {node: '>=10.13.0'} + + es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + es5-ext@0.10.64: + resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} + engines: {node: '>=0.10'} + + es6-iterator@2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + + es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + + es6-symbol@3.1.4: + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} + engines: {node: '>=0.12'} + + es6-weak-map@2.0.3: + resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@9.1.0: + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.6.3: + resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.31.0: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-prettier@5.2.1: + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-react-hooks@5.0.0: + resolution: {integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-scope@8.1.0: + resolution: {integrity: sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.1.0: + resolution: {integrity: sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.12.0: + resolution: {integrity: sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + esniff@2.0.1: + resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} + engines: {node: '>=0.10'} + + espree@10.2.0: + resolution: {integrity: sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + event-emitter@0.3.5: + resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + + ext@1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + + extract-zip@1.7.0: + resolution: {integrity: sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==} + hasBin: true + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.11.0: + resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + https-proxy-agent@2.2.4: + resolution: {integrity: sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==} + engines: {node: '>= 4.5.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-bun-module@1.2.1: + resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-promise@2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-to-typescript@14.1.0: + resolution: {integrity: sha512-VIeAFQkn88gFh26MSHWG4uX7TjK/arTw0NVLMZn6vX1WrSF+P6xu5MyEdovu+9PJ0uiS5gm0wzwQvYW9eSq1uw==} + engines: {node: '>=16.0.0'} + hasBin: true + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + live-compositor@0.1.0: + resolution: {integrity: sha512-TAScLUrHcSBAkAzQPsfyqvZ3EDHyETABKnp6E0uY7x1Zsqj+Xz4RkoOPB2cBJDORpSUkQUtj6pbchKUSXQ4Mnw==} + peerDependencies: + react: '*' + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-queue@0.1.0: + resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + memoizee@0.4.17: + resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} + engines: {node: '>=0.12'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.0.1: + resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} + engines: {node: '>= 18'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + node-popup@0.1.14: + resolution: {integrity: sha512-zmFaETuJn87rKY8Ib7IQVyBDcg9Uh7/GnPLFyPeCU1Tx5KA7Z2SBAs2kdhUBFiMElUzQwqllBRJoikpOf4ee2Q==} + + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + engines: {node: '>=14'} + hasBin: true + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + puppeteer-core@1.20.0: + resolution: {integrity: sha512-akoSCMDVv6BFd/4+dtW6mVgdaRQhy/cmkGzXcx9HAXZqnY9zXYbsfoXMiMpwt3+53U9zFGSjgvsi0mDKNJLfqg==} + engines: {node: '>=6.4.0'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-reconciler@0.29.2: + resolution: {integrity: sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^18.3.1 + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + engines: {node: ^14.18.0 || >=16.0.0} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + timers-ext@0.1.8: + resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} + engines: {node: '>=0.12'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.0: + resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type@2.7.3: + resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typescript-eslint@8.8.1: + resolution: {integrity: sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@6.2.3: + resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@apidevtools/json-schema-ref-parser@11.7.2': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.0 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@eslint-community/eslint-utils@4.4.0(eslint@9.12.0)': + dependencies: + eslint: 9.12.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.11.1': {} + + '@eslint/config-array@0.18.0': + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.7 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.6.0': {} + + '@eslint/eslintrc@3.1.0': + dependencies: + ajv: 6.12.6 + debug: 4.3.7 + espree: 10.2.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.12.0': {} + + '@eslint/object-schema@2.1.4': {} + + '@eslint/plugin-kit@0.2.0': + dependencies: + levn: 0.4.1 + + '@humanfs/core@0.19.0': {} + + '@humanfs/node@0.16.5': + dependencies: + '@humanfs/core': 0.19.0 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@jsdevtools/ono@7.1.3': {} + + '@live-compositor/core@0.1.0(live-compositor@0.1.0(react@18.3.1))(react@18.3.1)': + dependencies: + live-compositor: 0.1.0(react@18.3.1) + react-reconciler: 0.29.2(react@18.3.1) + transitivePeerDependencies: + - react + + '@live-compositor/node@0.1.0(live-compositor@0.1.0(react@18.3.1))(react@18.3.1)': + dependencies: + '@live-compositor/core': 0.1.0(live-compositor@0.1.0(react@18.3.1))(react@18.3.1) + fs-extra: 11.2.0 + node-fetch: 2.7.0 + tar: 7.4.3 + uuid: 10.0.0 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - encoding + - live-compositor + - react + - utf-8-validate + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.1.1': {} + + '@rtsao/scc@1.1.0': {} + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/estree@1.0.6': {} + + '@types/fs-extra@11.0.4': + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 20.16.11 + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/jsonfile@6.1.4': + dependencies: + '@types/node': 20.16.11 + + '@types/lodash@4.17.10': {} + + '@types/node-fetch@2.6.11': + dependencies: + '@types/node': 20.16.11 + form-data: 4.0.1 + + '@types/node@20.16.11': + dependencies: + undici-types: 6.19.8 + + '@types/prop-types@15.7.13': {} + + '@types/react@18.3.11': + dependencies: + '@types/prop-types': 15.7.13 + csstype: 3.1.3 + + '@typescript-eslint/eslint-plugin@8.8.1(@typescript-eslint/parser@8.8.1(eslint@9.12.0)(typescript@5.6.3))(eslint@9.12.0)(typescript@5.6.3)': + dependencies: + '@eslint-community/regexpp': 4.11.1 + '@typescript-eslint/parser': 8.8.1(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.8.1 + '@typescript-eslint/type-utils': 8.8.1(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.8.1(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.8.1 + eslint: 9.12.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/eslint-plugin@8.9.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint@9.12.0)(typescript@5.6.3)': + dependencies: + '@eslint-community/regexpp': 4.11.1 + '@typescript-eslint/parser': 8.9.0(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.9.0 + '@typescript-eslint/type-utils': 8.9.0(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.9.0(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.9.0 + eslint: 9.12.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.8.1(eslint@9.12.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.8.1 + '@typescript-eslint/types': 8.8.1 + '@typescript-eslint/typescript-estree': 8.8.1(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.8.1 + debug: 4.3.7 + eslint: 9.12.0 + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.9.0 + '@typescript-eslint/types': 8.9.0 + '@typescript-eslint/typescript-estree': 8.9.0(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.9.0 + debug: 4.3.7 + eslint: 9.12.0 + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.8.1': + dependencies: + '@typescript-eslint/types': 8.8.1 + '@typescript-eslint/visitor-keys': 8.8.1 + + '@typescript-eslint/scope-manager@8.9.0': + dependencies: + '@typescript-eslint/types': 8.9.0 + '@typescript-eslint/visitor-keys': 8.9.0 + + '@typescript-eslint/type-utils@8.8.1(eslint@9.12.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.8.1(typescript@5.6.3) + '@typescript-eslint/utils': 8.8.1(eslint@9.12.0)(typescript@5.6.3) + debug: 4.3.7 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - eslint + - supports-color + + '@typescript-eslint/type-utils@8.9.0(eslint@9.12.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.9.0(typescript@5.6.3) + '@typescript-eslint/utils': 8.9.0(eslint@9.12.0)(typescript@5.6.3) + debug: 4.3.7 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - eslint + - supports-color + + '@typescript-eslint/types@8.8.1': {} + + '@typescript-eslint/types@8.9.0': {} + + '@typescript-eslint/typescript-estree@8.8.1(typescript@5.6.3)': + dependencies: + '@typescript-eslint/types': 8.8.1 + '@typescript-eslint/visitor-keys': 8.8.1 + debug: 4.3.7 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@8.9.0(typescript@5.6.3)': + dependencies: + '@typescript-eslint/types': 8.9.0 + '@typescript-eslint/visitor-keys': 8.9.0 + debug: 4.3.7 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.8.1(eslint@9.12.0)(typescript@5.6.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0) + '@typescript-eslint/scope-manager': 8.8.1 + '@typescript-eslint/types': 8.8.1 + '@typescript-eslint/typescript-estree': 8.8.1(typescript@5.6.3) + eslint: 9.12.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/utils@8.9.0(eslint@9.12.0)(typescript@5.6.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0) + '@typescript-eslint/scope-manager': 8.9.0 + '@typescript-eslint/types': 8.9.0 + '@typescript-eslint/typescript-estree': 8.9.0(typescript@5.6.3) + eslint: 9.12.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@8.8.1': + dependencies: + '@typescript-eslint/types': 8.8.1 + eslint-visitor-keys: 3.4.3 + + '@typescript-eslint/visitor-keys@8.9.0': + dependencies: + '@typescript-eslint/types': 8.9.0 + eslint-visitor-keys: 3.4.3 + + acorn-jsx@5.3.2(acorn@8.13.0): + dependencies: + acorn: 8.13.0 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.13.0 + + acorn@8.13.0: {} + + agent-base@4.3.0: + dependencies: + es6-promisify: 5.0.0 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + arg@4.1.3: {} + + argparse@2.0.1: {} + + array-buffer-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + + array.prototype.findlastindex@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.flat@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.flatmap@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + arraybuffer.prototype.slice@1.0.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + + async-limiter@1.0.1: {} + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + buffer-crc32@0.2.13: {} + + buffer-from@1.1.2: {} + + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + callsites@3.1.0: {} + + carlo@0.9.43: + dependencies: + debug: 4.3.7 + puppeteer-core: 1.20.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chownr@3.0.0: {} + + cli-color@2.0.4: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + memoizee: 0.4.17 + timers-ext: 0.1.8 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + concat-map@0.0.1: {} + + concat-stream@1.6.2: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + + core-util-is@1.0.3: {} + + create-require@1.1.1: {} + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + d@1.0.2: + dependencies: + es5-ext: 0.10.64 + type: 2.7.3 + + data-uri-to-buffer@4.0.1: {} + + data-view-buffer@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-offset@1.0.0: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.3.7: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + diff@4.0.2: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + eastasianwidth@0.2.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.17.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + es-abstract@1.23.3: + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.2 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.3 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.0.2: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + es5-ext@0.10.64: + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esniff: 2.0.1 + next-tick: 1.1.0 + + es6-iterator@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-symbol: 3.1.4 + + es6-promise@4.2.8: {} + + es6-promisify@5.0.0: + dependencies: + es6-promise: 4.2.8 + + es6-symbol@3.1.4: + dependencies: + d: 1.0.2 + ext: 1.7.0 + + es6-weak-map@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@9.1.0(eslint@9.12.0): + dependencies: + eslint: 9.12.0 + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.15.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@9.12.0): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.3.7 + enhanced-resolve: 5.17.1 + eslint: 9.12.0 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0) + fast-glob: 3.3.2 + get-tsconfig: 4.8.1 + is-bun-module: 1.2.1 + is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0) + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.9.0(eslint@9.12.0)(typescript@5.6.3) + eslint: 9.12.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@9.12.0) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.12.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0) + hasown: 2.0.2 + is-core-module: 2.15.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.9.0(eslint@9.12.0)(typescript@5.6.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.12.0))(eslint@9.12.0)(prettier@3.3.3): + dependencies: + eslint: 9.12.0 + prettier: 3.3.3 + prettier-linter-helpers: 1.0.0 + synckit: 0.9.2 + optionalDependencies: + eslint-config-prettier: 9.1.0(eslint@9.12.0) + + eslint-plugin-react-hooks@5.0.0(eslint@9.12.0): + dependencies: + eslint: 9.12.0 + + eslint-scope@8.1.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.1.0: {} + + eslint@9.12.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0) + '@eslint-community/regexpp': 4.11.1 + '@eslint/config-array': 0.18.0 + '@eslint/core': 0.6.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.12.0 + '@eslint/plugin-kit': 0.2.0 + '@humanfs/node': 0.16.5 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.3.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.7 + escape-string-regexp: 4.0.0 + eslint-scope: 8.1.0 + eslint-visitor-keys: 4.1.0 + espree: 10.2.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + esniff@2.0.1: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + event-emitter: 0.3.5 + type: 2.7.3 + + espree@10.2.0: + dependencies: + acorn: 8.13.0 + acorn-jsx: 5.3.2(acorn@8.13.0) + eslint-visitor-keys: 4.1.0 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + event-emitter@0.3.5: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + + ext@1.7.0: + dependencies: + type: 2.7.3 + + extract-zip@1.7.0: + dependencies: + concat-stream: 1.6.2 + debug: 2.6.9 + mkdirp: 0.5.6 + yauzl: 2.10.0 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + + flatted@3.3.1: {} + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + + function-bind@1.1.2: {} + + function.prototype.name@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + + functions-have-names@1.2.3: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-symbol-description@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + get-tsconfig@4.8.1: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@14.0.0: {} + + globals@15.11.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.0.2: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + https-proxy-agent@2.2.4: + dependencies: + agent-base: 4.3.0 + debug: 3.2.7 + transitivePeerDependencies: + - supports-color + + ignore@5.3.2: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + internal-slot@1.0.7: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + + is-array-buffer@3.0.4: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + is-bigint@1.0.4: + dependencies: + has-bigints: 1.0.2 + + is-boolean-object@1.1.2: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-bun-module@1.2.1: + dependencies: + semver: 7.6.3 + + is-callable@1.2.7: {} + + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-promise@2.2.2: {} + + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-to-typescript@14.1.0: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.7.2 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.10 + cli-color: 2.0.4 + glob: 10.4.5 + is-glob: 4.0.3 + js-yaml: 4.1.0 + lodash: 4.17.21 + minimist: 1.2.8 + mkdirp: 3.0.1 + node-fetch: 3.3.2 + prettier: 3.3.3 + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + live-compositor@0.1.0(react@18.3.1): + dependencies: + react: 18.3.1 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@10.4.3: {} + + lru-queue@0.1.0: + dependencies: + es5-ext: 0.10.64 + + make-error@1.3.6: {} + + memoizee@0.4.17: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-weak-map: 2.0.3 + event-emitter: 0.3.5 + is-promise: 2.2.2 + lru-queue: 0.1.0 + next-tick: 1.1.0 + timers-ext: 0.1.8 + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@2.6.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + minizlib@3.0.1: + dependencies: + minipass: 7.1.2 + rimraf: 5.0.10 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@3.0.1: {} + + ms@2.0.0: {} + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + next-tick@1.1.0: {} + + node-domexception@1.0.0: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + node-popup@0.1.14: + dependencies: + carlo: 0.9.43 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + object-inspect@1.13.2: {} + + object-keys@1.1.1: {} + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + + object.values@1.2.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + pend@1.2.0: {} + + picomatch@2.3.1: {} + + possible-typed-array-names@1.0.0: {} + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.3.3: {} + + process-nextick-args@2.0.1: {} + + progress@2.0.3: {} + + proxy-from-env@1.1.0: {} + + punycode@2.3.1: {} + + puppeteer-core@1.20.0: + dependencies: + debug: 4.3.7 + extract-zip: 1.7.0 + https-proxy-agent: 2.2.4 + mime: 2.6.0 + progress: 2.0.3 + proxy-from-env: 1.1.0 + rimraf: 2.7.1 + ws: 6.2.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + queue-microtask@1.2.3: {} + + react-reconciler@0.29.2(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + regexp.prototype.flags@1.5.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.8: + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.0.4: {} + + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + + rimraf@5.0.10: + dependencies: + glob: 10.4.5 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.2: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-regex-test@1.0.3: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + semver@6.3.1: {} + + semver@7.6.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 + + signal-exit@4.1.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string.prototype.trim@1.2.9: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + string.prototype.trimend@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + synckit@0.9.2: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.8.0 + + tapable@2.2.1: {} + + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.1 + mkdirp: 3.0.1 + yallist: 5.0.0 + + text-table@0.2.0: {} + + timers-ext@0.1.8: + dependencies: + es5-ext: 0.10.64 + next-tick: 1.1.0 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + ts-api-utils@1.3.0(typescript@5.6.3): + dependencies: + typescript: 5.6.3 + + ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.16.11 + acorn: 8.13.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.6.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.0: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type@2.7.3: {} + + typed-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + typed-array-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-byte-offset@1.0.2: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-length@1.0.6: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + + typedarray@0.0.6: {} + + typescript-eslint@8.8.1(eslint@9.12.0)(typescript@5.6.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.8.1(@typescript-eslint/parser@8.8.1(eslint@9.12.0)(typescript@5.6.3))(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/parser': 8.8.1(eslint@9.12.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.8.1(eslint@9.12.0)(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - eslint + - supports-color + + typescript@5.6.3: {} + + unbox-primitive@1.0.2: + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + + undici-types@6.19.8: {} + + universalify@2.0.1: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + uuid@10.0.0: {} + + v8-compile-cache-lib@3.0.1: {} + + web-streams-polyfill@3.3.3: {} + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-boxed-primitive@1.0.2: + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + + which-typed-array@1.1.15: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + ws@6.2.3: + dependencies: + async-limiter: 1.0.1 + + ws@8.18.0: {} + + yallist@5.0.0: {} + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} diff --git a/demos/tsconfig.json b/demos/tsconfig.json index 569e1ebdf..1897c55a1 100644 --- a/demos/tsconfig.json +++ b/demos/tsconfig.json @@ -1,13 +1,13 @@ { - "compilerOptions": { - "module": "commonjs", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "esModuleInterop": true, - "declaration": true, - "jsx": "react-jsx" - } + "compilerOptions": { + "module": "commonjs", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true, + "declaration": true, + "jsx": "react-jsx" + } } diff --git a/demos/utils/ffmpeg.ts b/demos/utils/ffmpeg.ts index bf08a1ce8..0c2e0b801 100644 --- a/demos/utils/ffmpeg.ts +++ b/demos/utils/ffmpeg.ts @@ -1,6 +1,7 @@ -import { SpawnPromise, sleepAsync, spawn } from './utils'; +import type { SpawnPromise } from './utils'; +import { sleepAsync, spawn } from './utils'; import path from 'path'; -import fs from 'fs-extra'; +import { mkdirp, writeFile } from 'fs-extra'; const COMPOSITOR_DIR = path.join(__dirname, '../.live_compositor'); @@ -9,7 +10,7 @@ export async function ffplayStartPlayerAsync( audio_port: number | undefined = undefined ): Promise { let sdpFilePath; - await fs.mkdirp(COMPOSITOR_DIR); + await mkdirp(COMPOSITOR_DIR); if (audio_port === undefined) { sdpFilePath = path.join(COMPOSITOR_DIR, `video_input_${video_port}.sdp`); await writeVideoSdpFile('127.0.0.1', video_port, sdpFilePath); @@ -75,7 +76,7 @@ async function writeVideoAudioSdpFile( audio_port: number, destination: string ): Promise { - await fs.writeFile( + await writeFile( destination, ` v=0 @@ -94,7 +95,7 @@ a=rtcp-mux } async function writeVideoSdpFile(ip: string, port: number, destination: string): Promise { - await fs.writeFile( + await writeFile( destination, ` v=0 diff --git a/demos/utils/utils.ts b/demos/utils/utils.ts index 9d1b4cb36..11fd18ad4 100644 --- a/demos/utils/utils.ts +++ b/demos/utils/utils.ts @@ -1,8 +1,9 @@ import fetch from 'node-fetch'; -import fs from 'fs-extra'; +import fs, { mkdirp } from 'fs-extra'; import { promisify } from 'util'; import { Stream } from 'stream'; -import { ChildProcess, spawn as nodeSpawn } from 'child_process'; +import type { ChildProcess } from 'child_process'; +import { spawn as nodeSpawn } from 'child_process'; import { cwd } from 'process'; import path from 'path'; @@ -68,7 +69,7 @@ export async function downloadAsync(url: string, destination: string): Promise= 400) { const err: any = new Error(`Request to ${url} failed. \n${response.body}`); diff --git a/docs/.prettierrc.js b/docs/.prettierrc.js new file mode 100644 index 000000000..6d74d8619 --- /dev/null +++ b/docs/.prettierrc.js @@ -0,0 +1,11 @@ +const config = { + printWidth: 100, + tabWidth: 2, + singleQuote: true, + bracketSameLine: true, + trailingComma: "es5", + arrowParens: "avoid", + endOfLine: "auto" +}; + +export default config; \ No newline at end of file diff --git a/ts/.eslintrc.base.json b/ts/.eslintrc.base.json deleted file mode 100644 index 693c84045..000000000 --- a/ts/.eslintrc.base.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:import/recommended", - "plugin:import/typescript", - "prettier" - ], - "plugins": [ - "import", - "prettier" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": [ - "tsconfig.json" - ] - }, - "settings": { - "import/parsers": { - "@typescript-eslint/parser": [".ts", ".tsx"] - }, - "import/resolver": { - "typescript": { - "alwaysTryTypes": true, - "project": "**/tsconfig.json" - } - } - }, - "rules": { - "prettier/prettier": ["error"], - "@typescript-eslint/no-explicit-any": [0, {}], - "@typescript-eslint/no-floating-promises": ["error"], - "no-constant-condition": [0], - "@typescript-eslint/no-unused-vars": [ - "error", - { - "args": "all", - "argsIgnorePattern": "^_", - "caughtErrors": "all", - "caughtErrorsIgnorePattern": "^_", - "destructuredArrayIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "ignoreRestSiblings": true - } - ] - } -} diff --git a/ts/.npmrc b/ts/.npmrc new file mode 100644 index 000000000..6143860f5 --- /dev/null +++ b/ts/.npmrc @@ -0,0 +1,2 @@ +hoist-pattern[]=!react +hoist-pattern[]=!react-dom diff --git a/ts/.prettierrc b/ts/.prettierrc deleted file mode 100644 index ca5392be9..000000000 --- a/ts/.prettierrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "printWidth": 100, - "tabWidth": 2, - "singleQuote": true, - "bracketSameLine": true, - "trailingComma": "es5", - "arrowParens": "avoid", - "endOfLine": "auto" -} diff --git a/ts/.prettierrc.js b/ts/.prettierrc.js new file mode 100644 index 000000000..74da53f68 --- /dev/null +++ b/ts/.prettierrc.js @@ -0,0 +1,9 @@ +export default { + printWidth: 100, + tabWidth: 2, + singleQuote: true, + bracketSameLine: true, + trailingComma: 'es5', + arrowParens: 'avoid', + endOfLine: 'auto', +}; diff --git a/ts/@live-compositor/browser-render/.eslintignore b/ts/@live-compositor/browser-render/.eslintignore deleted file mode 100644 index 4429bff24..000000000 --- a/ts/@live-compositor/browser-render/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -src/generated diff --git a/ts/@live-compositor/browser-render/.eslintrc.json b/ts/@live-compositor/browser-render/.eslintrc.json deleted file mode 100644 index ed5ec9dbf..000000000 --- a/ts/@live-compositor/browser-render/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "../../.eslintrc.base.json" - ] -} diff --git a/ts/@live-compositor/browser-render/package.json b/ts/@live-compositor/browser-render/package.json index fd1932dd8..f18e22334 100644 --- a/ts/@live-compositor/browser-render/package.json +++ b/ts/@live-compositor/browser-render/package.json @@ -9,7 +9,7 @@ "build-wasm": "node ./scripts/buildWasm.mjs", "build": "rollup -c", "clean": "rimraf dist", - "prepublishOnly": "npm run clean && npm run build-wasm && npm run build" + "prepublishOnly": "pnpm run clean && pnpm run build-wasm && pnpm run build" }, "author": "", "license": "BUSL-1.1", @@ -22,6 +22,6 @@ "wasm-pack": "^0.13.0" }, "peerDependencies": { - "live-compositor": "^0.1.0" + "live-compositor": "workspace:0.1.0" } } diff --git a/ts/@live-compositor/browser-render/src/api.ts b/ts/@live-compositor/browser-render/src/api.ts index 5072d0c98..fa338d693 100644 --- a/ts/@live-compositor/browser-render/src/api.ts +++ b/ts/@live-compositor/browser-render/src/api.ts @@ -1,4 +1,4 @@ -import { Api } from 'live-compositor'; +import type { Api } from 'live-compositor'; export type Resolution = Api.Resolution; export type ImageSpec = Required>; diff --git a/ts/@live-compositor/browser-render/src/renderer.ts b/ts/@live-compositor/browser-render/src/renderer.ts index b69f657bf..50ec76188 100644 --- a/ts/@live-compositor/browser-render/src/renderer.ts +++ b/ts/@live-compositor/browser-render/src/renderer.ts @@ -1,5 +1,5 @@ import { wasm } from './wasm'; -import * as Api from './api'; +import type * as Api from './api'; export type RendererOptions = { /** diff --git a/ts/@live-compositor/browser-render/tsconfig.json b/ts/@live-compositor/browser-render/tsconfig.json index 83ca55649..3a24fb090 100644 --- a/ts/@live-compositor/browser-render/tsconfig.json +++ b/ts/@live-compositor/browser-render/tsconfig.json @@ -1,14 +1,11 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", "module": "ESNext", "moduleResolution": "bundler", "target": "ESNext", - "noEmit": true, "declaration": false }, - "include": [ - "./src/**/*" - ] + "include": ["./src/**/*"] } diff --git a/ts/@live-compositor/core/.eslintignore b/ts/@live-compositor/core/.eslintignore deleted file mode 100644 index 55294f895..000000000 --- a/ts/@live-compositor/core/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -esm -cjs diff --git a/ts/@live-compositor/core/.eslintrc.json b/ts/@live-compositor/core/.eslintrc.json deleted file mode 100644 index ed5ec9dbf..000000000 --- a/ts/@live-compositor/core/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "../../.eslintrc.base.json" - ] -} diff --git a/ts/@live-compositor/core/package.json b/ts/@live-compositor/core/package.json index 498568ecd..a3dffef7f 100644 --- a/ts/@live-compositor/core/package.json +++ b/ts/@live-compositor/core/package.json @@ -12,14 +12,14 @@ "scripts": { "lint": "eslint .", "typecheck": "tsc --noEmit", - "watch": "concurrently \"npm run watch:esm\" \"npm run watch:cjs\"", + "watch": "concurrently \"pnpm run watch:esm\" \"pnpm run watch:cjs\"", "watch:esm": "tsc --watch --preserveWatchOutput", "watch:cjs": "tsc --watch --preserveWatchOutput -p ./tsconfig.cjs.json", - "build": "npm run build:esm && npm run build:cjs", + "build": "pnpm run build:esm && pnpm run build:cjs", "build:esm": "tsc && echo '{\"type\": \"module\"}' > esm/package.json", "build:cjs": "tsc -p ./tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > cjs/package.json", "clean": "rimraf esm cjs", - "prepublishOnly": "npm run clean && npm run build" + "prepublishOnly": "pnpm run clean && pnpm run build" }, "author": "", "license": "MIT", @@ -28,12 +28,14 @@ "/cjs" ], "devDependencies": { + "@types/react": "^18.3.3", "@types/react-reconciler": "0.28.8" }, "dependencies": { "react-reconciler": "0.29.2" }, "peerDependencies": { - "live-compositor": "^0.1.0" + "react": "*", + "live-compositor": "workspace:^0.1.0" } } diff --git a/ts/@live-compositor/core/src/api.ts b/ts/@live-compositor/core/src/api.ts index 5e99adf53..b2cd348f8 100644 --- a/ts/@live-compositor/core/src/api.ts +++ b/ts/@live-compositor/core/src/api.ts @@ -1,7 +1,7 @@ import { Api } from 'live-compositor'; -import { CompositorManager } from './compositorManager.js'; -import { RegisterOutputRequest } from './api/output.js'; -import { RegisterInputRequest } from './api/input.js'; +import type { CompositorManager } from './compositorManager.js'; +import type { RegisterOutputRequest } from './api/output.js'; +import type { RegisterInputRequest } from './api/input.js'; export { Api }; diff --git a/ts/@live-compositor/core/src/api/input.ts b/ts/@live-compositor/core/src/api/input.ts index 792ba7128..5c3048d3a 100644 --- a/ts/@live-compositor/core/src/api/input.ts +++ b/ts/@live-compositor/core/src/api/input.ts @@ -1,5 +1,5 @@ -import { Api } from '../api.js'; -import { RegisterMp4Input, RegisterRtpInput, Inputs } from 'live-compositor'; +import type { Api } from '../api.js'; +import type { RegisterMp4Input, RegisterRtpInput, Inputs } from 'live-compositor'; export type RegisterInputRequest = Api.RegisterInput; diff --git a/ts/@live-compositor/core/src/api/output.ts b/ts/@live-compositor/core/src/api/output.ts index 1a913bd2e..8708f0f04 100644 --- a/ts/@live-compositor/core/src/api/output.ts +++ b/ts/@live-compositor/core/src/api/output.ts @@ -1,4 +1,4 @@ -import { +import type { Api, Outputs, RegisterRtpOutput, diff --git a/ts/@live-compositor/core/src/api/renderer.ts b/ts/@live-compositor/core/src/api/renderer.ts index f75dff1e9..665cee075 100644 --- a/ts/@live-compositor/core/src/api/renderer.ts +++ b/ts/@live-compositor/core/src/api/renderer.ts @@ -1,5 +1,5 @@ -import { Api } from '../api.js'; -import { Renderers } from 'live-compositor'; +import type { Api } from '../api.js'; +import type { Renderers } from 'live-compositor'; export function intoRegisterImage(image: Renderers.RegisterImage): Api.ImageSpec { const source = { diff --git a/ts/@live-compositor/core/src/compositor.ts b/ts/@live-compositor/core/src/compositor.ts index f257e8e8b..e06c16f10 100644 --- a/ts/@live-compositor/core/src/compositor.ts +++ b/ts/@live-compositor/core/src/compositor.ts @@ -1,9 +1,12 @@ -import { _liveCompositorInternals, Renderers } from 'live-compositor'; +import type { Renderers } from 'live-compositor'; +import { _liveCompositorInternals } from 'live-compositor'; import { ApiClient } from './api.js'; import Output from './output.js'; -import { CompositorManager } from './compositorManager.js'; -import { intoRegisterOutput, RegisterOutput } from './api/output.js'; -import { intoRegisterInput, RegisterInput } from './api/input.js'; +import type { CompositorManager } from './compositorManager.js'; +import type { RegisterOutput } from './api/output.js'; +import { intoRegisterOutput } from './api/output.js'; +import type { RegisterInput } from './api/input.js'; +import { intoRegisterInput } from './api/input.js'; import { onCompositorEvent } from './event.js'; import { intoRegisterImage, intoRegisterWebRenderer } from './api/renderer.js'; diff --git a/ts/@live-compositor/core/src/compositorManager.ts b/ts/@live-compositor/core/src/compositorManager.ts index 6af287159..ebdcdca73 100644 --- a/ts/@live-compositor/core/src/compositorManager.ts +++ b/ts/@live-compositor/core/src/compositorManager.ts @@ -1,4 +1,4 @@ -import { ApiRequest } from './api.js'; +import type { ApiRequest } from './api.js'; export interface CompositorManager { setupInstance(): Promise; diff --git a/ts/@live-compositor/core/src/event.ts b/ts/@live-compositor/core/src/event.ts index a31145002..f1d6af766 100644 --- a/ts/@live-compositor/core/src/event.ts +++ b/ts/@live-compositor/core/src/event.ts @@ -1,4 +1,5 @@ -import { _liveCompositorInternals, CompositorEvent, CompositorEventType } from 'live-compositor'; +import type { _liveCompositorInternals, CompositorEvent } from 'live-compositor'; +import { CompositorEventType } from 'live-compositor'; type InstanceContextStore = _liveCompositorInternals.InstanceContextStore; diff --git a/ts/@live-compositor/core/src/output.ts b/ts/@live-compositor/core/src/output.ts index b97e95717..ee119ae99 100644 --- a/ts/@live-compositor/core/src/output.ts +++ b/ts/@live-compositor/core/src/output.ts @@ -1,8 +1,11 @@ -import { _liveCompositorInternals, View, Outputs } from 'live-compositor'; -import React, { useSyncExternalStore } from 'react'; -import { ApiClient, Api } from './api.js'; +import type { Outputs } from 'live-compositor'; +import { _liveCompositorInternals, View } from 'live-compositor'; +import type React from 'react'; +import { createElement, useSyncExternalStore } from 'react'; +import type { ApiClient, Api } from './api.js'; import Renderer from './renderer.js'; -import { intoAudioInputsConfiguration, RegisterOutput } from './api/output.js'; +import type { RegisterOutput } from './api/output.js'; +import { intoAudioInputsConfiguration } from './api/output.js'; import { throttle } from './utils.js'; type OutputContext = _liveCompositorInternals.OutputContext; @@ -42,7 +45,7 @@ class Output { this.outputCtx = new _liveCompositorInternals.OutputContext(onUpdate, hasAudio); if (registerRequest.video) { - const rootElement = React.createElement(OutputRootComponent, { + const rootElement = createElement(OutputRootComponent, { instanceStore: store, outputCtx: this.outputCtx, outputRoot: registerRequest.video.root, @@ -125,14 +128,14 @@ function OutputRootComponent({ if (shouldShutdown) { // replace root with view to stop all the dynamic code - return React.createElement(View, {}); + return createElement(View, {}); } const reactCtx = { instanceStore, outputCtx, }; - return React.createElement( + return createElement( _liveCompositorInternals.LiveCompositorContext.Provider, { value: reactCtx }, outputRoot diff --git a/ts/@live-compositor/core/src/renderer.ts b/ts/@live-compositor/core/src/renderer.ts index c4b500e92..acabcb230 100644 --- a/ts/@live-compositor/core/src/renderer.ts +++ b/ts/@live-compositor/core/src/renderer.ts @@ -1,8 +1,9 @@ +// eslint-disable-next-line import/no-named-as-default import Reconciler from 'react-reconciler'; import { DefaultEventPriority, LegacyRoot } from 'react-reconciler/constants.js'; -import { Api } from './api.js'; -import { _liveCompositorInternals } from 'live-compositor'; -import React from 'react'; +import type { Api } from './api.js'; +import type { _liveCompositorInternals } from 'live-compositor'; +import type React from 'react'; type SceneBuilder

= _liveCompositorInternals.SceneBuilder

; type SceneComponent = _liveCompositorInternals.SceneComponent; diff --git a/ts/@live-compositor/core/tsconfig.cjs.json b/ts/@live-compositor/core/tsconfig.cjs.json index 9513b5819..79d0bd8c5 100644 --- a/ts/@live-compositor/core/tsconfig.cjs.json +++ b/ts/@live-compositor/core/tsconfig.cjs.json @@ -1,6 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { + "target": "ES2016", "outDir": "cjs", "module": "commonjs", "moduleResolution": "node", diff --git a/ts/@live-compositor/core/tsconfig.json b/ts/@live-compositor/core/tsconfig.json index 738a96a32..eb9bfd6cf 100644 --- a/ts/@live-compositor/core/tsconfig.json +++ b/ts/@live-compositor/core/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "esm" } diff --git a/ts/@live-compositor/node/.eslintignore b/ts/@live-compositor/node/.eslintignore deleted file mode 100644 index 1521c8b76..000000000 --- a/ts/@live-compositor/node/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/ts/@live-compositor/node/.eslintrc.json b/ts/@live-compositor/node/.eslintrc.json deleted file mode 100644 index ed5ec9dbf..000000000 --- a/ts/@live-compositor/node/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "../../.eslintrc.base.json" - ] -} diff --git a/ts/@live-compositor/node/package.json b/ts/@live-compositor/node/package.json index dacd01542..5339dfbb8 100644 --- a/ts/@live-compositor/node/package.json +++ b/ts/@live-compositor/node/package.json @@ -9,7 +9,7 @@ "watch": "tsc --watch --preserveWatchOutput", "build": "tsc", "clean": "rimraf dist", - "prepublishOnly": "npm run clean && npm run build" + "prepublishOnly": "pnpm run clean && pnpm run build" }, "author": "", "license": "MIT", @@ -24,7 +24,7 @@ "@types/ws": "^8.5.12" }, "dependencies": { - "@live-compositor/core": "^0.1.0", + "@live-compositor/core": "workspace:^0.1.0", "fs-extra": "^11.2.0", "node-fetch": "^2.6.7", "tar": "^7.4.3", diff --git a/ts/@live-compositor/node/src/fetch.ts b/ts/@live-compositor/node/src/fetch.ts index 37f009a03..c73c5744a 100644 --- a/ts/@live-compositor/node/src/fetch.ts +++ b/ts/@live-compositor/node/src/fetch.ts @@ -5,7 +5,7 @@ import { Stream } from 'stream'; import { promisify } from 'util'; import fetch from 'node-fetch'; -import { ApiRequest } from '@live-compositor/core'; +import type { ApiRequest } from '@live-compositor/core'; const pipeline = promisify(Stream.pipeline); const httpAgent = new http.Agent({ keepAlive: true }); diff --git a/ts/@live-compositor/node/src/index.ts b/ts/@live-compositor/node/src/index.ts index 716ba8aec..60614db7f 100644 --- a/ts/@live-compositor/node/src/index.ts +++ b/ts/@live-compositor/node/src/index.ts @@ -1,4 +1,5 @@ -import { LiveCompositor as CoreLiveCompositor, CompositorManager } from '@live-compositor/core'; +import type { CompositorManager } from '@live-compositor/core'; +import { LiveCompositor as CoreLiveCompositor } from '@live-compositor/core'; import LocallySpawnedInstance from './manager/locallySpawnedInstance'; import ExistingInstance from './manager/existingInstance'; diff --git a/ts/@live-compositor/node/src/manager/existingInstance.ts b/ts/@live-compositor/node/src/manager/existingInstance.ts index fd7d78ad4..3ea881de4 100644 --- a/ts/@live-compositor/node/src/manager/existingInstance.ts +++ b/ts/@live-compositor/node/src/manager/existingInstance.ts @@ -1,4 +1,4 @@ -import { ApiRequest, CompositorManager } from '@live-compositor/core'; +import type { ApiRequest, CompositorManager } from '@live-compositor/core'; import { sendRequest } from '../fetch'; import { retry, sleep } from '../utils'; diff --git a/ts/@live-compositor/node/src/manager/locallySpawnedInstance.ts b/ts/@live-compositor/node/src/manager/locallySpawnedInstance.ts index 7a7aea9eb..2d97f06e7 100644 --- a/ts/@live-compositor/node/src/manager/locallySpawnedInstance.ts +++ b/ts/@live-compositor/node/src/manager/locallySpawnedInstance.ts @@ -2,9 +2,9 @@ import os from 'os'; import path from 'path'; import { v4 as uuidv4 } from 'uuid'; -import fs from 'fs-extra'; +import * as fs from 'fs-extra'; import * as tar from 'tar'; -import { ApiRequest, CompositorManager } from '@live-compositor/core'; +import type { ApiRequest, CompositorManager } from '@live-compositor/core'; import { download, sendRequest } from '../fetch'; import { retry, sleep } from '../utils'; diff --git a/ts/@live-compositor/node/src/spawn.ts b/ts/@live-compositor/node/src/spawn.ts index ff30811e8..ecc138a2d 100644 --- a/ts/@live-compositor/node/src/spawn.ts +++ b/ts/@live-compositor/node/src/spawn.ts @@ -1,4 +1,5 @@ -import { ChildProcess, SpawnOptions, spawn as nodeSpawn } from 'child_process'; +import type { ChildProcess, SpawnOptions } from 'child_process'; +import { spawn as nodeSpawn } from 'child_process'; export interface SpawnPromise extends Promise { child: ChildProcess; diff --git a/ts/@live-compositor/node/tsconfig.json b/ts/@live-compositor/node/tsconfig.json index 4e94ea868..b4e69ae1f 100644 --- a/ts/@live-compositor/node/tsconfig.json +++ b/ts/@live-compositor/node/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist" } diff --git a/ts/@live-compositor/web-wasm/.eslintignore b/ts/@live-compositor/web-wasm/.eslintignore deleted file mode 100644 index 1521c8b76..000000000 --- a/ts/@live-compositor/web-wasm/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/ts/@live-compositor/web-wasm/.eslintrc.json b/ts/@live-compositor/web-wasm/.eslintrc.json deleted file mode 100644 index ed5ec9dbf..000000000 --- a/ts/@live-compositor/web-wasm/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "../../.eslintrc.base.json" - ] -} diff --git a/ts/@live-compositor/web-wasm/package.json b/ts/@live-compositor/web-wasm/package.json index 10b05c804..04b2a5f0c 100644 --- a/ts/@live-compositor/web-wasm/package.json +++ b/ts/@live-compositor/web-wasm/package.json @@ -9,7 +9,7 @@ "watch": "tsc --watch --preserveWatchOutput", "build": "tsc", "clean": "rimraf dist", - "prepublishOnly": "npm run clean && npm run build" + "prepublishOnly": "pnpm run clean && pnpm run build" }, "author": "", "license": "MIT", @@ -18,10 +18,13 @@ ], "dependencies": { "@datastructures-js/queue": "^4.2.3", - "@live-compositor/browser-render": "0.1.0-rc.4", - "@live-compositor/core": "0.1.0", - "live-compositor": "^0.1.0", + "@live-compositor/browser-render": "workspace:0.1.0-rc.4", + "@live-compositor/core": "workspace:0.1.0", + "live-compositor": "workspace:^0.1.0", "mp4box": "^0.5.2", "path-parser": "^6.1.0" + }, + "devDependencies": { + "@types/react": "^18.3.3" } } diff --git a/ts/@live-compositor/web-wasm/src/compositor.ts b/ts/@live-compositor/web-wasm/src/compositor.ts index 40ade2f38..18beb9bb8 100644 --- a/ts/@live-compositor/web-wasm/src/compositor.ts +++ b/ts/@live-compositor/web-wasm/src/compositor.ts @@ -1,9 +1,11 @@ import { Renderer } from '@live-compositor/browser-render'; import { LiveCompositor as CoreLiveCompositor } from '@live-compositor/core'; import WasmInstance from './manager/wasmInstance'; -import { intoRegisterOutput, RegisterOutput } from './output/registerOutput'; -import { intoRegisterInput, RegisterInput } from './input/registerInput'; -import { RegisterImage } from './renderers'; +import type { RegisterOutput } from './output/registerOutput'; +import { intoRegisterOutput } from './output/registerOutput'; +import type { RegisterInput } from './input/registerInput'; +import { intoRegisterInput } from './input/registerInput'; +import type { RegisterImage } from './renderers'; export type LiveCompositorOptions = { framerate?: Framerate; diff --git a/ts/@live-compositor/web-wasm/src/eventSender.ts b/ts/@live-compositor/web-wasm/src/eventSender.ts index 048850760..5bcd33758 100644 --- a/ts/@live-compositor/web-wasm/src/eventSender.ts +++ b/ts/@live-compositor/web-wasm/src/eventSender.ts @@ -1,4 +1,5 @@ -import { CompositorEvent, CompositorEventType } from 'live-compositor'; +import type { CompositorEvent } from 'live-compositor'; +import { CompositorEventType } from 'live-compositor'; export class EventSender { private eventCallback?: (event: object) => void; diff --git a/ts/@live-compositor/web-wasm/src/input/input.ts b/ts/@live-compositor/web-wasm/src/input/input.ts index 1069caaa0..b8c756a33 100644 --- a/ts/@live-compositor/web-wasm/src/input/input.ts +++ b/ts/@live-compositor/web-wasm/src/input/input.ts @@ -1,7 +1,7 @@ -import { Frame, InputId } from '@live-compositor/browser-render'; +import type { Frame, InputId } from '@live-compositor/browser-render'; import { CompositorEventType } from 'live-compositor'; -import { EventSender } from '../eventSender'; -import InputSource from './source'; +import type { EventSender } from '../eventSender'; +import type InputSource from './source'; /** * Represents frame produced by decoder. diff --git a/ts/@live-compositor/web-wasm/src/input/mp4/demuxer.ts b/ts/@live-compositor/web-wasm/src/input/mp4/demuxer.ts index f78a6bc44..47338d63a 100644 --- a/ts/@live-compositor/web-wasm/src/input/mp4/demuxer.ts +++ b/ts/@live-compositor/web-wasm/src/input/mp4/demuxer.ts @@ -1,4 +1,5 @@ -import MP4Box, { DataStream, MP4ArrayBuffer, MP4File, MP4Info, Sample } from 'mp4box'; +import type { MP4ArrayBuffer, MP4File, MP4Info, Sample } from 'mp4box'; +import MP4Box, { DataStream } from 'mp4box'; export type OnConfig = (config: VideoDecoderConfig) => void; diff --git a/ts/@live-compositor/web-wasm/src/input/mp4/source.ts b/ts/@live-compositor/web-wasm/src/input/mp4/source.ts index 42e9d48da..61a864b28 100644 --- a/ts/@live-compositor/web-wasm/src/input/mp4/source.ts +++ b/ts/@live-compositor/web-wasm/src/input/mp4/source.ts @@ -1,8 +1,8 @@ import { FrameFormat } from '@live-compositor/browser-render'; import { MP4Demuxer } from './demuxer'; import { H264Decoder } from '../decoder/h264Decoder'; -import { InputFrame } from '../input'; -import InputSource from '../source'; +import type { InputFrame } from '../input'; +import type InputSource from '../source'; export default class MP4Source implements InputSource { private fileUrl: string; diff --git a/ts/@live-compositor/web-wasm/src/input/registerInput.ts b/ts/@live-compositor/web-wasm/src/input/registerInput.ts index 1e0693593..cae44cd9a 100644 --- a/ts/@live-compositor/web-wasm/src/input/registerInput.ts +++ b/ts/@live-compositor/web-wasm/src/input/registerInput.ts @@ -1,4 +1,4 @@ -import { RegisterInput as InternalRegisterInput } from '@live-compositor/core'; +import type { RegisterInput as InternalRegisterInput } from '@live-compositor/core'; export type RegisterInput = { type: 'mp4' } & RegisterMP4Input; diff --git a/ts/@live-compositor/web-wasm/src/input/source.ts b/ts/@live-compositor/web-wasm/src/input/source.ts index 47dac36b0..13269be1f 100644 --- a/ts/@live-compositor/web-wasm/src/input/source.ts +++ b/ts/@live-compositor/web-wasm/src/input/source.ts @@ -1,5 +1,5 @@ -import { RegisterInputRequest } from '@live-compositor/core'; -import { InputFrame } from './input'; +import type { RegisterInputRequest } from '@live-compositor/core'; +import type { InputFrame } from './input'; import MP4Source from './mp4/source'; export default interface InputSource { diff --git a/ts/@live-compositor/web-wasm/src/manager/wasmInstance.ts b/ts/@live-compositor/web-wasm/src/manager/wasmInstance.ts index da18d3778..454dc8597 100644 --- a/ts/@live-compositor/web-wasm/src/manager/wasmInstance.ts +++ b/ts/@live-compositor/web-wasm/src/manager/wasmInstance.ts @@ -1,16 +1,17 @@ -import { +import type { ApiRequest, CompositorManager, RegisterInputRequest, RegisterOutputRequest, } from '@live-compositor/core'; -import { Renderer, Component, ImageSpec } from '@live-compositor/browser-render'; -import { Api } from 'live-compositor'; +import type { Renderer, Component, ImageSpec } from '@live-compositor/browser-render'; +import type { Api } from 'live-compositor'; import { Path } from 'path-parser'; -import { Queue, StopQueueFn } from '../queue'; +import type { StopQueueFn } from '../queue'; +import { Queue } from '../queue'; import { Input } from '../input/input'; import { EventSender } from '../eventSender'; -import { Framerate } from '../compositor'; +import type { Framerate } from '../compositor'; import { Output } from '../output/output'; import { sourceFromRequest } from '../input/source'; diff --git a/ts/@live-compositor/web-wasm/src/output/canvas.ts b/ts/@live-compositor/web-wasm/src/output/canvas.ts index 3def53a6c..5c7c0f7c1 100644 --- a/ts/@live-compositor/web-wasm/src/output/canvas.ts +++ b/ts/@live-compositor/web-wasm/src/output/canvas.ts @@ -1,5 +1,5 @@ -import { Frame } from '@live-compositor/browser-render'; -import { OutputSink } from './sink'; +import type { Frame } from '@live-compositor/browser-render'; +import type { OutputSink } from './sink'; export default class CanvasSink implements OutputSink { private ctx: CanvasRenderingContext2D; diff --git a/ts/@live-compositor/web-wasm/src/output/output.ts b/ts/@live-compositor/web-wasm/src/output/output.ts index 0a9682486..236106c75 100644 --- a/ts/@live-compositor/web-wasm/src/output/output.ts +++ b/ts/@live-compositor/web-wasm/src/output/output.ts @@ -1,7 +1,7 @@ -import { Frame, Resolution } from '@live-compositor/browser-render'; -import { OutputSink } from './sink'; +import type { Frame, Resolution } from '@live-compositor/browser-render'; +import type { OutputSink } from './sink'; import CanvasSink from './canvas'; -import { RegisterOutputRequest } from '@live-compositor/core'; +import type { RegisterOutputRequest } from '@live-compositor/core'; export class Output { private sink: OutputSink; diff --git a/ts/@live-compositor/web-wasm/src/output/registerOutput.ts b/ts/@live-compositor/web-wasm/src/output/registerOutput.ts index 87d37b1d8..c40682280 100644 --- a/ts/@live-compositor/web-wasm/src/output/registerOutput.ts +++ b/ts/@live-compositor/web-wasm/src/output/registerOutput.ts @@ -1,12 +1,13 @@ -import { Resolution } from '@live-compositor/browser-render'; -import { RegisterOutput as InternalRegisterOutput } from '@live-compositor/core'; +import type { Resolution } from '@live-compositor/browser-render'; +import type { RegisterOutput as InternalRegisterOutput } from '@live-compositor/core'; +import type { ReactElement } from 'react'; export type RegisterOutput = { type: 'canvas' } & RegisterCanvasOutput; export type RegisterCanvasOutput = { resolution: Resolution; canvas: HTMLCanvasElement; - root: React.ReactElement; + root: ReactElement; }; export function intoRegisterOutput(output: RegisterOutput): InternalRegisterOutput { diff --git a/ts/@live-compositor/web-wasm/src/output/sink.ts b/ts/@live-compositor/web-wasm/src/output/sink.ts index 8d7677d55..7f113a546 100644 --- a/ts/@live-compositor/web-wasm/src/output/sink.ts +++ b/ts/@live-compositor/web-wasm/src/output/sink.ts @@ -1,4 +1,4 @@ -import { Frame } from '@live-compositor/browser-render'; +import type { Frame } from '@live-compositor/browser-render'; export interface OutputSink { send(frame: Frame): Promise; diff --git a/ts/@live-compositor/web-wasm/src/queue.ts b/ts/@live-compositor/web-wasm/src/queue.ts index b15e2f482..390026b36 100644 --- a/ts/@live-compositor/web-wasm/src/queue.ts +++ b/ts/@live-compositor/web-wasm/src/queue.ts @@ -1,7 +1,7 @@ -import { FrameSet, InputId, OutputId, Renderer } from '@live-compositor/browser-render'; -import { Framerate } from './compositor'; -import { Input, InputFrame } from './input/input'; -import { Output } from './output/output'; +import type { FrameSet, InputId, OutputId, Renderer } from '@live-compositor/browser-render'; +import type { Framerate } from './compositor'; +import type { Input, InputFrame } from './input/input'; +import type { Output } from './output/output'; export type StopQueueFn = () => void; diff --git a/ts/@live-compositor/web-wasm/src/renderers.ts b/ts/@live-compositor/web-wasm/src/renderers.ts index dd5db0cb8..4112db962 100644 --- a/ts/@live-compositor/web-wasm/src/renderers.ts +++ b/ts/@live-compositor/web-wasm/src/renderers.ts @@ -1,3 +1,3 @@ -import { Renderers } from 'live-compositor'; +import type { Renderers } from 'live-compositor'; export type RegisterImage = Required>; diff --git a/ts/@live-compositor/web-wasm/tsconfig.json b/ts/@live-compositor/web-wasm/tsconfig.json index 91458fd4f..f73765f19 100644 --- a/ts/@live-compositor/web-wasm/tsconfig.json +++ b/ts/@live-compositor/web-wasm/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", "module": "ESNext", diff --git a/ts/create-live-compositor/.eslintignore b/ts/create-live-compositor/.eslintignore deleted file mode 100644 index 0d842b9e0..000000000 --- a/ts/create-live-compositor/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -templates diff --git a/ts/create-live-compositor/.eslintrc.json b/ts/create-live-compositor/.eslintrc.json deleted file mode 100644 index b80891633..000000000 --- a/ts/create-live-compositor/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "../.eslintrc.base.json" - ] -} diff --git a/ts/create-live-compositor/package.json b/ts/create-live-compositor/package.json index 63ed00d4b..53e4ccd5e 100644 --- a/ts/create-live-compositor/package.json +++ b/ts/create-live-compositor/package.json @@ -4,12 +4,12 @@ "description": "", "main": "dist/index.js", "scripts": { - "lint": "eslint .", + "lint": "eslint src", "typecheck": "tsc --noEmit", "watch": "tsc --watch --preserveWatchOutput", "build": "tsc", "clean": "rimraf dist", - "prepublishOnly": "npm run clean && npm run build" + "prepublishOnly": "pnpm run clean && pnpm run build" }, "author": "", "license": "MIT", diff --git a/ts/create-live-compositor/src/createNodeProject.ts b/ts/create-live-compositor/src/createNodeProject.ts index 8295695ae..b028cf35b 100644 --- a/ts/create-live-compositor/src/createNodeProject.ts +++ b/ts/create-live-compositor/src/createNodeProject.ts @@ -1,4 +1,4 @@ -import { ProjectOptions } from './options'; +import type { ProjectOptions } from './options'; import { ensureProjectDir } from './utils/workingdir'; import { runPackageManagerInstall } from './utils/packageManager'; import { applyTemplate } from './template'; diff --git a/ts/create-live-compositor/src/options.ts b/ts/create-live-compositor/src/options.ts index 2eca58f74..21fc8c8b9 100644 --- a/ts/create-live-compositor/src/options.ts +++ b/ts/create-live-compositor/src/options.ts @@ -1,6 +1,7 @@ -import { Choice, confirmPrompt, selectPrompt, textPrompt } from './utils/prompts'; +import type { Choice } from './utils/prompts'; +import { confirmPrompt, selectPrompt, textPrompt } from './utils/prompts'; import path from 'path'; -import { PackageManager } from './utils/packageManager'; +import type { PackageManager } from './utils/packageManager'; import { spawn } from './utils/spawn'; import chalk from 'chalk'; diff --git a/ts/create-live-compositor/src/template.ts b/ts/create-live-compositor/src/template.ts index ef100aa26..3fb22feeb 100644 --- a/ts/create-live-compositor/src/template.ts +++ b/ts/create-live-compositor/src/template.ts @@ -1,4 +1,4 @@ -import fs from 'fs-extra'; +import * as fs from 'fs-extra'; import path from 'path'; const TEMPLATES_ROOT = path.join(__dirname, '../templates'); diff --git a/ts/create-live-compositor/src/utils/prompts.ts b/ts/create-live-compositor/src/utils/prompts.ts index 6a573da67..af05f6757 100644 --- a/ts/create-live-compositor/src/utils/prompts.ts +++ b/ts/create-live-compositor/src/utils/prompts.ts @@ -1,5 +1,6 @@ import { constants } from 'os'; -import prompts, { Answers, Options, Choice as PromptChoice, PromptObject } from 'prompts'; +import type { Answers, Options, Choice as PromptChoice, PromptObject } from 'prompts'; +import { prompt } from 'prompts'; export interface Choice extends PromptChoice { value: T; @@ -9,7 +10,7 @@ async function promptWrapper( questions: PromptObject | Array>, options?: Options ): Promise> { - return await prompts(questions, { + return await prompt(questions, { onCancel() { process.exit(constants.signals.SIGINT + 128); // Exit code 130 used when process is interrupted with ctrl+c. }, diff --git a/ts/create-live-compositor/src/utils/spawn.ts b/ts/create-live-compositor/src/utils/spawn.ts index 8eeb8ea13..baf337700 100644 --- a/ts/create-live-compositor/src/utils/spawn.ts +++ b/ts/create-live-compositor/src/utils/spawn.ts @@ -1,4 +1,5 @@ -import { ChildProcess, SpawnOptions, spawn as nodeSpawn } from 'child_process'; +import type { ChildProcess, SpawnOptions } from 'child_process'; +import { spawn as nodeSpawn } from 'child_process'; export interface SpawnPromise extends Promise<{ stdout?: string; stderr?: string }> { child: ChildProcess; diff --git a/ts/create-live-compositor/src/utils/workingdir.ts b/ts/create-live-compositor/src/utils/workingdir.ts index f9ad5c186..c9a2ef28c 100644 --- a/ts/create-live-compositor/src/utils/workingdir.ts +++ b/ts/create-live-compositor/src/utils/workingdir.ts @@ -1,4 +1,4 @@ -import fs from 'fs-extra'; +import * as fs from 'fs-extra'; import { confirmPrompt } from './prompts'; export async function ensureProjectDir(directory: string) { diff --git a/ts/create-live-compositor/templates/node-express-zustand/package.json b/ts/create-live-compositor/templates/node-express-zustand/package.json index e528d8d9f..84914d87d 100644 --- a/ts/create-live-compositor/templates/node-express-zustand/package.json +++ b/ts/create-live-compositor/templates/node-express-zustand/package.json @@ -7,19 +7,19 @@ "license": "MIT", "scripts": { "start": "ts-node ./src/index.ts", - "build": "tsc" + "build": "tsc", + "lint": "eslint ." }, "dependencies": { - "@live-compositor/node": "^0.1.0", + "@live-compositor/node": "workspace:^0.1.0", "express": "^4.21.0", - "live-compositor": "^0.1.0", + "live-compositor": "workspace:^0.1.0", "react": "^18.3.1", "zustand": "4.5.5" }, "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.14.10", - "@types/react": "^18.3.3", - "typescript": "^5.5.3" + "@types/react": "^18.3.3" } } diff --git a/ts/create-live-compositor/templates/node-express-zustand/src/liveCompositorFfplayHelper.ts b/ts/create-live-compositor/templates/node-express-zustand/src/liveCompositorFfplayHelper.ts index 990951311..4eb1241c0 100644 --- a/ts/create-live-compositor/templates/node-express-zustand/src/liveCompositorFfplayHelper.ts +++ b/ts/create-live-compositor/templates/node-express-zustand/src/liveCompositorFfplayHelper.ts @@ -1,7 +1,8 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; -import { ChildProcess, spawn as nodeSpawn, SpawnOptions } from 'child_process'; +import type { ChildProcess, SpawnOptions } from 'child_process'; +import { spawn as nodeSpawn } from 'child_process'; const TMP_SDP_DIR = path.join(os.tmpdir(), 'live-composiotor-sdp'); diff --git a/ts/create-live-compositor/templates/node-express-zustand/src/routes.ts b/ts/create-live-compositor/templates/node-express-zustand/src/routes.ts index 9be6f98cc..2d60cae90 100644 --- a/ts/create-live-compositor/templates/node-express-zustand/src/routes.ts +++ b/ts/create-live-compositor/templates/node-express-zustand/src/routes.ts @@ -1,8 +1,9 @@ +import type { Express } from 'express'; import express, { json } from 'express'; import { Compositor } from './compositor'; import { store } from './store'; -export const app = express(); +export const app: Express = express(); app.use(json()); diff --git a/ts/create-live-compositor/templates/node-minimal/package.json b/ts/create-live-compositor/templates/node-minimal/package.json index 140b6e47f..de646f9f7 100644 --- a/ts/create-live-compositor/templates/node-minimal/package.json +++ b/ts/create-live-compositor/templates/node-minimal/package.json @@ -7,11 +7,12 @@ "license": "MIT", "scripts": { "start": "ts-node ./src/App.tsx", - "build": "tsc" + "build": "tsc", + "lint": "eslint ." }, "dependencies": { - "@live-compositor/node": "^0.1.0", - "live-compositor": "^0.1.0", + "@live-compositor/node": "workspace:^0.1.0", + "live-compositor": "workspace:^0.1.0", "react": "^18.3.1" }, "devDependencies": { diff --git a/ts/create-live-compositor/templates/node-minimal/src/index.tsx b/ts/create-live-compositor/templates/node-minimal/src/index.tsx index 3fb0890f3..92abd2f63 100644 --- a/ts/create-live-compositor/templates/node-minimal/src/index.tsx +++ b/ts/create-live-compositor/templates/node-minimal/src/index.tsx @@ -9,8 +9,8 @@ function App() { Open index.ts and get started - This example renders static text and sends the output stream via RTP to local port - 8001. Generated code includes helpers in liveCompositorFfplayHelper.ts that display the output + This example renders static text and sends the output stream via RTP to local port 8001. + Generated code includes helpers in liveCompositorFfplayHelper.ts that display the output stream using ffplay, make sure to remove them for any real production use. diff --git a/ts/create-live-compositor/templates/node-minimal/src/liveCompositorFfplayHelper.ts b/ts/create-live-compositor/templates/node-minimal/src/liveCompositorFfplayHelper.ts index d6229fe54..f7a70823c 100644 --- a/ts/create-live-compositor/templates/node-minimal/src/liveCompositorFfplayHelper.ts +++ b/ts/create-live-compositor/templates/node-minimal/src/liveCompositorFfplayHelper.ts @@ -1,7 +1,8 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; -import { ChildProcess, spawn as nodeSpawn, SpawnOptions } from 'child_process'; +import type { ChildProcess, SpawnOptions } from 'child_process'; +import { spawn as nodeSpawn } from 'child_process'; const TMP_SDP_DIR = path.join(os.tmpdir(), 'live-composiotor-sdp'); diff --git a/ts/create-live-compositor/tsconfig.json b/ts/create-live-compositor/tsconfig.json index e95d8d0fd..a6da6b6cd 100644 --- a/ts/create-live-compositor/tsconfig.json +++ b/ts/create-live-compositor/tsconfig.json @@ -1,9 +1,7 @@ { - "extends": "../tsconfig.base.json", + "extends": "../tsconfig.json", "compilerOptions": { "outDir": "dist" }, - "include": [ - "./src/**/*" - ] + "include": ["src"] } diff --git a/ts/eslint.config.js b/ts/eslint.config.js new file mode 100644 index 000000000..2a94483a4 --- /dev/null +++ b/ts/eslint.config.js @@ -0,0 +1,102 @@ +import globals from 'globals'; + +import eslintRecommended from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +import pluginImport from 'eslint-plugin-import'; +import pluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; +import { plugin as tsEslintPlugin } from 'typescript-eslint'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; + +import tsParser from '@typescript-eslint/parser'; + +export default [ + eslintRecommended.configs.recommended, + pluginImport.flatConfigs.recommended, + pluginPrettierRecommended, + eslintConfigPrettier, + { + files: ['**/*.{js,jsx,ts,tsx}'], + ignores: ['.prettierrc.js'], + plugins: { + '@typescript-eslint': tsEslintPlugin, + }, + languageOptions: { + parser: tsParser, + parserOptions: { + project: [ + 'tsconfig.json', + '**/examples/vite-browser-render/tsconfig.node.json', + '**/examples/vite-browser-render/tsconfig.app.json', + ], + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + globals: { + ...globals.browser, + ...globals.node, + }, + }, + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + typescript: { + alwaysTryTypes: true, + project: '**/tsconfig.json', + }, + }, + }, + rules: { + 'prettier/prettier': ['error'], + 'import/no-unresolved': 'error', + '@typescript-eslint/no-explicit-any': [0, {}], + '@typescript-eslint/no-floating-promises': ['error'], + 'no-constant-condition': [0], + 'no-unused-vars': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true, + vars: 'local', + }, + ], + '@typescript-eslint/consistent-type-imports': [ + 'error', + { + prefer: 'type-imports', + }, + ], + }, + }, + { + files: ['examples/vite-browser-render/**/*.{ts,tsx}'], + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': ['error', { allowConstantExport: true }], + }, + }, + { + ignores: [ + '**/dist/**/*', + '**/cjs/**/*', + '**/esm/**/*', + '**/generated/**/*', + '**/*.d.ts', + '**/*.mjs', + ], + }, +]; diff --git a/ts/examples/README.md b/ts/examples/README.md index 521486ce7..90cd682b9 100644 --- a/ts/examples/README.md +++ b/ts/examples/README.md @@ -12,11 +12,11 @@ To launch any of the above examples go to `node-examples` directory and run: ```bash -npm run ts-node +pnpm run ts-node ``` e.g. ```bash -npm run ts-node ./src/simple.tsx +pnpm run ts-node ./src/simple.tsx ``` diff --git a/ts/examples/node-examples/.eslintignore b/ts/examples/node-examples/.eslintignore deleted file mode 100644 index 1521c8b76..000000000 --- a/ts/examples/node-examples/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/ts/examples/node-examples/.eslintrc.json b/ts/examples/node-examples/.eslintrc.json deleted file mode 100644 index ed5ec9dbf..000000000 --- a/ts/examples/node-examples/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "../../.eslintrc.base.json" - ] -} diff --git a/ts/examples/node-examples/package.json b/ts/examples/node-examples/package.json index d67373b74..487e9953d 100644 --- a/ts/examples/node-examples/package.json +++ b/ts/examples/node-examples/package.json @@ -15,12 +15,17 @@ "author": "", "license": "MIT", "dependencies": { - "@live-compositor/node": "^0.1.0", - "@types/fs-extra": "^11.0.4", - "@types/node": "^20.14.10", + "@live-compositor/node": "workspace:^0.1.0", "fs-extra": "^11.2.0", - "live-compositor": "^0.1.0", + "live-compositor": "workspace:^0.1.0", "node-fetch": "^2.6.7", + "react": "^18.3.1", "ts-node": "^10.9.2" + }, + "devDependencies": { + "@types/fs-extra": "^11.0.4", + "@types/node": "^20.14.10", + "@types/node-fetch": "^2.6.11", + "@types/react": "^18.3.3" } } diff --git a/ts/examples/node-examples/src/dynamic-outputs.tsx b/ts/examples/node-examples/src/dynamic-outputs.tsx index 9f4718498..fb1d7b04e 100644 --- a/ts/examples/node-examples/src/dynamic-outputs.tsx +++ b/ts/examples/node-examples/src/dynamic-outputs.tsx @@ -2,7 +2,7 @@ import LiveCompositor from '@live-compositor/node'; import { Text, InputStream, Tiles, Rescaler, View, useInputStreams } from 'live-compositor'; import { downloadAllAssets, gstReceiveTcpStream, sleep } from './utils'; import path from 'path'; -import fs from 'fs-extra'; +import { mkdirp } from 'fs-extra'; function ExampleApp() { const inputs = useInputStreams(); @@ -31,7 +31,7 @@ function InputTile({ inputId }: { inputId: string }) { } async function run() { - await fs.mkdirp(path.join(__dirname, '../.workingdir')); + await mkdirp(path.join(__dirname, '../.workingdir')); await downloadAllAssets(); const compositor = new LiveCompositor(); await compositor.init(); diff --git a/ts/examples/node-examples/src/utils.ts b/ts/examples/node-examples/src/utils.ts index d0d97683b..bb35367b9 100644 --- a/ts/examples/node-examples/src/utils.ts +++ b/ts/examples/node-examples/src/utils.ts @@ -1,6 +1,7 @@ import path from 'path'; -import fs from 'fs-extra'; -import { ChildProcess, spawn as nodeSpawn } from 'child_process'; +import fs, { mkdirp, pathExists, writeFile } from 'fs-extra'; +import type { ChildProcess } from 'child_process'; +import { spawn as nodeSpawn } from 'child_process'; import { promisify } from 'util'; import { Stream } from 'stream'; import fetch from 'node-fetch'; @@ -14,7 +15,7 @@ export async function ffplayStartPlayerAsync( video_port: number, audio_port: number | undefined = undefined ): Promise<{ spawn_promise: SpawnPromise }> { - await fs.mkdirp(TMP_SDP_DIR); + await mkdirp(TMP_SDP_DIR); let sdpFilePath; if (audio_port === undefined) { sdpFilePath = path.join(TMP_SDP_DIR, `video_input_${video_port}.sdp`); @@ -89,7 +90,7 @@ async function writeVideoAudioSdpFile( audio_port: number, destination: string ): Promise { - await fs.writeFile( + await writeFile( destination, ` v=0 @@ -108,7 +109,7 @@ a=rtcp-mux } async function writeVideoSdpFile(ip: string, port: number, destination: string): Promise { - await fs.writeFile( + await writeFile( destination, ` v=0 @@ -144,10 +145,10 @@ const exampleAssets = [ export async function downloadAllAssets(): Promise { const downloadDir = path.join(__dirname, '../.assets'); - await fs.mkdirp(downloadDir); + await mkdirp(downloadDir); for (const asset of exampleAssets) { - if (!(await fs.pathExists(path.join(downloadDir, asset.path)))) { + if (!(await pathExists(path.join(downloadDir, asset.path)))) { await download(asset.url, path.join(downloadDir, asset.path)); } } diff --git a/ts/examples/node-examples/tsconfig.json b/ts/examples/node-examples/tsconfig.json index f3274a1fb..7382eee8a 100644 --- a/ts/examples/node-examples/tsconfig.json +++ b/ts/examples/node-examples/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", "jsx": "react-jsx" diff --git a/ts/examples/vite-browser-render/eslint.config.js b/ts/examples/vite-browser-render/eslint.config.js deleted file mode 100644 index c973d7f03..000000000 --- a/ts/examples/vite-browser-render/eslint.config.js +++ /dev/null @@ -1,25 +0,0 @@ -import js from '@eslint/js'; -import globals from 'globals'; -import reactHooks from 'eslint-plugin-react-hooks'; -import reactRefresh from 'eslint-plugin-react-refresh'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config( - { ignores: ['dist'] }, - { - extends: [js.configs.recommended, ...tseslint.configs.recommended], - files: ['**/*.{ts,tsx}'], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - plugins: { - 'react-hooks': reactHooks, - 'react-refresh': reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], - }, - } -); diff --git a/ts/examples/vite-browser-render/package.json b/ts/examples/vite-browser-render/package.json index 5790d75ea..546f90406 100644 --- a/ts/examples/vite-browser-render/package.json +++ b/ts/examples/vite-browser-render/package.json @@ -11,23 +11,22 @@ "preview": "vite preview" }, "dependencies": { - "@live-compositor/browser-render": "0.1.0-rc.4", - "@live-compositor/web-wasm": "0.1.0-rc.0", + "@live-compositor/browser-render": "workspace:0.1.0-rc.4", + "@live-compositor/web-wasm": "workspace:0.1.0-rc.0", + "mp4box": "^0.5.2", "react": "^18.3.1", "react-dom": "^18.3.1" }, "devDependencies": { - "@eslint/js": "^9.9.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.1", - "eslint": "^9.9.0", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.9", - "globals": "^15.9.0", "typescript": "^5.5.3", "typescript-eslint": "^8.0.1", "vite": "^5.4.1", "vite-plugin-static-copy": "^1.0.6" + }, + "peerDependencies": { + "live-compositor": "workspace:^0.1.0" } } diff --git a/ts/examples/vite-browser-render/src/App.tsx b/ts/examples/vite-browser-render/src/App.tsx index 1e2b754ca..9259b9bc6 100644 --- a/ts/examples/vite-browser-render/src/App.tsx +++ b/ts/examples/vite-browser-render/src/App.tsx @@ -3,11 +3,12 @@ import './App.css'; import Counter from './examples/Counter'; import MP4Player from './examples/MP4Player'; +const EXAMPLES = { + counter: , + mp4: , +}; + function App() { - const EXAMPLES = { - 'counter': , - 'mp4': , - }; const [currentExample, setCurrentExample] = useState('counter'); return ( @@ -17,12 +18,9 @@ function App() { -

- {EXAMPLES[currentExample]} -
+
{EXAMPLES[currentExample]}
); } - export default App; diff --git a/ts/examples/vite-browser-render/src/examples/Counter.tsx b/ts/examples/vite-browser-render/src/examples/Counter.tsx index cfcdcaf4a..7b5042c17 100644 --- a/ts/examples/vite-browser-render/src/examples/Counter.tsx +++ b/ts/examples/vite-browser-render/src/examples/Counter.tsx @@ -5,7 +5,6 @@ function Counter() { const canvasRef = useRef(null); const [count, setCount] = useState(0); const renderer = useRenderer(); - useEffect(() => { if (renderer == null) { return; diff --git a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx index 6c6eb12dc..13c20c0bc 100644 --- a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx +++ b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx @@ -2,7 +2,8 @@ import { useCallback, useEffect, useState } from 'react'; import { LiveCompositor } from '@live-compositor/web-wasm'; import { InputStream, Text, useInputStreams, View } from 'live-compositor'; -const BUNNY_URL = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'; +const BUNNY_URL = + 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'; function MP4Player() { const [compositor, canvasRef] = useCompositor(); @@ -14,7 +15,7 @@ function MP4Player() { void compositor.start(); return () => compositor.stop(); - }, [compositor]) + }, [compositor]); return ( <> @@ -86,10 +87,10 @@ function useCompositor(): [LiveCompositor | undefined, (canvas: HTMLCanvasElemen }, root: , }); - } + }; setupCompositor(); - }, []) + }, []); return [compositor, canvasRef]; } diff --git a/ts/examples/vite-browser-render/src/examples/mp4/decoder.ts b/ts/examples/vite-browser-render/src/examples/mp4/decoder.ts new file mode 100644 index 000000000..c7d50f78d --- /dev/null +++ b/ts/examples/vite-browser-render/src/examples/mp4/decoder.ts @@ -0,0 +1,102 @@ +import type { MP4ArrayBuffer, MP4File, MP4Info, Sample, TrakBox } from 'mp4box'; +import MP4Box, { DataStream } from 'mp4box'; + +const MAX_FRAMEBUFFER_SIZE = 3; + +export class MP4Decoder { + private file: MP4File; + private chunks: EncodedVideoChunk[] = []; + private frames: VideoFrame[] = []; + private decoder: VideoDecoder; + + public constructor() { + this.file = MP4Box.createFile(); + this.decoder = new VideoDecoder({ + output: frame => { + this.frames.push(frame); + }, + error: error => { + console.error(`VideoDecoder Error: ${error}`); + }, + }); + + this.file.onReady = info => this.onReady(info); + this.file.onSamples = (id, user, info) => this.onSamples(id, user, info); + this.file.onError = (error: string) => { + console.error(`MP4 Parser Error: ${error}`); + }; + } + + public decode(videoData: MP4ArrayBuffer) { + videoData.fileStart = 0; + this.file.appendBuffer(videoData); + this.file.flush(); + } + + public nextFrame(): VideoFrame | undefined { + this.enqueueNextChunks(); + + return this.frames.shift(); + } + + private enqueueNextChunks() { + while ( + this.decoder.decodeQueueSize < MAX_FRAMEBUFFER_SIZE && + this.frames.length < MAX_FRAMEBUFFER_SIZE + ) { + const chunk = this.chunks.shift(); + if (!chunk) { + return null; + } + + this.decoder.decode(chunk); + } + } + + private onReady(info: MP4Info) { + const videoTrack = info.videoTracks[0]; + console.log(`Using codec: ${videoTrack.codec}`); + + const trak = this.file.getTrackById(videoTrack.id); + if (!trak) return; + const description = getCodecDescription(trak); + if (!description) { + console.error('Codec description not found'); + return; + } + + this.decoder.configure({ + codec: videoTrack.codec, + codedWidth: videoTrack.video.width, + codedHeight: videoTrack.video.height, + description: description, + }); + + this.file.setExtractionOptions(videoTrack.id); + this.file.start(); + } + + private onSamples(_id: number, _user: object, samples: Sample[]) { + for (const sample of samples) { + const chunk = new EncodedVideoChunk({ + type: sample.is_sync ? 'key' : 'delta', + timestamp: (sample.cts * 1_000_000) / sample.timescale, + duration: (sample.duration * 1_000_000) / sample.timescale, + data: sample.data, + }); + + this.chunks.push(chunk); + } + } +} + +function getCodecDescription(trak: TrakBox) { + for (const entry of trak.mdia.minf.stbl.stsd.entries) { + const box = entry.avcC || entry.hvcC || entry.vpcC || entry.av1C; + if (box) { + const stream = new DataStream(undefined, 0, DataStream.BIG_ENDIAN); + box.write(stream); + return new Uint8Array(stream.buffer, 8); + } + } +} diff --git a/ts/examples/vite-browser-render/src/examples/utils.ts b/ts/examples/vite-browser-render/src/examples/utils.ts new file mode 100644 index 000000000..94121ae2d --- /dev/null +++ b/ts/examples/vite-browser-render/src/examples/utils.ts @@ -0,0 +1,28 @@ +import { loadWasmModule, Renderer } from '@live-compositor/browser-render'; +import { useEffect, useState } from 'react'; + +export function useRenderer(): Renderer | null { + const [renderer, setRenderer] = useState(null); + useEffect(() => { + const setupRenderer = async () => { + await loadWasmModule('./assets/live-compositor.wasm'); + const renderer = await Renderer.create({ + streamFallbackTimeoutMs: 500, + }); + + await renderer.registerImage('img', { + asset_type: 'gif', + url: 'https://media.tenor.com/eFPFHSN4rJ8AAAAM/example.gif', + }); + await renderer.registerFont( + 'https://fonts.gstatic.com/s/notosans/v36/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9a6Vc.ttf' + ); + + setRenderer(renderer); + }; + + setupRenderer().catch(err => console.error(err)); + }, []); + + return renderer; +} diff --git a/ts/examples/vite-browser-render/ts-declarations/mp4box.d.ts b/ts/examples/vite-browser-render/ts-declarations/mp4box.d.ts new file mode 100644 index 000000000..5859feb47 --- /dev/null +++ b/ts/examples/vite-browser-render/ts-declarations/mp4box.d.ts @@ -0,0 +1,112 @@ +declare module 'mp4box' { + export class DataStream { + constructor(buffer?: ArrayBuffer, byteOffset?: number, endianness?: boolean); + + get buffer(): ArrayBuffer; + set buffer(v: ArrayBuffer); + + static LITTLE_ENDIAN: boolean; + static BIG_ENDIAN: boolean; + } + + export interface MP4File { + onReady?: (info: MP4Info) => void; + onError?: (e: string) => void; + onSamples?: (id: number, user: object, samples: Sample[]) => void; + + getTrackById(id: number): TrakBox | undefined; + + appendBuffer(data: MP4ArrayBuffer): number; + start(): void; + stop(): void; + flush(): void; + + setExtractionOptions(id: number, user?: object, options?: ExtractionOptions): void; + } + + export interface MP4MediaTrack { + id: number; + movie_duration: number; + track_width: number; + track_height: number; + timescale: number; + duration: number; + bitrate: number; + codec: string; + } + + export interface MP4VideoTrack extends MP4MediaTrack { + video: { + width: number; + height: number; + }; + } + + export interface MP4AudioTrack extends MP4MediaTrack { + audio: { + sample_size: number; + sample_rate: number; + channel_count: number; + }; + } + + export type MP4Track = MP4VideoTrack | MP4AudioTrack; + + export interface MP4Info { + duration: number; + timescale: number; + tracks: MP4Track[]; + audioTracks: MP4AudioTrack[]; + videoTracks: MP4VideoTrack[]; + } + + export interface Sample { + timescale: number; + data: ArrayBuffer; + size: number; + duration: number; + cts: number; + dts: number; + is_sync: boolean; + depends: number; + } + + export interface ExtractionOptions { + nbSamples: number; + } + + export type MP4ArrayBuffer = ArrayBuffer & { fileStart: number }; + + export class Box { + write(stream: DataStream): void; + } + + export class TrakBox extends Box { + mdia: MdiaBox; + } + + export class MdiaBox extends Box { + minf: MinfBox; + } + + export class MinfBox extends Box { + stbl: StblBox; + } + + export class StblBox extends Box { + stsd: StsdBox; + } + + export class StsdBox extends Box { + entries: Description[]; + } + + export interface Description { + avcC?: Box; + hvcC?: Box; + vpcC?: Box; + av1C?: Box; + } + + export function createFile(): MP4File; +} diff --git a/ts/examples/vite-browser-render/tsconfig.app.json b/ts/examples/vite-browser-render/tsconfig.app.json index f0a235055..27b709d0a 100644 --- a/ts/examples/vite-browser-render/tsconfig.app.json +++ b/ts/examples/vite-browser-render/tsconfig.app.json @@ -20,5 +20,5 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src"] + "include": ["src", "ts-declarations"] } diff --git a/ts/examples/vite-browser-render/vite.config.ts b/ts/examples/vite-browser-render/vite.config.ts index b0bea3b86..46676fe10 100644 --- a/ts/examples/vite-browser-render/vite.config.ts +++ b/ts/examples/vite-browser-render/vite.config.ts @@ -13,7 +13,10 @@ export default defineConfig({ viteStaticCopy({ targets: [ { - src: path.join(path.dirname(require.resolve('@live-compositor/browser-render')), 'live-compositor.wasm'), + src: path.join( + path.dirname(require.resolve('@live-compositor/browser-render')), + 'live-compositor.wasm' + ), dest: 'assets', }, ], diff --git a/ts/live-compositor/.eslintignore b/ts/live-compositor/.eslintignore deleted file mode 100644 index 55294f895..000000000 --- a/ts/live-compositor/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -esm -cjs diff --git a/ts/live-compositor/.eslintrc.json b/ts/live-compositor/.eslintrc.json deleted file mode 100644 index b80891633..000000000 --- a/ts/live-compositor/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "../.eslintrc.base.json" - ] -} diff --git a/ts/live-compositor/package.json b/ts/live-compositor/package.json index cd1ae012d..bb6515f2e 100644 --- a/ts/live-compositor/package.json +++ b/ts/live-compositor/package.json @@ -12,14 +12,14 @@ "scripts": { "lint": "eslint .", "typecheck": "tsc --noEmit", - "watch": "concurrently \"npm run watch:esm\" \"npm run watch:cjs\"", + "watch": "concurrently \"pnpm run watch:esm\" \"pnpm run watch:cjs\"", "watch:esm": "tsc --watch --preserveWatchOutput", "watch:cjs": "tsc --watch --preserveWatchOutput -p ./tsconfig.cjs.json", - "build": "npm run build:esm && npm run build:cjs", + "build": "pnpm run build:esm && pnpm run build:cjs", "build:esm": "tsc && echo '{\"type\": \"module\"}' > esm/package.json", "build:cjs": "tsc -p ./tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > cjs/package.json", "clean": "rimraf esm cjs", - "prepublishOnly": "npm run clean && npm run build" + "prepublishOnly": "pnpm run clean && pnpm run build" }, "author": "", "license": "MIT", diff --git a/ts/live-compositor/src/component.ts b/ts/live-compositor/src/component.ts index abd075010..15d9bae3a 100644 --- a/ts/live-compositor/src/component.ts +++ b/ts/live-compositor/src/component.ts @@ -1,5 +1,6 @@ -import React, { useId } from 'react'; -import * as Api from './api.js'; +import type React from 'react'; +import { createElement, useId } from 'react'; +import type * as Api from './api.js'; type ComponentProps

= { children?: React.ReactNode; id?: Api.ComponentId } & P; @@ -13,7 +14,7 @@ export function createCompositorComponent

( const { children, ...otherProps } = props; const autoId = useId(); - return React.createElement( + return createElement( 'compositor', { sceneBuilder, diff --git a/ts/live-compositor/src/components/Image.ts b/ts/live-compositor/src/components/Image.ts index 4d8fa7483..445dde715 100644 --- a/ts/live-compositor/src/components/Image.ts +++ b/ts/live-compositor/src/components/Image.ts @@ -1,5 +1,6 @@ -import * as Api from '../api.js'; -import { createCompositorComponent, SceneComponent } from '../component.js'; +import type { SceneComponent } from '../component.js'; +import { createCompositorComponent } from '../component.js'; +import type { Api } from '../index.js'; export type ImageProps = { children?: undefined; diff --git a/ts/live-compositor/src/components/InputStream.ts b/ts/live-compositor/src/components/InputStream.ts index 27ef54016..59074cd0c 100644 --- a/ts/live-compositor/src/components/InputStream.ts +++ b/ts/live-compositor/src/components/InputStream.ts @@ -1,6 +1,7 @@ import { createElement } from 'react'; -import * as Api from '../api.js'; -import { createCompositorComponent, SceneComponent } from '../component.js'; +import type * as Api from '../api.js'; +import type { SceneComponent } from '../component.js'; +import { createCompositorComponent } from '../component.js'; import { useAudioInput } from '../hooks.js'; export type InputStreamProps = { diff --git a/ts/live-compositor/src/components/Rescaler.ts b/ts/live-compositor/src/components/Rescaler.ts index a1080ed47..c80278ced 100644 --- a/ts/live-compositor/src/components/Rescaler.ts +++ b/ts/live-compositor/src/components/Rescaler.ts @@ -1,7 +1,9 @@ -import React from 'react'; -import * as Api from '../api.js'; -import { intoApiTransition, Transition } from './common.js'; -import { createCompositorComponent, SceneComponent, sceneComponentIntoApi } from '../component.js'; +import type React from 'react'; +import type * as Api from '../api.js'; +import type { Transition } from './common.js'; +import { intoApiTransition } from './common.js'; +import type { SceneComponent } from '../component.js'; +import { createCompositorComponent, sceneComponentIntoApi } from '../component.js'; export type RescalerProps = { children: React.ReactElement | string | number; diff --git a/ts/live-compositor/src/components/Shader.ts b/ts/live-compositor/src/components/Shader.ts index 73809d5db..c429f804d 100644 --- a/ts/live-compositor/src/components/Shader.ts +++ b/ts/live-compositor/src/components/Shader.ts @@ -1,5 +1,6 @@ -import * as Api from '../api.js'; -import { createCompositorComponent, SceneComponent, sceneComponentIntoApi } from '../component.js'; +import type * as Api from '../api.js'; +import type { SceneComponent } from '../component.js'; +import { createCompositorComponent, sceneComponentIntoApi } from '../component.js'; export type ShaderProps = { /** diff --git a/ts/live-compositor/src/components/Text.ts b/ts/live-compositor/src/components/Text.ts index a5d5b9959..bd3643288 100644 --- a/ts/live-compositor/src/components/Text.ts +++ b/ts/live-compositor/src/components/Text.ts @@ -1,5 +1,6 @@ -import * as Api from '../api.js'; -import { createCompositorComponent, SceneComponent } from '../component.js'; +import type * as Api from '../api.js'; +import type { SceneComponent } from '../component.js'; +import { createCompositorComponent } from '../component.js'; import { intoApiRgbaColor } from './common.js'; export type TextProps = { diff --git a/ts/live-compositor/src/components/Tiles.ts b/ts/live-compositor/src/components/Tiles.ts index b900f95ca..927f9866e 100644 --- a/ts/live-compositor/src/components/Tiles.ts +++ b/ts/live-compositor/src/components/Tiles.ts @@ -1,6 +1,8 @@ -import * as Api from '../api.js'; -import { intoApiRgbaColor, intoApiTransition, Transition } from './common.js'; -import { createCompositorComponent, SceneComponent, sceneComponentIntoApi } from '../component.js'; +import type * as Api from '../api.js'; +import type { Transition } from './common.js'; +import { intoApiRgbaColor, intoApiTransition } from './common.js'; +import type { SceneComponent } from '../component.js'; +import { createCompositorComponent, sceneComponentIntoApi } from '../component.js'; export type TilesProps = { /** diff --git a/ts/live-compositor/src/components/View.ts b/ts/live-compositor/src/components/View.ts index 5a7e3a8c9..f54827686 100644 --- a/ts/live-compositor/src/components/View.ts +++ b/ts/live-compositor/src/components/View.ts @@ -1,6 +1,8 @@ -import * as Api from '../api.js'; -import { createCompositorComponent, SceneComponent, sceneComponentIntoApi } from '../component.js'; -import { intoApiRgbaColor, intoApiTransition, Transition } from './common.js'; +import type * as Api from '../api.js'; +import type { SceneComponent } from '../component.js'; +import { createCompositorComponent, sceneComponentIntoApi } from '../component.js'; +import type { Transition } from './common.js'; +import { intoApiRgbaColor, intoApiTransition } from './common.js'; export type ViewProps = { /** diff --git a/ts/live-compositor/src/components/WebView.ts b/ts/live-compositor/src/components/WebView.ts index d781c66a0..b0c61fcf5 100644 --- a/ts/live-compositor/src/components/WebView.ts +++ b/ts/live-compositor/src/components/WebView.ts @@ -1,5 +1,6 @@ -import * as Api from '../api.js'; -import { createCompositorComponent, SceneComponent, sceneComponentIntoApi } from '../component.js'; +import type * as Api from '../api.js'; +import type { SceneComponent } from '../component.js'; +import { createCompositorComponent, sceneComponentIntoApi } from '../component.js'; export type WebViewProps = { /** diff --git a/ts/live-compositor/src/components/common.ts b/ts/live-compositor/src/components/common.ts index 4678627a7..0df3635ac 100644 --- a/ts/live-compositor/src/components/common.ts +++ b/ts/live-compositor/src/components/common.ts @@ -1,4 +1,4 @@ -import * as Api from '../api.js'; +import type * as Api from '../api.js'; export interface Transition { /** diff --git a/ts/live-compositor/src/context/instanceContextStore.ts b/ts/live-compositor/src/context/instanceContextStore.ts index 1b24ab5b2..df64b6347 100644 --- a/ts/live-compositor/src/context/instanceContextStore.ts +++ b/ts/live-compositor/src/context/instanceContextStore.ts @@ -1,4 +1,4 @@ -import * as Api from '../api.js'; +import type * as Api from '../api.js'; export type StreamState = 'ready' | 'playing' | 'finished'; diff --git a/ts/live-compositor/src/context/outputContext.ts b/ts/live-compositor/src/context/outputContext.ts index 7aedb18bd..3f188e48d 100644 --- a/ts/live-compositor/src/context/outputContext.ts +++ b/ts/live-compositor/src/context/outputContext.ts @@ -1,4 +1,4 @@ -import { AudioInputsConfiguration } from '../types/registerOutput.js'; +import type { AudioInputsConfiguration } from '../types/registerOutput.js'; export type ContextAudioOptions = { volume: number; diff --git a/ts/live-compositor/src/hooks.ts b/ts/live-compositor/src/hooks.ts index 370fa7226..828e90329 100644 --- a/ts/live-compositor/src/hooks.ts +++ b/ts/live-compositor/src/hooks.ts @@ -1,8 +1,8 @@ import { useContext, useEffect, useSyncExternalStore } from 'react'; -import * as Api from './api.js'; +import type * as Api from './api.js'; import { LiveCompositorContext } from './context/index.js'; -import { InputStreamInfo } from './context/instanceContextStore.js'; +import type { InputStreamInfo } from './context/instanceContextStore.js'; export function useInputStreams(): Record { const ctx = useContext(LiveCompositorContext); diff --git a/ts/live-compositor/src/types/registerInput.ts b/ts/live-compositor/src/types/registerInput.ts index faffa7d23..77f049ac9 100644 --- a/ts/live-compositor/src/types/registerInput.ts +++ b/ts/live-compositor/src/types/registerInput.ts @@ -1,4 +1,4 @@ -import * as Api from '../api.js'; +import type * as Api from '../api.js'; export type RegisterRtpInput = { /** diff --git a/ts/live-compositor/src/types/registerOutput.ts b/ts/live-compositor/src/types/registerOutput.ts index 22e653031..977d9b77d 100644 --- a/ts/live-compositor/src/types/registerOutput.ts +++ b/ts/live-compositor/src/types/registerOutput.ts @@ -1,5 +1,5 @@ -import React from 'react'; -import * as Api from '../api.js'; +import type React from 'react'; +import type * as Api from '../api.js'; export type RegisterRtpOutput = { /** diff --git a/ts/live-compositor/src/types/registerRenderer.ts b/ts/live-compositor/src/types/registerRenderer.ts index 72b5ed030..3aca9afea 100644 --- a/ts/live-compositor/src/types/registerRenderer.ts +++ b/ts/live-compositor/src/types/registerRenderer.ts @@ -1,4 +1,4 @@ -import * as Api from '../api.js'; +import type * as Api from '../api.js'; export type RegisterShader = Api.ShaderSpec; diff --git a/ts/live-compositor/tsconfig.json b/ts/live-compositor/tsconfig.json index 27edaeb17..c86bcad63 100644 --- a/ts/live-compositor/tsconfig.json +++ b/ts/live-compositor/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../tsconfig.base.json", + "extends": "../tsconfig.json", "compilerOptions": { "outDir": "esm" } diff --git a/ts/package-lock.json b/ts/package-lock.json deleted file mode 100644 index 9315e68ee..000000000 --- a/ts/package-lock.json +++ /dev/null @@ -1,14365 +0,0 @@ -{ - "name": "live-compositor-workspace", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "live-compositor-workspace", - "version": "0.1.0", - "workspaces": [ - "live-compositor", - "@live-compositor/core", - "@live-compositor/node", - "@live-compositor/web-wasm", - "@live-compositor/browser-render", - "examples/node-examples", - "examples/vite-browser-render", - "create-live-compositor", - "create-live-compositor/templates/node-minimal", - "create-live-compositor/templates/node-express-zustand" - ], - "devDependencies": { - "@eslint/plugin-kit": "^0.2.0", - "@typescript-eslint/eslint-plugin": "^7.16.0", - "@typescript-eslint/parser": "^7.18.0", - "concurrently": "^9.0.1", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-typescript": "^3.6.3", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-prettier": "^5.1.3", - "json-schema-to-typescript": "^15.0.1", - "lerna": "^8.1.8", - "prettier": "^3.3.2", - "typescript": "^5.5.3" - } - }, - "@live-compositor/browser-render": { - "version": "0.1.0-rc.4", - "license": "BUSL-1.1", - "devDependencies": { - "@rollup/plugin-typescript": "^11.1.6", - "rollup": "^4.21.2", - "rollup-plugin-copy": "^3.5.0", - "rollup-plugin-dts": "^6.1.1", - "wasm-pack": "^0.13.0" - }, - "peerDependencies": { - "live-compositor": "^0.1.0" - } - }, - "@live-compositor/core": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "react-reconciler": "0.29.2" - }, - "devDependencies": { - "@types/react-reconciler": "0.28.8" - }, - "peerDependencies": { - "live-compositor": "^0.1.0" - } - }, - "@live-compositor/node": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "@live-compositor/core": "^0.1.0", - "fs-extra": "^11.2.0", - "node-fetch": "^2.6.7", - "tar": "^7.4.3", - "uuid": "^10.0.0", - "ws": "^8.18.0" - }, - "devDependencies": { - "@types/fs-extra": "^11.0.4", - "@types/node": "^20.14.10", - "@types/node-fetch": "^2.6.11", - "@types/uuid": "^10.0.0", - "@types/ws": "^8.5.12" - } - }, - "@live-compositor/node/node_modules/tar": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", - "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", - "license": "ISC", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "@live-compositor/web-wasm": { - "version": "0.1.0-rc.0", - "license": "MIT", - "dependencies": { - "@datastructures-js/queue": "^4.2.3", - "@live-compositor/browser-render": "0.1.0-rc.4", - "@live-compositor/core": "0.1.0", - "live-compositor": "^0.1.0", - "mp4box": "^0.5.2", - "path-parser": "^6.1.0" - } - }, - "create-live-compositor": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2", - "fs-extra": "^11.2.0", - "prompts": "^2.4.2" - }, - "bin": { - "create-live-compositor": "dist/index.js" - }, - "devDependencies": { - "@types/fs-extra": "^11.0.4", - "@types/prompts": "^2.4.9" - } - }, - "create-live-compositor/templates/node-express-zustand": { - "name": "template-node-express-zustand", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@live-compositor/node": "^0.1.0", - "express": "^4.21.0", - "live-compositor": "^0.1.0", - "react": "^18.3.1", - "zustand": "4.5.5" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "@types/node": "^20.14.10", - "@types/react": "^18.3.3", - "typescript": "^5.5.3" - } - }, - "create-live-compositor/templates/node-minimal": { - "name": "template-node-minimal", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@live-compositor/node": "^0.1.0", - "live-compositor": "^0.1.0", - "react": "^18.3.1" - }, - "devDependencies": { - "@types/node": "^20.14.10", - "@types/react": "^18.3.3", - "typescript": "^5.5.3" - } - }, - "examples/node-examples": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@live-compositor/node": "^0.1.0", - "@types/fs-extra": "^11.0.4", - "@types/node": "^20.14.10", - "fs-extra": "^11.2.0", - "live-compositor": "^0.1.0", - "node-fetch": "^2.6.7", - "ts-node": "^10.9.2" - } - }, - "examples/vite-browser-render": { - "name": "example", - "version": "1.0.0", - "dependencies": { - "@live-compositor/browser-render": "0.1.0-rc.4", - "@live-compositor/web-wasm": "0.1.0-rc.0", - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@eslint/js": "^9.9.0", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", - "eslint": "^9.9.0", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.9", - "globals": "^15.9.0", - "typescript": "^5.5.3", - "typescript-eslint": "^8.0.1", - "vite": "^5.4.1", - "vite-plugin-static-copy": "^1.0.6" - } - }, - "examples/vite-browser-render/node_modules/eslint": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", - "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.13.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "live-compositor": { - "version": "0.1.0", - "license": "MIT", - "devDependencies": { - "@types/react": "^18.3.3" - }, - "peerDependencies": { - "react": "*" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz", - "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", - "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.25.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", - "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", - "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helpers": "^7.25.7", - "@babel/parser": "^7.25.8", - "@babel/template": "^7.25.7", - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.8", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", - "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", - "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", - "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", - "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.7", - "@babel/helper-simple-access": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "@babel/traverse": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", - "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", - "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", - "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", - "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", - "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", - "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.8" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.7.tgz", - "integrity": "sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.7.tgz", - "integrity": "sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", - "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", - "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", - "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@datastructures-js/queue": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@datastructures-js/queue/-/queue-4.2.3.tgz", - "integrity": "sha512-GWVMorC/xi2V2ta+Z/CPgPGHL2ZJozcj48g7y2nIX5GIGZGRrbShSHgvMViJwHJurUzJYOdIdRZnWDRrROFwJA==", - "license": "MIT" - }, - "node_modules/@emnapi/core": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz", - "integrity": "sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emnapi/wasi-threads": "1.0.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", - "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", - "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", - "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz", - "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", - "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", - "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.0", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@hutson/parse-repository-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", - "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", - "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "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, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "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, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "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==", - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lerna/create": { - "version": "8.1.8", - "resolved": "https://registry.npmjs.org/@lerna/create/-/create-8.1.8.tgz", - "integrity": "sha512-wi72R01tgjBjzG2kjRyTHl4yCTKDfDMIXRyKz9E/FBa9SkFvUOAE4bdyY9MhEsRZmSWL7+CYE8Flv/HScRpBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@npmcli/arborist": "7.5.4", - "@npmcli/package-json": "5.2.0", - "@npmcli/run-script": "8.1.0", - "@nx/devkit": ">=17.1.2 < 20", - "@octokit/plugin-enterprise-rest": "6.0.1", - "@octokit/rest": "19.0.11", - "aproba": "2.0.0", - "byte-size": "8.1.1", - "chalk": "4.1.0", - "clone-deep": "4.0.1", - "cmd-shim": "6.0.3", - "color-support": "1.1.3", - "columnify": "1.6.0", - "console-control-strings": "^1.1.0", - "conventional-changelog-core": "5.0.1", - "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "^8.2.0", - "dedent": "1.5.3", - "execa": "5.0.0", - "fs-extra": "^11.2.0", - "get-stream": "6.0.0", - "git-url-parse": "14.0.0", - "glob-parent": "6.0.2", - "globby": "11.1.0", - "graceful-fs": "4.2.11", - "has-unicode": "2.0.1", - "ini": "^1.3.8", - "init-package-json": "6.0.3", - "inquirer": "^8.2.4", - "is-ci": "3.0.1", - "is-stream": "2.0.0", - "js-yaml": "4.1.0", - "libnpmpublish": "9.0.9", - "load-json-file": "6.2.0", - "lodash": "^4.17.21", - "make-dir": "4.0.0", - "minimatch": "3.0.5", - "multimatch": "5.0.0", - "node-fetch": "2.6.7", - "npm-package-arg": "11.0.2", - "npm-packlist": "8.0.2", - "npm-registry-fetch": "^17.1.0", - "nx": ">=17.1.2 < 20", - "p-map": "4.0.0", - "p-map-series": "2.1.0", - "p-queue": "6.6.2", - "p-reduce": "^2.1.0", - "pacote": "^18.0.6", - "pify": "5.0.0", - "read-cmd-shim": "4.0.0", - "resolve-from": "5.0.0", - "rimraf": "^4.4.1", - "semver": "^7.3.4", - "set-blocking": "^2.0.0", - "signal-exit": "3.0.7", - "slash": "^3.0.0", - "ssri": "^10.0.6", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "strong-log-transformer": "2.1.0", - "tar": "6.2.1", - "temp-dir": "1.0.0", - "upath": "2.0.1", - "uuid": "^10.0.0", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "5.0.1", - "wide-align": "1.1.5", - "write-file-atomic": "5.0.1", - "write-pkg": "4.0.0", - "yargs": "17.7.2", - "yargs-parser": "21.1.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@lerna/create/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@lerna/create/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, - "license": "MIT" - }, - "node_modules/@lerna/create/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@lerna/create/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@lerna/create/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/@lerna/create/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, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@live-compositor/browser-render": { - "resolved": "@live-compositor/browser-render", - "link": true - }, - "node_modules/@live-compositor/core": { - "resolved": "@live-compositor/core", - "link": true - }, - "node_modules/@live-compositor/node": { - "resolved": "@live-compositor/node", - "link": true - }, - "node_modules/@live-compositor/web-wasm": { - "resolved": "@live-compositor/web-wasm", - "link": true - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", - "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emnapi/core": "^1.1.0", - "@emnapi/runtime": "^1.1.0", - "@tybys/wasm-util": "^0.9.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nolyfill/is-core-module": { - "version": "1.0.39", - "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", - "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.4.0" - } - }, - "node_modules/@npmcli/agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", - "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", - "dev": true, - "license": "ISC", - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/agent/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, - "license": "ISC" - }, - "node_modules/@npmcli/arborist": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.5.4.tgz", - "integrity": "sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g==", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^3.1.1", - "@npmcli/installed-package-contents": "^2.1.0", - "@npmcli/map-workspaces": "^3.0.2", - "@npmcli/metavuln-calculator": "^7.1.1", - "@npmcli/name-from-folder": "^2.0.0", - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^5.1.0", - "@npmcli/query": "^3.1.0", - "@npmcli/redact": "^2.0.0", - "@npmcli/run-script": "^8.1.0", - "bin-links": "^4.0.4", - "cacache": "^18.0.3", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^7.0.2", - "json-parse-even-better-errors": "^3.0.2", - "json-stringify-nice": "^1.1.4", - "lru-cache": "^10.2.2", - "minimatch": "^9.0.4", - "nopt": "^7.2.1", - "npm-install-checks": "^6.2.0", - "npm-package-arg": "^11.0.2", - "npm-pick-manifest": "^9.0.1", - "npm-registry-fetch": "^17.0.1", - "pacote": "^18.0.6", - "parse-conflict-json": "^3.0.0", - "proc-log": "^4.2.0", - "proggy": "^2.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^3.0.1", - "read-package-json-fast": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^10.0.6", - "treeverse": "^3.0.0", - "walk-up-path": "^3.0.1" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/arborist/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@npmcli/arborist/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, - "license": "ISC" - }, - "node_modules/@npmcli/arborist/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@npmcli/fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", - "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", - "dev": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", - "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^7.0.0", - "ini": "^4.1.3", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^9.0.0", - "proc-log": "^4.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git/node_modules/ini": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", - "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/git/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, - "license": "ISC" - }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", - "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/map-workspaces": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz", - "integrity": "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^2.0.0", - "glob": "^10.2.2", - "minimatch": "^9.0.0", - "read-package-json-fast": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/map-workspaces/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@npmcli/map-workspaces/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@npmcli/metavuln-calculator": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-7.1.1.tgz", - "integrity": "sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g==", - "dev": true, - "license": "ISC", - "dependencies": { - "cacache": "^18.0.0", - "json-parse-even-better-errors": "^3.0.0", - "pacote": "^18.0.0", - "proc-log": "^4.1.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/name-from-folder": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", - "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", - "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^5.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^7.0.0", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "proc-log": "^4.0.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", - "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/query": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-3.1.0.tgz", - "integrity": "sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/redact": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.1.tgz", - "integrity": "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz", - "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^5.0.0", - "@npmcli/promise-spawn": "^7.0.0", - "node-gyp": "^10.0.0", - "proc-log": "^4.0.0", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/@nrwl/devkit": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.8.6.tgz", - "integrity": "sha512-F6+4Lv2hSS+02H7aqa+jYIHzbmip7082DF9/NkNtUAEqLUi8STsbung0nchaR1Tjg20E+BZujEsZgTC3GJegLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nx/devkit": "19.8.6" - } - }, - "node_modules/@nrwl/tao": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.8.6.tgz", - "integrity": "sha512-ibxGL7aDpNARgPegXQ8HAocemZ1WvZE5+NHkXDs7jSmnSt9qaXIKE1dXotDTqp3TqCirlje1/RMMTqzCl2oExQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "nx": "19.8.6", - "tslib": "^2.3.0" - }, - "bin": { - "tao": "index.js" - } - }, - "node_modules/@nx/devkit": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.8.6.tgz", - "integrity": "sha512-8NAdnqwzki3srj2sAImWQ9cQiq79NqwqVqx/XOdg0XHR6siugn+sAAXWpM3xJVdv4uRbcyz7BO1GWYxMW0AOYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nrwl/devkit": "19.8.6", - "ejs": "^3.1.7", - "enquirer": "~2.3.6", - "ignore": "^5.0.4", - "minimatch": "9.0.3", - "semver": "^7.5.3", - "tmp": "~0.2.1", - "tslib": "^2.3.0", - "yargs-parser": "21.1.1" - }, - "peerDependencies": { - "nx": ">= 19 <= 21" - } - }, - "node_modules/@nx/devkit/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@nx/devkit/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@nx/nx-darwin-arm64": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.8.6.tgz", - "integrity": "sha512-lzFV07gUgvy07lPtRFJFhlQdcR0qNTPPq7/ZB+3alwUIDdAn706ZVzf6apCJWOBIgNFKbAQiy/du0zmuKPSzXA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-darwin-x64": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.8.6.tgz", - "integrity": "sha512-1ZmOXwJva14jCcTHM8jmsEBp33CCLng/tXK8/554ACwL3Kk4kbtdLfUjM/VEMZ3v3c1D7cJWxyYfTav5meumxg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-freebsd-x64": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.8.6.tgz", - "integrity": "sha512-1a681ZqSS05H1pC6JG3ae0BLhnxGtISkCigl9R6W5NeyFLBgP+Y4BLh+H9cCAlKzzLwiKWWRmhbxvjpnlhzB+w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.8.6.tgz", - "integrity": "sha512-qGztEgbEjMsFr9IjedQXJNmXLHCpSldW/sEtXoVZ8tXIzGr86GXbv+mLdZSZHrlJaNOq0y2K6XpVd2UH4ndwnQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.8.6.tgz", - "integrity": "sha512-rSwsEISx5odXkg1kjXBZ6kjXCnM3fnAA+8YU1muRr7PmhUfM/zuCnNYcwmjtCRc7rRYBKzxmyE3T95fGK/NOIg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm64-musl": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.8.6.tgz", - "integrity": "sha512-7rW21+uFj5KJx3z/HXhl6PUcp8+mQ8r/nUGbS59HjmMdVMZDd7PZKUVJF9Tu1ESproOCYSeJbOVk4WGiHtbF9Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.8.6.tgz", - "integrity": "sha512-2/5WDr2wwWyvbqlB//ICWS5q3rRF4GyNX2NOp/tVkmh1RfDhH0ZAVZ/oJ7QvE1mKLQh0AM7bQBHsF5ikmMhUXw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.8.6.tgz", - "integrity": "sha512-G3UIMk+C090WR/btOaJCrBgRa7gjTj6ZBHinFceO7rii8r3D1SiN5cW1Njd1pV2K7IjJaSTuRtd9c1eLcIj9rQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.8.6.tgz", - "integrity": "sha512-8dfUstJkN2ChbIcj3TfcHgWyJy0b9za+3gU9IvZm82P9EeDCjEGoE/ld9VALGa+2UnX2Ve5BqlWGTD8BqYTeCA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-win32-x64-msvc": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.8.6.tgz", - "integrity": "sha512-kbWDZGD9kwP60UykTnfMR1hOUMDK0evXb5EnF4MAf4o18+b5KSzHyaL2TyNl+3s6lYdtZ2kYC679R+eJErKG8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@octokit/auth-token": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", - "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/@octokit/core": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz", - "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/auth-token": "^3.0.0", - "@octokit/graphql": "^5.0.0", - "@octokit/request": "^6.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@octokit/endpoint": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", - "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@octokit/graphql": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", - "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/request": "^6.0.0", - "@octokit/types": "^9.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "18.1.1", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.1.1.tgz", - "integrity": "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-enterprise-rest": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", - "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz", - "integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/tsconfig": "^1.0.2", - "@octokit/types": "^9.2.3" - }, - "engines": { - "node": ">= 14" - }, - "peerDependencies": { - "@octokit/core": ">=4" - } - }, - "node_modules/@octokit/plugin-request-log": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz", - "integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^10.0.0" - }, - "engines": { - "node": ">= 14" - }, - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz", - "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^18.0.0" - } - }, - "node_modules/@octokit/request": { - "version": "6.2.8", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz", - "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/endpoint": "^7.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@octokit/request-error": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", - "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^9.0.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@octokit/rest": { - "version": "19.0.11", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.11.tgz", - "integrity": "sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/core": "^4.2.1", - "@octokit/plugin-paginate-rest": "^6.1.2", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^7.1.2" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@octokit/tsconfig": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", - "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/types": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz", - "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^18.0.0" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@rollup/plugin-typescript": { - "version": "11.1.6", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", - "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.1.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.14.0||^3.0.0||^4.0.0", - "tslib": "*", - "typescript": ">=3.7.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - }, - "tslib": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", - "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", - "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", - "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", - "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", - "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", - "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", - "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", - "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", - "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", - "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", - "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", - "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", - "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", - "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", - "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", - "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", - "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sigstore/bundle": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", - "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", - "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", - "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/sign": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", - "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^2.3.2", - "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "make-fetch-happen": "^13.0.1", - "proc-log": "^4.2.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/tuf": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", - "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2", - "tuf-js": "^2.2.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/verify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", - "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^2.3.2", - "@sigstore/core": "^1.1.0", - "@sigstore/protobuf-specs": "^0.3.2" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "license": "MIT" - }, - "node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", - "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@tufjs/models/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", - "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/fs-extra": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", - "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", - "license": "MIT", - "dependencies": { - "@types/jsonfile": "*", - "@types/node": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/jsonfile": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", - "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/lodash": { - "version": "4.17.12", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.12.tgz", - "integrity": "sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.16.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.13.tgz", - "integrity": "sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/prompts": { - "version": "2.4.9", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.9.tgz", - "integrity": "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "kleur": "^3.0.3" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/qs": { - "version": "6.9.16", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", - "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.11", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", - "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-reconciler": { - "version": "0.28.8", - "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", - "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "node_modules/@types/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/ws": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", - "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", - "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/type-utils": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.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/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" - }, - "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/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", - "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/utils": "7.18.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/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.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/typescript-estree/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.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/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.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/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz", - "integrity": "sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/plugin-transform-react-jsx-self": "^7.24.7", - "@babel/plugin-transform-react-jsx-source": "^7.24.7", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" - } - }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", - "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", - "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/add-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", - "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-differ": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true, - "license": "MIT" - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/bin-links": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.4.tgz", - "integrity": "sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==", - "dev": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "read-cmd-shim": "^4.0.0", - "write-file-atomic": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/binary-install": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/binary-install/-/binary-install-1.1.0.tgz", - "integrity": "sha512-rkwNGW+3aQVSZoD0/o3mfPN6Yxh3Id0R/xzTVBVVpGNlVz8EGwusksxRlbk/A5iKTZt9zkMn3qIqmAt3vpfbzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "axios": "^0.26.1", - "rimraf": "^3.0.2", - "tar": "^6.1.11" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/binary-install/node_modules/axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.14.8" - } - }, - "node_modules/binary-install/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/binary-install/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/byte-size": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-8.1.1.tgz", - "integrity": "sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "18.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", - "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/cacache/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, - "license": "ISC" - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001669", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/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, - "license": "MIT" - }, - "node_modules/cliui/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, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "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, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cmd-shim": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.3.tgz", - "integrity": "sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/columnify": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", - "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/common-ancestor-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", - "dev": true, - "license": "ISC" - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "dev": true, - "engines": [ - "node >= 6.0" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concurrently": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.0.1.tgz", - "integrity": "sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2", - "lodash": "^4.17.21", - "rxjs": "^7.8.1", - "shell-quote": "^1.8.1", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.2" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/conventional-changelog-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/conventional-changelog-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-5.0.1.tgz", - "integrity": "sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "add-stream": "^1.0.0", - "conventional-changelog-writer": "^6.0.0", - "conventional-commits-parser": "^4.0.0", - "dateformat": "^3.0.3", - "get-pkg-repo": "^4.2.1", - "git-raw-commits": "^3.0.0", - "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^5.0.0", - "normalize-package-data": "^3.0.3", - "read-pkg": "^3.0.0", - "read-pkg-up": "^3.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/conventional-changelog-preset-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-3.0.0.tgz", - "integrity": "sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-changelog-writer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz", - "integrity": "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "conventional-commits-filter": "^3.0.0", - "dateformat": "^3.0.3", - "handlebars": "^4.7.7", - "json-stringify-safe": "^5.0.1", - "meow": "^8.1.2", - "semver": "^7.0.0", - "split": "^1.0.1" - }, - "bin": { - "conventional-changelog-writer": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-commits-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", - "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-commits-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", - "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.3.5", - "meow": "^8.1.2", - "split2": "^3.2.2" - }, - "bin": { - "conventional-commits-parser": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-recommended-bump": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-7.0.1.tgz", - "integrity": "sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==", - "dev": true, - "license": "MIT", - "dependencies": { - "concat-stream": "^2.0.0", - "conventional-changelog-preset-loader": "^3.0.0", - "conventional-commits-filter": "^3.0.0", - "conventional-commits-parser": "^4.0.0", - "git-raw-commits": "^3.0.0", - "git-semver-tags": "^5.0.0", - "meow": "^8.1.2" - }, - "bin": { - "conventional-recommended-bump": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/create-live-compositor": { - "resolved": "create-live-compositor", - "link": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-indent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-expand": { - "version": "11.0.6", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.6.tgz", - "integrity": "sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^16.4.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true, - "license": "MIT" - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.41", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", - "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", - "dev": true, - "license": "ISC" - }, - "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==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", - "dev": true, - "license": "MIT", - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true, - "license": "MIT" - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", - "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.3.5", - "enhanced-resolve": "^5.15.0", - "eslint-module-utils": "^2.8.1", - "fast-glob": "^3.3.2", - "get-tsconfig": "^4.7.5", - "is-bun-module": "^1.0.2", - "is-glob": "^4.0.3" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "peerDependenciesMeta": { - "eslint-plugin-import": { - "optional": true - }, - "eslint-plugin-import-x": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.1.0-rc-fb9a90fa48-20240614", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz", - "integrity": "sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.13.tgz", - "integrity": "sha512-f1EppwrpJRWmqDTyvAyomFVDYRtrS7iTEqv3nokETnMiMzs2SSTmKRTACce4O2p4jYyowiSMvpdwC/RLcMFhuQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": ">=7" - } - }, - "node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/eslint/node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/eslint/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT" - }, - "node_modules/example": { - "resolved": "examples/vite-browser-render", - "link": true - }, - "node_modules/execa": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", - "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "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, - "license": "MIT" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true, - "license": "ISC" - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/front-matter": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", - "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^3.13.1" - } - }, - "node_modules/front-matter/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/front-matter/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/front-matter/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-pkg-repo": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", - "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@hutson/parse-repository-url": "^3.0.0", - "hosted-git-info": "^4.0.0", - "through2": "^2.0.0", - "yargs": "^16.2.0" - }, - "bin": { - "get-pkg-repo": "src/cli.js" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-pkg-repo/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/get-pkg-repo/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, - "license": "MIT" - }, - "node_modules/get-pkg-repo/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-pkg-repo/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-pkg-repo/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, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/get-pkg-repo/node_modules/wrap-ansi": { - "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, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/get-pkg-repo/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/get-pkg-repo/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-pkg-repo/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/get-port": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", - "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", - "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/git-raw-commits": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz", - "integrity": "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dargs": "^7.0.0", - "meow": "^8.1.2", - "split2": "^3.2.2" - }, - "bin": { - "git-raw-commits": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "gitconfiglocal": "^1.0.0", - "pify": "^2.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/git-remote-origin-url/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/git-semver-tags": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-5.0.1.tgz", - "integrity": "sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "meow": "^8.1.2", - "semver": "^7.0.0" - }, - "bin": { - "git-semver-tags": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/git-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", - "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-ssh": "^1.4.0", - "parse-url": "^8.1.0" - } - }, - "node_modules/git-url-parse": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-14.0.0.tgz", - "integrity": "sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "git-up": "^7.0.0" - } - }, - "node_modules/gitconfiglocal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", - "dev": true, - "license": "BSD", - "dependencies": { - "ini": "^1.3.2" - } - }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/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==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", - "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/hosted-git-info/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, - "license": "ISC" - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-walk": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", - "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", - "dev": true, - "license": "ISC", - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/ignore-walk/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/ignore-walk/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC" - }, - "node_modules/init-package-json": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-6.0.3.tgz", - "integrity": "sha512-Zfeb5ol+H+eqJWHTaGca9BovufyGeIfr4zaaBorPmJBMrJ+KBnN+kQx2ZtXdsotUTgldHmHQV44xvUWOUA7E2w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/package-json": "^5.0.0", - "npm-package-arg": "^11.0.0", - "promzard": "^1.0.0", - "read": "^3.0.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer/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, - "license": "MIT" - }, - "node_modules/inquirer/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, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bun-module": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", - "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.6.3" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "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==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ssh": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz", - "integrity": "sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "protocols": "^2.0.1" - } - }, - "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "text-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", - "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/json-schema-to-typescript": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.2.tgz", - "integrity": "sha512-+cRBw+bBJ3k783mZroDIgz1pLNPB4hvj6nnbHTWwEVl0dkW8qdZ+M9jWhBb+Y0FAdHvNsXACga3lewGO8lktrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^11.5.5", - "@types/json-schema": "^7.0.15", - "@types/lodash": "^4.17.7", - "glob": "^10.3.12", - "is-glob": "^4.0.3", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "prettier": "^3.2.5" - }, - "bin": { - "json2ts": "dist/src/cli.js" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stringify-nice": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", - "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", - "dev": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "license": "ISC" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "license": "MIT" - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "license": "(MIT OR Apache-2.0)", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/just-diff": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", - "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", - "dev": true, - "license": "MIT" - }, - "node_modules/just-diff-apply": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", - "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lerna": { - "version": "8.1.8", - "resolved": "https://registry.npmjs.org/lerna/-/lerna-8.1.8.tgz", - "integrity": "sha512-Rmo5ShMx73xM2CUcRixjmpZIXB7ZFlWEul1YvJyx/rH4onAwDHtUGD7Rx4NZYL8QSRiQHroglM2Oyq+WqA4BYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@lerna/create": "8.1.8", - "@npmcli/arborist": "7.5.4", - "@npmcli/package-json": "5.2.0", - "@npmcli/run-script": "8.1.0", - "@nx/devkit": ">=17.1.2 < 20", - "@octokit/plugin-enterprise-rest": "6.0.1", - "@octokit/rest": "19.0.11", - "aproba": "2.0.0", - "byte-size": "8.1.1", - "chalk": "4.1.0", - "clone-deep": "4.0.1", - "cmd-shim": "6.0.3", - "color-support": "1.1.3", - "columnify": "1.6.0", - "console-control-strings": "^1.1.0", - "conventional-changelog-angular": "7.0.0", - "conventional-changelog-core": "5.0.1", - "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "^8.2.0", - "dedent": "1.5.3", - "envinfo": "7.13.0", - "execa": "5.0.0", - "fs-extra": "^11.2.0", - "get-port": "5.1.1", - "get-stream": "6.0.0", - "git-url-parse": "14.0.0", - "glob-parent": "6.0.2", - "globby": "11.1.0", - "graceful-fs": "4.2.11", - "has-unicode": "2.0.1", - "import-local": "3.1.0", - "ini": "^1.3.8", - "init-package-json": "6.0.3", - "inquirer": "^8.2.4", - "is-ci": "3.0.1", - "is-stream": "2.0.0", - "jest-diff": ">=29.4.3 < 30", - "js-yaml": "4.1.0", - "libnpmaccess": "8.0.6", - "libnpmpublish": "9.0.9", - "load-json-file": "6.2.0", - "lodash": "^4.17.21", - "make-dir": "4.0.0", - "minimatch": "3.0.5", - "multimatch": "5.0.0", - "node-fetch": "2.6.7", - "npm-package-arg": "11.0.2", - "npm-packlist": "8.0.2", - "npm-registry-fetch": "^17.1.0", - "nx": ">=17.1.2 < 20", - "p-map": "4.0.0", - "p-map-series": "2.1.0", - "p-pipe": "3.1.0", - "p-queue": "6.6.2", - "p-reduce": "2.1.0", - "p-waterfall": "2.1.1", - "pacote": "^18.0.6", - "pify": "5.0.0", - "read-cmd-shim": "4.0.0", - "resolve-from": "5.0.0", - "rimraf": "^4.4.1", - "semver": "^7.3.8", - "set-blocking": "^2.0.0", - "signal-exit": "3.0.7", - "slash": "3.0.0", - "ssri": "^10.0.6", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "strong-log-transformer": "2.1.0", - "tar": "6.2.1", - "temp-dir": "1.0.0", - "typescript": ">=3 < 6", - "upath": "2.0.1", - "uuid": "^10.0.0", - "validate-npm-package-license": "3.0.4", - "validate-npm-package-name": "5.0.1", - "wide-align": "1.1.5", - "write-file-atomic": "5.0.1", - "write-pkg": "4.0.0", - "yargs": "17.7.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "lerna": "dist/cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/lerna/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/lerna/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, - "license": "MIT" - }, - "node_modules/lerna/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/lerna/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/lerna/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/lerna/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, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/libnpmaccess": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-8.0.6.tgz", - "integrity": "sha512-uM8DHDEfYG6G5gVivVl+yQd4pH3uRclHC59lzIbSvy7b5FEwR+mU49Zq1jEyRtRFv7+M99mUW9S0wL/4laT4lw==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^11.0.2", - "npm-registry-fetch": "^17.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/libnpmpublish": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-9.0.9.tgz", - "integrity": "sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==", - "dev": true, - "license": "ISC", - "dependencies": { - "ci-info": "^4.0.0", - "normalize-package-data": "^6.0.1", - "npm-package-arg": "^11.0.2", - "npm-registry-fetch": "^17.0.1", - "proc-log": "^4.2.0", - "semver": "^7.3.7", - "sigstore": "^2.2.0", - "ssri": "^10.0.6" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/libnpmpublish/node_modules/ci-info": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", - "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/lines-and-columns": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", - "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/live-compositor": { - "resolved": "live-compositor", - "link": true - }, - "node_modules/load-json-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", - "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^5.0.0", - "strip-bom": "^4.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/load-json-file/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lru-cache/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "license": "ISC" - }, - "node_modules/make-fetch-happen": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", - "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", - "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "proc-log": "^4.2.0", - "promise-retry": "^2.0.1", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/meow/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/meow/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/meow/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-fetch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", - "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-fetch/node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-fetch/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minizlib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz", - "integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==", - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/minizlib/node_modules/rimraf": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", - "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", - "license": "ISC", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mp4box": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/mp4box/-/mp4box-0.5.2.tgz", - "integrity": "sha512-zRmGlvxy+YdW3Dmt+TR4xPHynbxwXtAQDTN/Fo9N3LMxaUlB2C5KmZpzYyGKy4c7k4Jf3RCR0A2pm9SZELOLXw==", - "license": "BSD-3-Clause" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/multimatch": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", - "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/multimatch/node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true, - "license": "ISC" - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-examples": { - "resolved": "examples/node-examples", - "link": true - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.2.0.tgz", - "integrity": "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^4.1.0", - "semver": "^7.3.5", - "tar": "^6.2.1", - "which": "^4.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-machine-id": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", - "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true, - "license": "MIT" - }, - "node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/normalize-package-data": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", - "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^7.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-bundled": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", - "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-install-checks": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", - "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", - "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^7.0.0", - "proc-log": "^4.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-packlist": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", - "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", - "dev": true, - "license": "ISC", - "dependencies": { - "ignore-walk": "^6.0.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", - "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^11.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz", - "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/redact": "^2.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^13.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minizlib": "^2.1.2", - "npm-package-arg": "^11.0.0", - "proc-log": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm-registry-fetch/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm-registry-fetch/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nx": { - "version": "19.8.6", - "resolved": "https://registry.npmjs.org/nx/-/nx-19.8.6.tgz", - "integrity": "sha512-VkEbXoCil4UnSDOJP5OcIKZgI13hKsFlQNf6oKhUHCYWoEHvVqpvabMv/ZY9mGG78skvqAorzn85BS3evlt0Cw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@napi-rs/wasm-runtime": "0.2.4", - "@nrwl/tao": "19.8.6", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.7", - "axios": "^1.7.4", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^8.0.1", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", - "enquirer": "~2.3.6", - "figures": "3.2.0", - "flat": "^5.0.2", - "front-matter": "^4.0.2", - "ignore": "^5.0.4", - "jest-diff": "^29.4.1", - "jsonc-parser": "3.2.0", - "lines-and-columns": "2.0.3", - "minimatch": "9.0.3", - "node-machine-id": "1.1.12", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "ora": "5.3.0", - "semver": "^7.5.3", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js", - "nx-cloud": "bin/nx-cloud.js" - }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.8.6", - "@nx/nx-darwin-x64": "19.8.6", - "@nx/nx-freebsd-x64": "19.8.6", - "@nx/nx-linux-arm-gnueabihf": "19.8.6", - "@nx/nx-linux-arm64-gnu": "19.8.6", - "@nx/nx-linux-arm64-musl": "19.8.6", - "@nx/nx-linux-x64-gnu": "19.8.6", - "@nx/nx-linux-x64-musl": "19.8.6", - "@nx/nx-win32-arm64-msvc": "19.8.6", - "@nx/nx-win32-x64-msvc": "19.8.6" - }, - "peerDependencies": { - "@swc-node/register": "^1.8.0", - "@swc/core": "^1.3.85" - }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } - } - }, - "node_modules/nx/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/nx/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, - "license": "MIT" - }, - "node_modules/nx/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nx/node_modules/ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nx/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, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nx/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/nx/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map-series": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz", - "integrity": "sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/p-pipe": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz", - "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-queue": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", - "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.4", - "p-timeout": "^3.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-reduce": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", - "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-waterfall": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz", - "integrity": "sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-reduce": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/pacote": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", - "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^5.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/package-json": "^5.1.0", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^8.0.0", - "cacache": "^18.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^11.0.0", - "npm-packlist": "^8.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^17.0.0", - "proc-log": "^4.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^2.2.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-conflict-json": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz", - "integrity": "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "just-diff": "^6.0.0", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-json/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/parse-json/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, - "license": "MIT" - }, - "node_modules/parse-path": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", - "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", - "dev": true, - "license": "MIT", - "dependencies": { - "protocols": "^2.0.0" - } - }, - "node_modules/parse-url": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", - "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", - "dev": true, - "license": "MIT", - "dependencies": { - "parse-path": "^7.0.0" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/path-parser/-/path-parser-6.1.0.tgz", - "integrity": "sha512-nAB6J73z2rFcQP+870OHhpkHFj5kO4rPLc2Ol4Y3Ale7F6Hk1/cPKp7cQ8RznKF8FOSvu+YR9Xc6Gafk7DlpYA==", - "license": "MIT", - "dependencies": { - "search-params": "3.0.0", - "tslib": "^1.10.0" - } - }, - "node_modules/path-parser/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/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==", - "license": "ISC" - }, - "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.0", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/proc-log": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/proggy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/proggy/-/proggy-2.0.0.tgz", - "integrity": "sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/promise-all-reject-late": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", - "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", - "dev": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/promise-call-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-3.0.2.tgz", - "integrity": "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==", - "dev": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/promzard": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-1.0.2.tgz", - "integrity": "sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "read": "^3.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/protocols": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", - "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, - "license": "MIT" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-reconciler": { - "version": "0.29.2", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.2.tgz", - "integrity": "sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/read/-/read-3.0.1.tgz", - "integrity": "sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==", - "dev": true, - "license": "ISC", - "dependencies": { - "mute-stream": "^1.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-cmd-shim": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", - "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "node_modules/read-pkg/node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/read/node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", - "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", - "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^9.2.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", - "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.6" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.24.0", - "@rollup/rollup-android-arm64": "4.24.0", - "@rollup/rollup-darwin-arm64": "4.24.0", - "@rollup/rollup-darwin-x64": "4.24.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", - "@rollup/rollup-linux-arm-musleabihf": "4.24.0", - "@rollup/rollup-linux-arm64-gnu": "4.24.0", - "@rollup/rollup-linux-arm64-musl": "4.24.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", - "@rollup/rollup-linux-riscv64-gnu": "4.24.0", - "@rollup/rollup-linux-s390x-gnu": "4.24.0", - "@rollup/rollup-linux-x64-gnu": "4.24.0", - "@rollup/rollup-linux-x64-musl": "4.24.0", - "@rollup/rollup-win32-arm64-msvc": "4.24.0", - "@rollup/rollup-win32-ia32-msvc": "4.24.0", - "@rollup/rollup-win32-x64-msvc": "4.24.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-copy": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", - "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "engines": { - "node": ">=8.3" - } - }, - "node_modules/rollup-plugin-copy/node_modules/@types/fs-extra": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", - "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/rollup-plugin-copy/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/rollup-plugin-copy/node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rollup-plugin-copy/node_modules/is-plain-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", - "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rollup-plugin-copy/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/rollup-plugin-copy/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/rollup-plugin-dts": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-6.1.1.tgz", - "integrity": "sha512-aSHRcJ6KG2IHIioYlvAOcEq6U99sVtqDDKVhnwt70rW6tsz3tv5OSjEiWcgzfsHdLyGXZ/3b/7b/+Za3Y6r1XA==", - "dev": true, - "license": "LGPL-3.0-only", - "dependencies": { - "magic-string": "^0.30.10" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/Swatinem" - }, - "optionalDependencies": { - "@babel/code-frame": "^7.24.2" - }, - "peerDependencies": { - "rollup": "^3.29.4 || ^4", - "typescript": "^4.5 || ^5.0" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/search-params": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/search-params/-/search-params-3.0.0.tgz", - "integrity": "sha512-8CYNl/bjkEhXWbDTU/K7c2jQtrnqEffIPyOLMqygW/7/b+ym8UtQumcAZjOfMLjZKR6AxK5tOr9fChbQZCzPqg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sigstore": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", - "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^2.3.2", - "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "@sigstore/sign": "^2.3.2", - "@sigstore/tuf": "^2.3.4", - "@sigstore/verify": "^1.2.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "license": "MIT" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.1", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.20", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", - "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "license": "ISC", - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/ssri": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", - "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "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==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/synckit": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/temp-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/template-node-express-zustand": { - "resolved": "create-live-compositor/templates/node-express-zustand", - "link": true - }, - "node_modules/template-node-minimal": { - "resolved": "create-live-compositor/templates/node-minimal", - "link": true - }, - "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/treeverse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", - "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tuf-js": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", - "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tufjs/models": "2.0.1", - "debug": "^4.3.4", - "make-fetch-happen": "^13.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.10.0.tgz", - "integrity": "sha512-YIu230PeN7z9zpu/EtqCIuRVHPs4iSlqW6TEvjbyDAE3MZsSl2RXBo+5ag+lbABCG8sFM1WVKEXhlQ8Ml8A3Fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.10.0", - "@typescript-eslint/parser": "8.10.0", - "@typescript-eslint/utils": "8.10.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.10.0.tgz", - "integrity": "sha512-phuB3hoP7FFKbRXxjl+DRlQDuJqhpOnm5MmtROXyWi3uS/Xg2ZXqiQfcG2BJHiN4QKyzdOJi3NEn/qTnjUlkmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.10.0", - "@typescript-eslint/type-utils": "8.10.0", - "@typescript-eslint/utils": "8.10.0", - "@typescript-eslint/visitor-keys": "8.10.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.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.10.0.tgz", - "integrity": "sha512-E24l90SxuJhytWJ0pTQydFT46Nk0Z+bsLKo/L8rtQSL93rQ6byd1V/QbDpHUTdLPOMsBCcYXZweADNCfOCmOAg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "8.10.0", - "@typescript-eslint/types": "8.10.0", - "@typescript-eslint/typescript-estree": "8.10.0", - "@typescript-eslint/visitor-keys": "8.10.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.10.0.tgz", - "integrity": "sha512-AgCaEjhfql9MDKjMUxWvH7HjLeBqMCBfIaBbzzIcBbQPZE7CPh1m6FF+L75NUMJFMLYhCywJXIDEMa3//1A0dw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.10.0", - "@typescript-eslint/visitor-keys": "8.10.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.10.0.tgz", - "integrity": "sha512-PCpUOpyQSpxBn230yIcK+LeCQaXuxrgCm2Zk1S+PTIRJsEfU6nJ0TtwyH8pIwPK/vJoA+7TZtzyAJSGBz+s/dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "8.10.0", - "@typescript-eslint/utils": "8.10.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.10.0.tgz", - "integrity": "sha512-k/E48uzsfJCRRbGLapdZgrX52csmWJ2rcowwPvOZ8lwPUv3xW6CcFeJAXgx4uJm+Ge4+a4tFOkdYvSpxhRhg1w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.10.0.tgz", - "integrity": "sha512-3OE0nlcOHaMvQ8Xu5gAfME3/tWVDpb/HxtpUZ1WeOAksZ/h/gwrBzCklaGzwZT97/lBbbxJ16dMA98JMEngW4w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "8.10.0", - "@typescript-eslint/visitor-keys": "8.10.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "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.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.10.0.tgz", - "integrity": "sha512-Oq4uZ7JFr9d1ZunE/QKy5egcDRXT/FrS2z/nlxzPua2VHFtmMvFNDvpq1m/hq0ra+T52aUezfcjGRIB7vNJF9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.10.0", - "@typescript-eslint/types": "8.10.0", - "@typescript-eslint/typescript-estree": "8.10.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.10.0.tgz", - "integrity": "sha512-k8nekgqwr7FadWk548Lfph6V3r9OVqjzAIVskE7orMZR23cGJjAOVazsZSJW+ElyjfTM4wx/1g88Mi70DDtG9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.10.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/typescript-eslint/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, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/upath": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", - "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", - "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "license": "MIT" - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-name": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", - "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vite": { - "version": "5.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz", - "integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-plugin-static-copy": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.6.tgz", - "integrity": "sha512-3uSvsMwDVFZRitqoWHj0t4137Kz7UynnJeq1EZlRW7e25h2068fyIZX4ORCCOAkfp1FklGxJNVJBkBOD+PZIew==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.3", - "fast-glob": "^3.2.11", - "fs-extra": "^11.1.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "vite": "^5.0.0" - } - }, - "node_modules/walk-up-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", - "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", - "dev": true, - "license": "ISC" - }, - "node_modules/wasm-pack": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.13.0.tgz", - "integrity": "sha512-AmboGZEnZoIcVCzSlkLEmNFEqJN+IwgshJ5S7pi30uNUTce4LvWkifQzsQRxnWj47G8gkqZxlyGlyQplsnIS7w==", - "dev": true, - "hasInstallScript": true, - "license": "MIT OR Apache-2.0", - "dependencies": { - "binary-install": "^1.0.1" - }, - "bin": { - "wasm-pack": "run.js" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wide-align/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, - "license": "MIT" - }, - "node_modules/wide-align/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, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "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==", - "license": "MIT" - }, - "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==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/write-json-file": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz", - "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-indent": "^5.0.0", - "graceful-fs": "^4.1.15", - "make-dir": "^2.1.0", - "pify": "^4.0.1", - "sort-keys": "^2.0.0", - "write-file-atomic": "^2.4.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/write-json-file/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/write-json-file/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/write-json-file/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/write-json-file/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-json-file/node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/write-pkg": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz", - "integrity": "sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==", - "dev": true, - "license": "MIT", - "dependencies": { - "sort-keys": "^2.0.0", - "type-fest": "^0.4.1", - "write-json-file": "^3.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/write-pkg/node_modules/type-fest": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", - "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=6" - } - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs/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, - "license": "MIT" - }, - "node_modules/yargs/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, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zustand": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz", - "integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "1.2.2" - }, - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "immer": ">=9.0.6", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - } - } - } - } -} diff --git a/ts/package.json b/ts/package.json index 013a641d1..f4aeb0e78 100644 --- a/ts/package.json +++ b/ts/package.json @@ -1,44 +1,35 @@ { - "name": "live-compositor-workspace", + "name": "live-compositor-root", "private": true, "version": "0.1.0", + "type": "module", "scripts": { - "lint": "lerna run lint", - "lint:fix": "lerna run lint -- --fix", - "build": "lerna run build --concurrency=1", - "build:sdk": "lerna run build --concurrency 1 --scope @live-compositor/core --scope @live-compositor/node --scope @live-compositor/web --scope live-compositor", - "build:all": "npm run -w @live-compositor/browser-render build-wasm && npm run build", - "typecheck": "lerna run typecheck", - "clean": "lerna run clean", - "watch": "lerna run --parallel --stream watch --private", + "lint": "pnpm -r --no-bail run lint", + "lint:fix": "pnpm -r run lint -- --fix", + "build": "pnpm -r run build", + "build:sdk": "pnpm -C @live-compositor/core run build && pnpm -C @live-compositor/node run build && pnpm -C @live-compositor/web-wasm run build && pnpm -C live-compositor run build", + "build:all": "pnpm -C @live-compositor/browser-render run build-wasm && pnpm -r run build", + "typecheck": "pnpm -r run typecheck", + "clean": "pnpm -r run clean", + "watch": "pnpm -r --parallel --stream run watch", "generate-types": "node ./scripts/generateTypes.mjs" }, - "workspaces": [ - "live-compositor", - "@live-compositor/core", - "@live-compositor/node", - "@live-compositor/web-wasm", - "@live-compositor/browser-render", - "examples/node-examples", - "examples/vite-browser-render", - "create-live-compositor", - "create-live-compositor/templates/node-minimal", - "create-live-compositor/templates/node-express-zustand" - ], "devDependencies": { "@eslint/plugin-kit": "^0.2.0", - "@typescript-eslint/eslint-plugin": "^7.16.0", - "@typescript-eslint/parser": "^7.18.0", + "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/parser": "^8.8.1", "concurrently": "^9.0.1", - "eslint": "^8.57.0", + "eslint": "^9.12.0", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.3", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.9", + "globals": "^15.9.0", "json-schema-to-typescript": "^15.0.1", - "lerna": "^8.1.8", - "prettier": "^3.3.2", - "typescript": "^5.5.3" + "prettier": "^3.3.3", + "typescript": "5.5.3" }, "overrides": { "rollup-plugin-copy": { diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml new file mode 100644 index 000000000..1b0bd08d7 --- /dev/null +++ b/ts/pnpm-lock.yaml @@ -0,0 +1,4895 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@eslint/plugin-kit': + specifier: ^0.2.0 + version: 0.2.2 + '@typescript-eslint/eslint-plugin': + specifier: ^8.8.1 + version: 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/parser': + specifier: ^8.8.1 + version: 8.12.2(eslint@9.13.0)(typescript@5.5.3) + concurrently: + specifier: ^9.0.1 + version: 9.0.1 + eslint: + specifier: ^9.12.0 + version: 9.13.0 + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.0(eslint@9.13.0) + eslint-import-resolver-typescript: + specifier: ^3.6.3 + version: 3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.31.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0) + eslint-plugin-prettier: + specifier: ^5.2.1 + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.13.0))(eslint@9.13.0)(prettier@3.3.3) + eslint-plugin-react-hooks: + specifier: ^5.0.0 + version: 5.0.0(eslint@9.13.0) + eslint-plugin-react-refresh: + specifier: ^0.4.9 + version: 0.4.14(eslint@9.13.0) + globals: + specifier: ^15.9.0 + version: 15.11.0 + json-schema-to-typescript: + specifier: ^15.0.1 + version: 15.0.2 + prettier: + specifier: ^3.3.3 + version: 3.3.3 + typescript: + specifier: 5.5.3 + version: 5.5.3 + + '@live-compositor/browser-render': + dependencies: + live-compositor: + specifier: workspace:0.1.0 + version: link:../../live-compositor + devDependencies: + '@rollup/plugin-typescript': + specifier: ^11.1.6 + version: 11.1.6(rollup@4.24.3)(tslib@2.8.0)(typescript@5.5.3) + rollup: + specifier: ^4.21.2 + version: 4.24.3 + rollup-plugin-copy: + specifier: ^3.5.0 + version: 3.5.0 + rollup-plugin-dts: + specifier: ^6.1.1 + version: 6.1.1(rollup@4.24.3)(typescript@5.5.3) + wasm-pack: + specifier: ^0.13.0 + version: 0.13.1 + + '@live-compositor/core': + dependencies: + live-compositor: + specifier: workspace:^0.1.0 + version: link:../../live-compositor + react: + specifier: '*' + version: 18.3.1 + react-reconciler: + specifier: 0.29.2 + version: 0.29.2(react@18.3.1) + devDependencies: + '@types/react': + specifier: ^18.3.3 + version: 18.3.12 + '@types/react-reconciler': + specifier: 0.28.8 + version: 0.28.8 + + '@live-compositor/node': + dependencies: + '@live-compositor/core': + specifier: workspace:^0.1.0 + version: link:../core + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 + node-fetch: + specifier: ^2.6.7 + version: 2.7.0 + tar: + specifier: ^7.4.3 + version: 7.4.3 + uuid: + specifier: ^10.0.0 + version: 10.0.0 + ws: + specifier: ^8.18.0 + version: 8.18.0 + devDependencies: + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@types/node': + specifier: ^20.14.10 + version: 20.17.3 + '@types/node-fetch': + specifier: ^2.6.11 + version: 2.6.11 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 + '@types/ws': + specifier: ^8.5.12 + version: 8.5.12 + + '@live-compositor/web-wasm': + dependencies: + '@datastructures-js/queue': + specifier: ^4.2.3 + version: 4.2.3 + '@live-compositor/browser-render': + specifier: workspace:0.1.0-rc.4 + version: link:../browser-render + '@live-compositor/core': + specifier: workspace:0.1.0 + version: link:../core + live-compositor: + specifier: workspace:^0.1.0 + version: link:../../live-compositor + mp4box: + specifier: ^0.5.2 + version: 0.5.2 + path-parser: + specifier: ^6.1.0 + version: 6.1.0 + devDependencies: + '@types/react': + specifier: ^18.3.3 + version: 18.3.12 + + create-live-compositor: + dependencies: + chalk: + specifier: ^4.1.2 + version: 4.1.2 + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 + prompts: + specifier: ^2.4.2 + version: 2.4.2 + devDependencies: + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@types/prompts': + specifier: ^2.4.9 + version: 2.4.9 + + create-live-compositor/templates/node-express-zustand: + dependencies: + '@live-compositor/node': + specifier: workspace:^0.1.0 + version: link:../../../@live-compositor/node + express: + specifier: ^4.21.0 + version: 4.21.1 + live-compositor: + specifier: workspace:^0.1.0 + version: link:../../../live-compositor + react: + specifier: ^18.3.1 + version: 18.3.1 + zustand: + specifier: 4.5.5 + version: 4.5.5(@types/react@18.3.12)(react@18.3.1) + devDependencies: + '@types/express': + specifier: ^4.17.21 + version: 4.17.21 + '@types/node': + specifier: ^20.14.10 + version: 20.17.3 + '@types/react': + specifier: ^18.3.3 + version: 18.3.12 + + create-live-compositor/templates/node-minimal: + dependencies: + '@live-compositor/node': + specifier: workspace:^0.1.0 + version: link:../../../@live-compositor/node + live-compositor: + specifier: workspace:^0.1.0 + version: link:../../../live-compositor + react: + specifier: ^18.3.1 + version: 18.3.1 + devDependencies: + '@types/node': + specifier: ^20.14.10 + version: 20.17.3 + '@types/react': + specifier: ^18.3.3 + version: 18.3.12 + typescript: + specifier: ^5.5.3 + version: 5.5.3 + + examples/node-examples: + dependencies: + '@live-compositor/node': + specifier: workspace:^0.1.0 + version: link:../../@live-compositor/node + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 + live-compositor: + specifier: workspace:^0.1.0 + version: link:../../live-compositor + node-fetch: + specifier: ^2.6.7 + version: 2.7.0 + react: + specifier: ^18.3.1 + version: 18.3.1 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@20.17.3)(typescript@5.5.3) + devDependencies: + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@types/node': + specifier: ^20.14.10 + version: 20.17.3 + '@types/node-fetch': + specifier: ^2.6.11 + version: 2.6.11 + '@types/react': + specifier: ^18.3.3 + version: 18.3.12 + + examples/vite-browser-render: + dependencies: + '@live-compositor/browser-render': + specifier: workspace:0.1.0-rc.4 + version: link:../../@live-compositor/browser-render + '@live-compositor/web-wasm': + specifier: workspace:0.1.0-rc.0 + version: link:../../@live-compositor/web-wasm + live-compositor: + specifier: workspace:^0.1.0 + version: link:../../live-compositor + mp4box: + specifier: ^0.5.2 + version: 0.5.2 + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + devDependencies: + '@types/react': + specifier: ^18.3.3 + version: 18.3.12 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.1 + '@vitejs/plugin-react': + specifier: ^4.3.1 + version: 4.3.3(vite@5.4.10(@types/node@20.17.3)) + typescript: + specifier: ^5.5.3 + version: 5.5.3 + typescript-eslint: + specifier: ^8.0.1 + version: 8.12.2(eslint@9.13.0)(typescript@5.5.3) + vite: + specifier: ^5.4.1 + version: 5.4.10(@types/node@20.17.3) + vite-plugin-static-copy: + specifier: ^1.0.6 + version: 1.0.6(vite@5.4.10(@types/node@20.17.3)) + + live-compositor: + dependencies: + react: + specifier: '*' + version: 18.3.1 + devDependencies: + '@types/react': + specifier: ^18.3.3 + version: 18.3.12 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@apidevtools/json-schema-ref-parser@11.7.2': + resolution: {integrity: sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==} + engines: {node: '>= 16'} + + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.26.2': + resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.26.2': + resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.25.9': + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.25.9': + resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.26.2': + resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.25.9': + resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.25.9': + resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.25.9': + resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.26.0': + resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} + engines: {node: '>=6.9.0'} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@datastructures-js/queue@4.2.3': + resolution: {integrity: sha512-GWVMorC/xi2V2ta+Z/CPgPGHL2ZJozcj48g7y2nIX5GIGZGRrbShSHgvMViJwHJurUzJYOdIdRZnWDRrROFwJA==} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.18.0': + resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.7.0': + resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.1.0': + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.13.0': + resolution: {integrity: sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.4': + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.2': + resolution: {integrity: sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@rollup/plugin-typescript@11.1.6': + resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.14.0||^3.0.0||^4.0.0 + tslib: '*' + typescript: '>=3.7.0' + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + + '@rollup/pluginutils@5.1.3': + resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.24.3': + resolution: {integrity: sha512-ufb2CH2KfBWPJok95frEZZ82LtDl0A6QKTa8MoM+cWwDZvVGl5/jNb79pIhRvAalUu+7LD91VYR0nwRD799HkQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.24.3': + resolution: {integrity: sha512-iAHpft/eQk9vkWIV5t22V77d90CRofgR2006UiCjHcHJFVI1E0oBkQIAbz+pLtthFw3hWEmVB4ilxGyBf48i2Q==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.24.3': + resolution: {integrity: sha512-QPW2YmkWLlvqmOa2OwrfqLJqkHm7kJCIMq9kOz40Zo9Ipi40kf9ONG5Sz76zszrmIZZ4hgRIkez69YnTHgEz1w==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.24.3': + resolution: {integrity: sha512-KO0pN5x3+uZm1ZXeIfDqwcvnQ9UEGN8JX5ufhmgH5Lz4ujjZMAnxQygZAVGemFWn+ZZC0FQopruV4lqmGMshow==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.24.3': + resolution: {integrity: sha512-CsC+ZdIiZCZbBI+aRlWpYJMSWvVssPuWqrDy/zi9YfnatKKSLFCe6fjna1grHuo/nVaHG+kiglpRhyBQYRTK4A==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.24.3': + resolution: {integrity: sha512-F0nqiLThcfKvRQhZEzMIXOQG4EeX61im61VYL1jo4eBxv4aZRmpin6crnBJQ/nWnCsjH5F6J3W6Stdm0mBNqBg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.24.3': + resolution: {integrity: sha512-KRSFHyE/RdxQ1CSeOIBVIAxStFC/hnBgVcaiCkQaVC+EYDtTe4X7z5tBkFyRoBgUGtB6Xg6t9t2kulnX6wJc6A==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.24.3': + resolution: {integrity: sha512-h6Q8MT+e05zP5BxEKz0vi0DhthLdrNEnspdLzkoFqGwnmOzakEHSlXfVyA4HJ322QtFy7biUAVFPvIDEDQa6rw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.24.3': + resolution: {integrity: sha512-fKElSyXhXIJ9pqiYRqisfirIo2Z5pTTve5K438URf08fsypXrEkVmShkSfM8GJ1aUyvjakT+fn2W7Czlpd/0FQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.24.3': + resolution: {integrity: sha512-YlddZSUk8G0px9/+V9PVilVDC6ydMz7WquxozToozSnfFK6wa6ne1ATUjUvjin09jp34p84milxlY5ikueoenw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.24.3': + resolution: {integrity: sha512-yNaWw+GAO8JjVx3s3cMeG5Esz1cKVzz8PkTJSfYzE5u7A+NvGmbVFEHP+BikTIyYWuz0+DX9kaA3pH9Sqxp69g==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.24.3': + resolution: {integrity: sha512-lWKNQfsbpv14ZCtM/HkjCTm4oWTKTfxPmr7iPfp3AHSqyoTz5AgLemYkWLwOBWc+XxBbrU9SCokZP0WlBZM9lA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.24.3': + resolution: {integrity: sha512-HoojGXTC2CgCcq0Woc/dn12wQUlkNyfH0I1ABK4Ni9YXyFQa86Fkt2Q0nqgLfbhkyfQ6003i3qQk9pLh/SpAYw==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.24.3': + resolution: {integrity: sha512-mnEOh4iE4USSccBOtcrjF5nj+5/zm6NcNhbSEfR3Ot0pxBwvEn5QVUXcuOwwPkapDtGZ6pT02xLoPaNv06w7KQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.24.3': + resolution: {integrity: sha512-rMTzawBPimBQkG9NKpNHvquIUTQPzrnPxPbCY1Xt+mFkW7pshvyIS5kYgcf74goxXOQk0CP3EoOC1zcEezKXhw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.24.3': + resolution: {integrity: sha512-2lg1CE305xNvnH3SyiKwPVsTVLCg4TmNCF1z7PSHX2uZY2VbUpdkgAllVoISD7JO7zu+YynpWNSKAtOrX3AiuA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.24.3': + resolution: {integrity: sha512-9SjYp1sPyxJsPWuhOCX6F4jUMXGbVVd5obVpoVEi8ClZqo52ViZewA6eFz85y8ezuOA+uJMP5A5zo6Oz4S5rVQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.24.3': + resolution: {integrity: sha512-HGZgRFFYrMrP3TJlq58nR1xy8zHKId25vhmm5S9jETEfDf6xybPxsavFTJaufe2zgOGYJBskGlj49CwtEuFhWQ==} + cpu: [x64] + os: [win32] + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + + '@types/body-parser@1.19.5': + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/express-serve-static-core@4.19.6': + resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} + + '@types/express@4.17.21': + resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + + '@types/fs-extra@11.0.4': + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + + '@types/fs-extra@8.1.5': + resolution: {integrity: sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==} + + '@types/glob@7.2.0': + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + + '@types/http-errors@2.0.4': + resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/jsonfile@6.1.4': + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + + '@types/lodash@4.17.13': + resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} + + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + + '@types/minimatch@5.1.2': + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + + '@types/node-fetch@2.6.11': + resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} + + '@types/node@20.17.3': + resolution: {integrity: sha512-tSQrmKKatLDGnG92h40GD7FzUt0MjahaHwOME4VAFeeA/Xopayq5qLyQRy7Jg/pjgKIFBXuKcGhJo+UdYG55jQ==} + + '@types/prompts@2.4.9': + resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} + + '@types/prop-types@15.7.13': + resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} + + '@types/qs@6.9.16': + resolution: {integrity: sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/react-dom@18.3.1': + resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==} + + '@types/react-reconciler@0.28.8': + resolution: {integrity: sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==} + + '@types/react@18.3.12': + resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} + + '@types/send@0.17.4': + resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + + '@types/serve-static@1.15.7': + resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} + + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + + '@types/ws@8.5.12': + resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} + + '@typescript-eslint/eslint-plugin@8.12.2': + resolution: {integrity: sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@8.12.2': + resolution: {integrity: sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@8.12.2': + resolution: {integrity: sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.12.2': + resolution: {integrity: sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@8.12.2': + resolution: {integrity: sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.12.2': + resolution: {integrity: sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@8.12.2': + resolution: {integrity: sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + + '@typescript-eslint/visitor-keys@8.12.2': + resolution: {integrity: sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vitejs/plugin-react@4.3.3': + resolution: {integrity: sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axios@0.26.1: + resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + binary-install@1.1.0: + resolution: {integrity: sha512-rkwNGW+3aQVSZoD0/o3mfPN6Yxh3Id0R/xzTVBVVpGNlVz8EGwusksxRlbk/A5iKTZt9zkMn3qIqmAt3vpfbzg==} + engines: {node: '>=10'} + + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001675: + resolution: {integrity: sha512-/wV1bQwPrkLiQMjaJF5yUMVM/VdRPOCU8QZ+PmG6uW6DvYSrNY1bpwHI/3mOcUosLaJCzYDi5o91IQB51ft6cg==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concurrently@9.0.1: + resolution: {integrity: sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg==} + engines: {node: '>=18'} + hasBin: true + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.49: + resolution: {integrity: sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} + engines: {node: '>=10.13.0'} + + es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@9.1.0: + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.6.3: + resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.31.0: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-prettier@5.2.1: + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-react-hooks@5.0.0: + resolution: {integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-refresh@0.4.14: + resolution: {integrity: sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==} + peerDependencies: + eslint: '>=7' + + eslint-scope@8.2.0: + resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.13.0: + resolution: {integrity: sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + express@4.21.1: + resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} + engines: {node: '>= 0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.11.0: + resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@10.0.1: + resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==} + engines: {node: '>=8'} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-bun-module@1.2.1: + resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-object@3.0.1: + resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} + engines: {node: '>=0.10.0'} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-to-typescript@15.0.2: + resolution: {integrity: sha512-+cRBw+bBJ3k783mZroDIgz1pLNPB4hvj6nnbHTWwEVl0dkW8qdZ+M9jWhBb+Y0FAdHvNsXACga3lewGO8lktrw==} + engines: {node: '>=16.0.0'} + hasBin: true + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.30.12: + resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + minizlib@3.0.1: + resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} + engines: {node: '>= 18'} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + mp4box@0.5.2: + resolution: {integrity: sha512-zRmGlvxy+YdW3Dmt+TR4xPHynbxwXtAQDTN/Fo9N3LMxaUlB2C5KmZpzYyGKy4c7k4Jf3RCR0A2pm9SZELOLXw==} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-parser@6.1.0: + resolution: {integrity: sha512-nAB6J73z2rFcQP+870OHhpkHFj5kO4rPLc2Ol4Y3Ale7F6Hk1/cPKp7cQ8RznKF8FOSvu+YR9Xc6Gafk7DlpYA==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-to-regexp@0.1.10: + resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + engines: {node: '>=14'} + hasBin: true + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react-reconciler@0.29.2: + resolution: {integrity: sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^18.3.1 + + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + hasBin: true + + rollup-plugin-copy@3.5.0: + resolution: {integrity: sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==} + engines: {node: '>=8.3'} + + rollup-plugin-dts@6.1.1: + resolution: {integrity: sha512-aSHRcJ6KG2IHIioYlvAOcEq6U99sVtqDDKVhnwt70rW6tsz3tv5OSjEiWcgzfsHdLyGXZ/3b/7b/+Za3Y6r1XA==} + engines: {node: '>=16'} + peerDependencies: + rollup: ^3.29.4 || ^4 + typescript: ^4.5 || ^5.0 + + rollup@4.24.3: + resolution: {integrity: sha512-HBW896xR5HGmoksbi3JBDtmVzWiPAYqp7wip50hjQ67JbDz61nyoMPdqu1DvVW9asYb2M65Z20ZHsyJCMqMyDg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + search-params@3.0.0: + resolution: {integrity: sha512-8CYNl/bjkEhXWbDTU/K7c2jQtrnqEffIPyOLMqygW/7/b+ym8UtQumcAZjOfMLjZKR6AxK5tOr9fChbQZCzPqg==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + engines: {node: ^14.18.0 || >=16.0.0} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.8.0: + resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.12.2: + resolution: {integrity: sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + typescript@5.5.3: + resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-sync-external-store@1.2.2: + resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite-plugin-static-copy@1.0.6: + resolution: {integrity: sha512-3uSvsMwDVFZRitqoWHj0t4137Kz7UynnJeq1EZlRW7e25h2068fyIZX4ORCCOAkfp1FklGxJNVJBkBOD+PZIew==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 + + vite@5.4.10: + resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + wasm-pack@0.13.1: + resolution: {integrity: sha512-P9exD4YkjpDbw68xUhF3MDm/CC/3eTmmthyG5bHJ56kalxOTewOunxTke4SyF8MTXV6jUtNjXggPgrGmMtczGg==} + hasBin: true + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zustand@4.5.5: + resolution: {integrity: sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@apidevtools/json-schema-ref-parser@11.7.2': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.0 + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.26.2': {} + + '@babel/core@7.26.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + convert-source-map: 2.0.0 + debug: 4.3.7 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.26.2': + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.0.2 + + '@babel/helper-compilation-targets@7.25.9': + dependencies: + '@babel/compat-data': 7.26.2 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.25.9': {} + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helpers@7.26.0': + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + + '@babel/parser@7.26.2': + dependencies: + '@babel/types': 7.26.0 + + '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/template@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + + '@babel/traverse@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + debug: 4.3.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.26.0': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@datastructures-js/queue@4.2.3': {} + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@eslint-community/eslint-utils@4.4.1(eslint@9.13.0)': + dependencies: + eslint: 9.13.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.18.0': + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.7 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.7.0': {} + + '@eslint/eslintrc@3.1.0': + dependencies: + ajv: 6.12.6 + debug: 4.3.7 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.13.0': {} + + '@eslint/object-schema@2.1.4': {} + + '@eslint/plugin-kit@0.2.2': + dependencies: + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@jsdevtools/ono@7.1.3': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.1.1': {} + + '@rollup/plugin-typescript@11.1.6(rollup@4.24.3)(tslib@2.8.0)(typescript@5.5.3)': + dependencies: + '@rollup/pluginutils': 5.1.3(rollup@4.24.3) + resolve: 1.22.8 + typescript: 5.5.3 + optionalDependencies: + rollup: 4.24.3 + tslib: 2.8.0 + + '@rollup/pluginutils@5.1.3(rollup@4.24.3)': + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 4.0.2 + optionalDependencies: + rollup: 4.24.3 + + '@rollup/rollup-android-arm-eabi@4.24.3': + optional: true + + '@rollup/rollup-android-arm64@4.24.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.24.3': + optional: true + + '@rollup/rollup-darwin-x64@4.24.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.24.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.24.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.24.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.24.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.24.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.24.3': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.24.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.24.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.24.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.24.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.24.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.24.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.24.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.24.3': + optional: true + + '@rtsao/scc@1.1.0': {} + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.26.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.26.0 + + '@types/body-parser@1.19.5': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 20.17.3 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 20.17.3 + + '@types/estree@1.0.6': {} + + '@types/express-serve-static-core@4.19.6': + dependencies: + '@types/node': 20.17.3 + '@types/qs': 6.9.16 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + + '@types/express@4.17.21': + dependencies: + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 4.19.6 + '@types/qs': 6.9.16 + '@types/serve-static': 1.15.7 + + '@types/fs-extra@11.0.4': + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 20.17.3 + + '@types/fs-extra@8.1.5': + dependencies: + '@types/node': 20.17.3 + + '@types/glob@7.2.0': + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 20.17.3 + + '@types/http-errors@2.0.4': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/jsonfile@6.1.4': + dependencies: + '@types/node': 20.17.3 + + '@types/lodash@4.17.13': {} + + '@types/mime@1.3.5': {} + + '@types/minimatch@5.1.2': {} + + '@types/node-fetch@2.6.11': + dependencies: + '@types/node': 20.17.3 + form-data: 4.0.1 + + '@types/node@20.17.3': + dependencies: + undici-types: 6.19.8 + + '@types/prompts@2.4.9': + dependencies: + '@types/node': 20.17.3 + kleur: 3.0.3 + + '@types/prop-types@15.7.13': {} + + '@types/qs@6.9.16': {} + + '@types/range-parser@1.2.7': {} + + '@types/react-dom@18.3.1': + dependencies: + '@types/react': 18.3.12 + + '@types/react-reconciler@0.28.8': + dependencies: + '@types/react': 18.3.12 + + '@types/react@18.3.12': + dependencies: + '@types/prop-types': 15.7.13 + csstype: 3.1.3 + + '@types/send@0.17.4': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 20.17.3 + + '@types/serve-static@1.15.7': + dependencies: + '@types/http-errors': 2.0.4 + '@types/node': 20.17.3 + '@types/send': 0.17.4 + + '@types/uuid@10.0.0': {} + + '@types/ws@8.5.12': + dependencies: + '@types/node': 20.17.3 + + '@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint@9.13.0)(typescript@5.5.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/type-utils': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 8.12.2 + eslint: 9.13.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 8.12.2 + debug: 4.3.7 + eslint: 9.13.0 + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.12.2': + dependencies: + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/visitor-keys': 8.12.2 + + '@typescript-eslint/type-utils@8.12.2(eslint@9.13.0)(typescript@5.5.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.5.3) + '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + debug: 4.3.7 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - eslint + - supports-color + + '@typescript-eslint/types@8.12.2': {} + + '@typescript-eslint/typescript-estree@8.12.2(typescript@5.5.3)': + dependencies: + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/visitor-keys': 8.12.2 + debug: 4.3.7 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.12.2(eslint@9.13.0)(typescript@5.5.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0) + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.5.3) + eslint: 9.13.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@8.12.2': + dependencies: + '@typescript-eslint/types': 8.12.2 + eslint-visitor-keys: 3.4.3 + + '@vitejs/plugin-react@4.3.3(vite@5.4.10(@types/node@20.17.3))': + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.2 + vite: 5.4.10(@types/node@20.17.3) + transitivePeerDependencies: + - supports-color + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + acorn-jsx@5.3.2(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.14.0 + + acorn@8.14.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@4.1.3: {} + + argparse@2.0.1: {} + + array-buffer-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + + array-flatten@1.1.1: {} + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + + array-union@2.1.0: {} + + array.prototype.findlastindex@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.flat@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.flatmap@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + arraybuffer.prototype.slice@1.0.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + axios@0.26.1: + dependencies: + follow-redirects: 1.15.9 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + binary-extensions@2.3.0: {} + + binary-install@1.1.0: + dependencies: + axios: 0.26.1 + rimraf: 3.0.2 + tar: 6.2.1 + transitivePeerDependencies: + - debug + + body-parser@1.20.3: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.13.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.24.2: + dependencies: + caniuse-lite: 1.0.30001675 + electron-to-chromium: 1.5.49 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.2) + + bytes@3.1.2: {} + + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001675: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chownr@2.0.0: {} + + chownr@3.0.0: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@1.4.0: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + concat-map@0.0.1: {} + + concurrently@9.0.1: + dependencies: + chalk: 4.1.2 + lodash: 4.17.21 + rxjs: 7.8.1 + shell-quote: 1.8.1 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.0.6: {} + + cookie@0.7.1: {} + + create-require@1.1.1: {} + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + data-view-buffer@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-offset@1.0.0: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.3.7: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + destroy@1.2.0: {} + + diff@4.0.2: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.49: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + + enhanced-resolve@5.17.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + es-abstract@1.23.3: + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.2 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.3 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.0.2: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@9.1.0(eslint@9.13.0): + dependencies: + eslint: 9.13.0 + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.15.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.3.7 + enhanced-resolve: 5.17.1 + eslint: 9.13.0 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0) + fast-glob: 3.3.2 + get-tsconfig: 4.8.1 + is-bun-module: 1.2.1 + is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0) + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + eslint: 9.13.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.13.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0) + hasown: 2.0.2 + is-core-module: 2.15.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.13.0))(eslint@9.13.0)(prettier@3.3.3): + dependencies: + eslint: 9.13.0 + prettier: 3.3.3 + prettier-linter-helpers: 1.0.0 + synckit: 0.9.2 + optionalDependencies: + eslint-config-prettier: 9.1.0(eslint@9.13.0) + + eslint-plugin-react-hooks@5.0.0(eslint@9.13.0): + dependencies: + eslint: 9.13.0 + + eslint-plugin-react-refresh@0.4.14(eslint@9.13.0): + dependencies: + eslint: 9.13.0 + + eslint-scope@8.2.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@9.13.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.18.0 + '@eslint/core': 0.7.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.13.0 + '@eslint/plugin-kit': 0.2.2 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.3.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.7 + escape-string-regexp: 4.0.0 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@10.3.0: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + express@4.21.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.3 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.10 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@1.3.1: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + + flatted@3.3.1: {} + + follow-redirects@1.15.9: {} + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + forwarded@0.2.0: {} + + fresh@0.5.2: {} + + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + + functions-have-names@1.2.3: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-symbol-description@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + get-tsconfig@4.8.1: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@11.12.0: {} + + globals@14.0.0: {} + + globals@15.11.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + + globby@10.0.1: + dependencies: + '@types/glob': 7.2.0 + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + glob: 7.2.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.0.2: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + internal-slot@1.0.7: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + + ipaddr.js@1.9.1: {} + + is-array-buffer@3.0.4: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + is-bigint@1.0.4: + dependencies: + has-bigints: 1.0.2 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.1.2: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-bun-module@1.2.1: + dependencies: + semver: 7.6.3 + + is-callable@1.2.7: {} + + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-plain-object@3.0.1: {} + + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.0.2: {} + + json-buffer@3.0.1: {} + + json-schema-to-typescript@15.0.2: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.7.2 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.13 + glob: 10.4.5 + is-glob: 4.0.3 + js-yaml: 4.1.0 + lodash: 4.17.21 + minimist: 1.2.8 + prettier: 3.3.3 + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kleur@3.0.3: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.12: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + make-error@1.3.6: {} + + media-typer@0.3.0: {} + + merge-descriptors@1.0.3: {} + + merge2@1.4.1: {} + + methods@1.1.2: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minipass@7.1.2: {} + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + minizlib@3.0.1: + dependencies: + minipass: 7.1.2 + rimraf: 5.0.10 + + mkdirp@1.0.4: {} + + mkdirp@3.0.1: {} + + mp4box@0.5.2: {} + + ms@2.0.0: {} + + ms@2.1.3: {} + + nanoid@3.3.7: {} + + natural-compare@1.4.0: {} + + negotiator@0.6.3: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-releases@2.0.18: {} + + normalize-path@3.0.0: {} + + object-inspect@1.13.2: {} + + object-keys@1.1.1: {} + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + + object.values@1.2.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-parser@6.1.0: + dependencies: + search-params: 3.0.0 + tslib: 1.14.1 + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-to-regexp@0.1.10: {} + + path-type@4.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + possible-typed-array-names@1.0.0: {} + + postcss@8.4.47: + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.3.3: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + punycode@2.3.1: {} + + qs@6.13.0: + dependencies: + side-channel: 1.0.6 + + queue-microtask@1.2.3: {} + + range-parser@1.2.1: {} + + raw-body@2.5.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react-reconciler@0.29.2(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react-refresh@0.14.2: {} + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + regexp.prototype.flags@1.5.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + require-directory@2.1.1: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.8: + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.0.4: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + rimraf@5.0.10: + dependencies: + glob: 10.4.5 + + rollup-plugin-copy@3.5.0: + dependencies: + '@types/fs-extra': 8.1.5 + colorette: 1.4.0 + fs-extra: 8.1.0 + globby: 10.0.1 + is-plain-object: 3.0.1 + + rollup-plugin-dts@6.1.1(rollup@4.24.3)(typescript@5.5.3): + dependencies: + magic-string: 0.30.12 + rollup: 4.24.3 + typescript: 5.5.3 + optionalDependencies: + '@babel/code-frame': 7.26.2 + + rollup@4.24.3: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.24.3 + '@rollup/rollup-android-arm64': 4.24.3 + '@rollup/rollup-darwin-arm64': 4.24.3 + '@rollup/rollup-darwin-x64': 4.24.3 + '@rollup/rollup-freebsd-arm64': 4.24.3 + '@rollup/rollup-freebsd-x64': 4.24.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.24.3 + '@rollup/rollup-linux-arm-musleabihf': 4.24.3 + '@rollup/rollup-linux-arm64-gnu': 4.24.3 + '@rollup/rollup-linux-arm64-musl': 4.24.3 + '@rollup/rollup-linux-powerpc64le-gnu': 4.24.3 + '@rollup/rollup-linux-riscv64-gnu': 4.24.3 + '@rollup/rollup-linux-s390x-gnu': 4.24.3 + '@rollup/rollup-linux-x64-gnu': 4.24.3 + '@rollup/rollup-linux-x64-musl': 4.24.3 + '@rollup/rollup-win32-arm64-msvc': 4.24.3 + '@rollup/rollup-win32-ia32-msvc': 4.24.3 + '@rollup/rollup-win32-x64-msvc': 4.24.3 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rxjs@7.8.1: + dependencies: + tslib: 2.8.0 + + safe-array-concat@1.1.2: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-regex-test@1.0.3: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + + safer-buffer@2.1.2: {} + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + search-params@3.0.0: {} + + semver@6.3.1: {} + + semver@7.6.3: {} + + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.8.1: {} + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 + + signal-exit@4.1.0: {} + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + source-map-js@1.2.1: {} + + statuses@2.0.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string.prototype.trim@1.2.9: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + string.prototype.trimend@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + synckit@0.9.2: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.8.0 + + tapable@2.2.1: {} + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.1 + mkdirp: 3.0.1 + yallist: 5.0.0 + + text-table@0.2.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tr46@0.0.3: {} + + tree-kill@1.2.2: {} + + ts-api-utils@1.3.0(typescript@5.5.3): + dependencies: + typescript: 5.5.3 + + ts-node@10.9.2(@types/node@20.17.3)(typescript@5.5.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.17.3 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@1.14.1: {} + + tslib@2.8.0: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + typed-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + typed-array-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-byte-offset@1.0.2: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-length@1.0.6: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + + typescript-eslint@8.12.2(eslint@9.13.0)(typescript@5.5.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - eslint + - supports-color + + typescript@5.5.3: {} + + unbox-primitive@1.0.2: + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + + undici-types@6.19.8: {} + + universalify@0.1.2: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + update-browserslist-db@1.1.1(browserslist@4.24.2): + dependencies: + browserslist: 4.24.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-sync-external-store@1.2.2(react@18.3.1): + dependencies: + react: 18.3.1 + + utils-merge@1.0.1: {} + + uuid@10.0.0: {} + + v8-compile-cache-lib@3.0.1: {} + + vary@1.1.2: {} + + vite-plugin-static-copy@1.0.6(vite@5.4.10(@types/node@20.17.3)): + dependencies: + chokidar: 3.6.0 + fast-glob: 3.3.2 + fs-extra: 11.2.0 + picocolors: 1.1.1 + vite: 5.4.10(@types/node@20.17.3) + + vite@5.4.10(@types/node@20.17.3): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.47 + rollup: 4.24.3 + optionalDependencies: + '@types/node': 20.17.3 + fsevents: 2.3.3 + + wasm-pack@0.13.1: + dependencies: + binary-install: 1.1.0 + transitivePeerDependencies: + - debug + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-boxed-primitive@1.0.2: + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + + which-typed-array@1.1.15: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + ws@8.18.0: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yallist@5.0.0: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + zustand@4.5.5(@types/react@18.3.12)(react@18.3.1): + dependencies: + use-sync-external-store: 1.2.2(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + react: 18.3.1 diff --git a/ts/pnpm-workspace.yaml b/ts/pnpm-workspace.yaml new file mode 100644 index 000000000..8a5766dd2 --- /dev/null +++ b/ts/pnpm-workspace.yaml @@ -0,0 +1,11 @@ +packages: + - 'live-compositor' + - '@live-compositor/core' + - '@live-compositor/node' + - '@live-compositor/browser-render' + - '@live-compositor/web-wasm' + - 'examples/node-examples' + - 'examples/vite-browser-render' + - 'create-live-compositor' + - 'create-live-compositor/templates/node-minimal' + - 'create-live-compositor/templates/node-express-zustand' diff --git a/ts/tsconfig.base.json b/ts/tsconfig.json similarity index 100% rename from ts/tsconfig.base.json rename to ts/tsconfig.json From 721ce43356fb260d4537306a6213b8b6da6a1c73 Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:30:27 +0100 Subject: [PATCH 15/51] Add support for b-frame decoding (#844) --- Cargo.lock | 1 + .../pipeline/decoder/video/vulkan_video.rs | 12 +- integration_tests/examples/vulkan.rs | 17 +- vk-video/Cargo.toml | 1 + vk-video/examples/basic.rs | 8 +- vk-video/examples/wgpu.rs | 8 +- vk-video/src/lib.rs | 100 +++-- vk-video/src/parser.rs | 273 +++--------- vk-video/src/parser/au_splitter.rs | 16 +- vk-video/src/parser/nalu_parser.rs | 159 +++++++ vk-video/src/parser/nalu_splitter.rs | 47 +++ vk-video/src/parser/reference_manager.rs | 390 +++++++++++++----- vk-video/src/vulkan_decoder.rs | 172 ++++---- vk-video/src/vulkan_decoder/frame_sorter.rs | 69 ++++ .../src/vulkan_decoder/session_resources.rs | 86 +++- .../session_resources/images.rs | 6 +- vk-video/src/vulkan_decoder/vulkan_ctx.rs | 39 +- vk-video/src/vulkan_decoder/wrappers/mem.rs | 7 +- .../vulkan_decoder/wrappers/parameter_sets.rs | 181 ++++++++ vk-video/src/vulkan_decoder/wrappers/video.rs | 22 +- 20 files changed, 1118 insertions(+), 496 deletions(-) create mode 100644 vk-video/src/parser/nalu_parser.rs create mode 100644 vk-video/src/parser/nalu_splitter.rs create mode 100644 vk-video/src/vulkan_decoder/frame_sorter.rs diff --git a/Cargo.lock b/Cargo.lock index 44267b97f..920bce870 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3973,6 +3973,7 @@ name = "vk-video" version = "0.1.0" dependencies = [ "ash", + "bytes", "cfg_aliases 0.2.1", "derivative", "h264-reader", diff --git a/compositor_pipeline/src/pipeline/decoder/video/vulkan_video.rs b/compositor_pipeline/src/pipeline/decoder/video/vulkan_video.rs index 8e2363412..149723124 100644 --- a/compositor_pipeline/src/pipeline/decoder/video/vulkan_video.rs +++ b/compositor_pipeline/src/pipeline/decoder/video/vulkan_video.rs @@ -1,9 +1,9 @@ -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; use compositor_render::{Frame, FrameData, InputId, Resolution}; use crossbeam_channel::{Receiver, Sender}; use tracing::{debug, error, span, trace, warn, Level}; -use vk_video::{Decoder, VulkanCtx}; +use vk_video::{VulkanCtx, WgpuTexturesDeocder}; use crate::{ error::InputInitError, @@ -52,7 +52,7 @@ fn run_decoder_thread( chunks_receiver: Receiver>, frame_sender: Sender>, ) { - let mut decoder = match Decoder::new(vulkan_ctx) { + let mut decoder = match WgpuTexturesDeocder::new(vulkan_ctx) { Ok(decoder) => { init_result_sender.send(Ok(())).unwrap(); decoder @@ -79,7 +79,7 @@ fn run_decoder_thread( continue; } - let result = match decoder.decode_to_wgpu_textures(&chunk.data) { + let result = match decoder.decode(&chunk.data, Some(chunk.pts.as_micros() as u64)) { Ok(res) => res, Err(err) => { warn!("Failed to decode frame: {err}"); @@ -87,7 +87,7 @@ fn run_decoder_thread( } }; - for frame in result { + for vk_video::Frame { frame, pts } in result { let resolution = Resolution { width: frame.width() as usize, height: frame.height() as usize, @@ -95,7 +95,7 @@ fn run_decoder_thread( let frame = Frame { data: FrameData::Nv12WgpuTexture(frame.into()), - pts: chunk.pts, + pts: Duration::from_micros(pts.unwrap()), resolution, }; diff --git a/integration_tests/examples/vulkan.rs b/integration_tests/examples/vulkan.rs index 099515b41..fa884563c 100644 --- a/integration_tests/examples/vulkan.rs +++ b/integration_tests/examples/vulkan.rs @@ -74,10 +74,10 @@ fn client_code() -> Result<()> { }; const IP: &str = "127.0.0.1"; - const INPUT_PORT: u16 = 8002; + const INPUT_PORT: u16 = 8006; const OUTPUT_PORT: u16 = 8004; - const VIDEOS: u16 = 6; + const VIDEOS: u16 = 1; start_ffmpeg_receive(Some(OUTPUT_PORT), None)?; let config = read_config(); @@ -103,12 +103,12 @@ fn client_code() -> Result<()> { let mut children = Vec::new(); - for i in 1..VIDEOS + 1 { + for i in 0..VIDEOS { let input_id = InputId(format!("input_{i}").into()); let input_options = RegisterInputOptions { input_options: InputOptions::Rtp(RtpReceiverOptions { - port: RequestedPort::Exact(INPUT_PORT + 2 + 2 * i), + port: RequestedPort::Exact(INPUT_PORT + 2 * i), transport_protocol: TransportProtocol::Udp, stream: RtpStream { video: Some(InputVideoStream { @@ -179,13 +179,8 @@ fn client_code() -> Result<()> { Pipeline::start(&pipeline); - for i in 1..VIDEOS + 1 { - start_ffmpeg_send( - IP, - Some(INPUT_PORT + 2 + 2 * i), - None, - TestSample::BigBuckBunny, - )?; + for i in 0..VIDEOS { + start_ffmpeg_send(IP, Some(INPUT_PORT + 2 * i), None, TestSample::Sample)?; } let event_loop_fallback = || { diff --git a/vk-video/Cargo.toml b/vk-video/Cargo.toml index becd44adf..7256069af 100644 --- a/vk-video/Cargo.toml +++ b/vk-video/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/software-mansion/live-compositor" [dependencies] ash = "0.38.0" +bytes = "1" derivative = "2.2.0" h264-reader = { git = "https://github.com/membraneframework-labs/h264-reader.git", branch = "@jerzywilczek/scaling-lists" } thiserror = "1.0.59" diff --git a/vk-video/examples/basic.rs b/vk-video/examples/basic.rs index 388078fb3..17eaaf4ad 100644 --- a/vk-video/examples/basic.rs +++ b/vk-video/examples/basic.rs @@ -2,6 +2,8 @@ fn main() { use std::io::Write; + use vk_video::Frame; + let subscriber = tracing_subscriber::FmtSubscriber::builder() .with_max_level(tracing::Level::INFO) .finish(); @@ -26,14 +28,14 @@ fn main() { ) .unwrap(), ); - let mut decoder = vk_video::Decoder::new(vulkan_ctx).unwrap(); + let mut decoder = vk_video::BytesDecoder::new(vulkan_ctx).unwrap(); let mut output_file = std::fs::File::create("output.nv12").unwrap(); for chunk in h264_bytestream.chunks(256) { - let frames = decoder.decode_to_bytes(chunk).unwrap(); + let frames = decoder.decode(chunk, None).unwrap(); - for frame in frames { + for Frame { frame, .. } in frames { output_file.write_all(&frame).unwrap(); } } diff --git a/vk-video/examples/wgpu.rs b/vk-video/examples/wgpu.rs index 36f52be03..95d56096a 100644 --- a/vk-video/examples/wgpu.rs +++ b/vk-video/examples/wgpu.rs @@ -2,6 +2,8 @@ fn main() { use std::io::Write; + use vk_video::Frame; + let subscriber = tracing_subscriber::FmtSubscriber::builder() .with_max_level(tracing::Level::INFO) .finish(); @@ -25,16 +27,16 @@ fn main() { ) .unwrap(), ); - let mut decoder = vk_video::Decoder::new(vulkan_ctx.clone()).unwrap(); + let mut decoder = vk_video::WgpuTexturesDeocder::new(vulkan_ctx.clone()).unwrap(); let mut output_file = std::fs::File::create("output.nv12").unwrap(); for chunk in h264_bytestream.chunks(256) { - let frames = decoder.decode_to_wgpu_textures(chunk).unwrap(); + let frames = decoder.decode(chunk, None).unwrap(); let device = &vulkan_ctx.wgpu_ctx.device; let queue = &vulkan_ctx.wgpu_ctx.queue; - for frame in frames { + for Frame { frame, .. } in frames { let decoded_frame = download_wgpu_texture(device, queue, frame); output_file.write_all(&decoded_frame).unwrap(); } diff --git a/vk-video/src/lib.rs b/vk-video/src/lib.rs index 5826803b8..92fcbb26f 100644 --- a/vk-video/src/lib.rs +++ b/vk-video/src/lib.rs @@ -3,18 +3,13 @@ mod parser; mod vulkan_decoder; use parser::Parser; -use vulkan_decoder::VulkanDecoder; +use vulkan_decoder::{FrameSorter, VulkanDecoder}; pub use parser::ParserError; pub use vulkan_decoder::{VulkanCtx, VulkanCtxError, VulkanDecoderError}; pub use vulkan_decoder::WgpuCtx; -pub struct Decoder<'a> { - vulkan_decoder: VulkanDecoder<'a>, - parser: Parser, -} - #[derive(Debug, thiserror::Error)] pub enum DecoderError { #[error("Decoder error: {0}")] @@ -24,46 +19,89 @@ pub enum DecoderError { ParserError(#[from] ParserError), } -impl<'a> Decoder<'a> { +pub struct Frame { + pub frame: T, + pub pts: Option, +} + +pub struct WgpuTexturesDeocder<'a> { + vulkan_decoder: VulkanDecoder<'a>, + parser: Parser, + frame_sorter: FrameSorter, +} + +impl WgpuTexturesDeocder<'_> { pub fn new(vulkan_ctx: std::sync::Arc) -> Result { let parser = Parser::default(); let vulkan_decoder = VulkanDecoder::new(vulkan_ctx)?; + let frame_sorter = FrameSorter::::new(); Ok(Self { parser, vulkan_decoder, + frame_sorter, }) } -} -impl Decoder<'_> { - /// The result is a [`Vec`] of [`Vec`]. Each [`Vec`] contains a single frame in the - /// NV12 format. - pub fn decode_to_bytes( + // TODO: the below hasn't been verified. + /// The produced textures have the [`wgpu::TextureFormat::NV12`] format and can be used as a copy source or a texture binding. + pub fn decode( &mut self, h264_bytestream: &[u8], - ) -> Result>, DecoderError> { - let instructions = self - .parser - .parse(h264_bytestream) - .into_iter() - .collect::, _>>()?; - - Ok(self.vulkan_decoder.decode_to_bytes(&instructions)?) + pts: Option, + ) -> Result>, DecoderError> { + let instructions = self.parser.parse(h264_bytestream, pts)?; + + let unsorted_frames = self.vulkan_decoder.decode_to_wgpu_textures(&instructions)?; + + let mut result = Vec::new(); + + for unsorted_frame in unsorted_frames { + let mut sorted_frames = self.frame_sorter.put(unsorted_frame); + result.append(&mut sorted_frames); + } + + Ok(result) } +} - // TODO: the below hasn't been verified. - /// The produced textures have the [`wgpu::TextureFormat::NV12`] format and can be used as a copy source or a texture binding. - pub fn decode_to_wgpu_textures( +pub struct BytesDecoder<'a> { + vulkan_decoder: VulkanDecoder<'a>, + parser: Parser, + frame_sorter: FrameSorter>, +} + +impl BytesDecoder<'_> { + pub fn new(vulkan_ctx: std::sync::Arc) -> Result { + let parser = Parser::default(); + let vulkan_decoder = VulkanDecoder::new(vulkan_ctx)?; + let frame_sorter = FrameSorter::>::new(); + + Ok(Self { + parser, + vulkan_decoder, + frame_sorter, + }) + } + + /// The result is a sequence of frames. Te payload of each [`Frame`] struct is a [`Vec`]. Each [`Vec`] contains a single + /// decoded frame in the [NV12 format](https://en.wikipedia.org/wiki/YCbCr#4:2:0). + pub fn decode( &mut self, h264_bytestream: &[u8], - ) -> Result, DecoderError> { - let instructions = self - .parser - .parse(h264_bytestream) - .into_iter() - .collect::, _>>()?; - - Ok(self.vulkan_decoder.decode_to_wgpu_textures(&instructions)?) + pts: Option, + ) -> Result>>, DecoderError> { + let instructions = self.parser.parse(h264_bytestream, pts)?; + + let unsorted_frames = self.vulkan_decoder.decode_to_bytes(&instructions)?; + + let mut result = Vec::new(); + + for unsorted_frame in unsorted_frames { + let mut sorted_frames = self.frame_sorter.put(unsorted_frame); + result.append(&mut sorted_frames); + } + + Ok(result) } } diff --git a/vk-video/src/parser.rs b/vk-video/src/parser.rs index 1fbcc41c0..03648e8fc 100644 --- a/vk-video/src/parser.rs +++ b/vk-video/src/parser.rs @@ -1,26 +1,28 @@ -use std::{ - io::Read, - sync::{mpsc, Arc}, -}; +use std::sync::{mpsc, Arc}; +use au_splitter::AUSplitter; use h264_reader::{ annexb::AnnexBReader, - nal::{pps::PicParameterSet, slice::SliceHeader, sps::SeqParameterSet, Nal, RefNal}, - push::{AccumulatedNalHandler, NalAccumulator, NalInterest}, + nal::{pps::PicParameterSet, slice::SliceHeader, sps::SeqParameterSet}, + push::NalAccumulator, }; -use reference_manager::ReferenceContext; -use tracing::trace; +use nalu_parser::{NalReceiver, ParsedNalu}; +use nalu_splitter::NALUSplitter; +use reference_manager::{ReferenceContext, ReferenceManagementError}; + +pub(crate) use reference_manager::ReferenceId; mod au_splitter; +mod nalu_parser; +mod nalu_splitter; mod reference_manager; -pub use reference_manager::{ReferenceId, ReferenceManagementError}; - #[derive(Clone, derivative::Derivative)] #[derivative(Debug)] #[allow(non_snake_case)] pub struct DecodeInformation { - pub(crate) reference_list: Option>, + pub(crate) reference_list_l0: Option>, + pub(crate) reference_list_l1: Option>, #[derivative(Debug = "ignore")] pub(crate) rbsp_bytes: Vec, pub(crate) slice_indices: Vec, @@ -29,14 +31,17 @@ pub struct DecodeInformation { pub(crate) sps_id: u8, pub(crate) pps_id: u8, pub(crate) picture_info: PictureInfo, + pub(crate) pts: Option, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] #[allow(non_snake_case)] pub(crate) struct ReferencePictureInfo { pub(crate) id: ReferenceId, pub(crate) LongTermPicNum: Option, - pub(crate) picture_info: PictureInfo, + pub(crate) non_existing: bool, + pub(crate) FrameNum: u16, + pub(crate) PicOrderCnt: [i32; 2], } #[derive(Debug, Clone, Copy)] @@ -45,17 +50,14 @@ pub(crate) struct PictureInfo { pub(crate) used_for_long_term_reference: bool, pub(crate) non_existing: bool, pub(crate) FrameNum: u16, - pub(crate) PicOrderCnt: [i32; 2], + pub(crate) PicOrderCnt_for_decoding: [i32; 2], + pub(crate) PicOrderCnt_as_reference_pic: [i32; 2], } #[derive(Debug, Clone)] pub enum DecoderInstruction { Decode { decode_info: DecodeInformation, - }, - - DecodeAndStoreAs { - decode_info: DecodeInformation, reference_id: ReferenceId, }, @@ -97,213 +99,66 @@ pub enum ParserError { SliceParseError(h264_reader::nal::slice::SliceHeaderError), } -struct NalReceiver { - parser_ctx: h264_reader::Context, - au_splitter: au_splitter::AUSplitter, - reference_ctx: ReferenceContext, - debug_channel: mpsc::Sender, - decoder_channel: mpsc::Sender>, -} - -impl AccumulatedNalHandler for NalReceiver { - fn nal(&mut self, nal: RefNal<'_>) -> NalInterest { - if !nal.is_complete() { - return NalInterest::Buffer; - } - - match self.handle_nal(nal) { - Ok((debug_nalu, instructions)) => { - self.debug_channel.send(debug_nalu).unwrap(); - for instruction in instructions { - self.decoder_channel.send(Ok(instruction)).unwrap(); - } - } - - Err(err) => { - self.decoder_channel.send(Err(err)).unwrap(); - } - } - - NalInterest::Ignore - } -} - -impl NalReceiver { - fn handle_nal( - &mut self, - nal: RefNal<'_>, - ) -> Result<(NaluDebugInfo, Vec), ParserError> { - let nal_unit_type = nal - .header() - .map_err(ParserError::NalHeaderParseError)? - .nal_unit_type(); - - match nal_unit_type { - h264_reader::nal::UnitType::SeqParameterSet => { - let parsed = h264_reader::nal::sps::SeqParameterSet::from_bits(nal.rbsp_bits()) - .map_err(ParserError::SpsParseError)?; - - // Perhaps this shouldn't be here, but this is the only place we process sps - // before sending them to the decoder. It also seems that this is the only thing we - // need to check about the sps. - if parsed.gaps_in_frame_num_value_allowed_flag { - // TODO: what else to do here? sure we'll throw an error, but shouldn't we also - // terminate the parser somehow? - // perhaps this should be considered in other places we throw errors too - Err(ParserError::GapsInFrameNumNotSupported) - } else { - self.parser_ctx.put_seq_param_set(parsed.clone()); - Ok(( - NaluDebugInfo::Sps(parsed.clone()), - vec![DecoderInstruction::Sps(parsed)], - )) - } - } - - h264_reader::nal::UnitType::PicParameterSet => { - let parsed = h264_reader::nal::pps::PicParameterSet::from_bits( - &self.parser_ctx, - nal.rbsp_bits(), - ) - .map_err(ParserError::PpsParseError)?; - - self.parser_ctx.put_pic_param_set(parsed.clone()); - - Ok(( - NaluDebugInfo::Pps(parsed.clone()), - vec![DecoderInstruction::Pps(parsed)], - )) - } - - h264_reader::nal::UnitType::SliceLayerWithoutPartitioningNonIdr - | h264_reader::nal::UnitType::SliceLayerWithoutPartitioningIdr => { - let (header, sps, pps) = h264_reader::nal::slice::SliceHeader::from_bits( - &self.parser_ctx, - &mut nal.rbsp_bits(), - nal.header().unwrap(), - ) - .map_err(ParserError::SliceParseError)?; - - let header = Arc::new(header); - - let debug_nalu = match nal_unit_type { - h264_reader::nal::UnitType::SliceLayerWithoutPartitioningIdr => { - NaluDebugInfo::SliceWithoutPartitioningHeaderIdr(header.clone()) - } - h264_reader::nal::UnitType::SliceLayerWithoutPartitioningNonIdr => { - NaluDebugInfo::SliceWithoutPartitioningHeaderNonIdr(header.clone()) - } - _ => unreachable!(), - }; - - let mut rbsp_bytes = vec![0, 0, 0, 1]; - nal.reader().read_to_end(&mut rbsp_bytes).unwrap(); - let slice = Slice { - nal_header: nal.header().unwrap(), - header, - pps_id: pps.pic_parameter_set_id, - rbsp_bytes, - }; - - let Some(slices) = self.au_splitter.put_slice(slice) else { - return Ok((debug_nalu, Vec::new())); - }; - - let instructions = self.reference_ctx.put_picture(slices, sps, pps)?; - - Ok((debug_nalu, instructions)) - } - - h264_reader::nal::UnitType::Unspecified(_) - | h264_reader::nal::UnitType::SliceDataPartitionALayer - | h264_reader::nal::UnitType::SliceDataPartitionBLayer - | h264_reader::nal::UnitType::SliceDataPartitionCLayer - | h264_reader::nal::UnitType::SEI - | h264_reader::nal::UnitType::AccessUnitDelimiter - | h264_reader::nal::UnitType::EndOfSeq - | h264_reader::nal::UnitType::EndOfStream - | h264_reader::nal::UnitType::FillerData - | h264_reader::nal::UnitType::SeqParameterSetExtension - | h264_reader::nal::UnitType::PrefixNALUnit - | h264_reader::nal::UnitType::SubsetSeqParameterSet - | h264_reader::nal::UnitType::DepthParameterSet - | h264_reader::nal::UnitType::SliceLayerWithoutPartitioningAux - | h264_reader::nal::UnitType::SliceExtension - | h264_reader::nal::UnitType::SliceExtensionViewComponent - | h264_reader::nal::UnitType::Reserved(_) => Ok(( - NaluDebugInfo::Other(format!("{:?}", nal.header().unwrap().nal_unit_type())), - Vec::new(), - )), - } - } -} - -trait SpsExt { - fn max_frame_num(&self) -> i64; -} - -impl SpsExt for SeqParameterSet { - fn max_frame_num(&self) -> i64 { - 1 << self.log2_max_frame_num() - } -} - -#[derive(Debug)] -// this struct is only ever printed out in debug mode, but clippy detects this as it not being -// used. -#[allow(dead_code)] -pub enum NaluDebugInfo { - Sps(SeqParameterSet), - Pps(PicParameterSet), - SliceWithoutPartitioningHeaderNonIdr(Arc), - SliceWithoutPartitioningHeaderIdr(Arc), - Other(String), -} - -pub struct Slice { - pub nal_header: h264_reader::nal::NalHeader, - pub pps_id: h264_reader::nal::pps::PicParamSetId, - pub header: Arc, - pub rbsp_bytes: Vec, -} - pub struct Parser { reader: AnnexBReader>, - debug_channel: mpsc::Receiver, - decoder_channel: mpsc::Receiver>, + reference_ctx: ReferenceContext, + au_splitter: AUSplitter, + receiver: mpsc::Receiver>, + nalu_splitter: NALUSplitter, } impl Default for Parser { fn default() -> Self { - let (debug_tx, debug_rx) = mpsc::channel(); - let (decoder_tx, decoder_rx) = mpsc::channel(); + let (tx, rx) = mpsc::channel(); Parser { - reader: AnnexBReader::accumulate(NalReceiver { - reference_ctx: ReferenceContext::default(), - au_splitter: au_splitter::AUSplitter::default(), - debug_channel: debug_tx, - decoder_channel: decoder_tx, - parser_ctx: h264_reader::Context::new(), - }), - debug_channel: debug_rx, - decoder_channel: decoder_rx, + reader: AnnexBReader::accumulate(NalReceiver::new(tx)), + reference_ctx: ReferenceContext::default(), + au_splitter: AUSplitter::default(), + receiver: rx, + nalu_splitter: NALUSplitter::default(), } } } impl Parser { - pub fn parse(&mut self, bytes: &[u8]) -> Vec> { - self.reader.push(bytes); + pub fn parse( + &mut self, + bytes: &[u8], + pts: Option, + ) -> Result, ParserError> { + let nalus = self.nalu_splitter.push(bytes, pts); + let nalus = nalus + .into_iter() + .map(|(nalu, pts)| { + self.reader.push(&nalu); + (self.receiver.try_recv().unwrap(), pts) + }) + .collect::>(); let mut instructions = Vec::new(); - while let Ok(instruction) = self.decoder_channel.try_recv() { - instructions.push(instruction); - } - while let Ok(nalu) = self.debug_channel.try_recv() { - trace!("parsed nalu: {nalu:#?}"); + for (nalu, pts) in nalus { + let nalu = nalu?; + match nalu { + ParsedNalu::Sps(seq_parameter_set) => { + instructions.push(DecoderInstruction::Sps(seq_parameter_set)) + } + ParsedNalu::Pps(pic_parameter_set) => { + instructions.push(DecoderInstruction::Pps(pic_parameter_set)) + } + ParsedNalu::Slice(slice) => { + let Some(slices) = self.au_splitter.put_slice(slice, pts) else { + continue; + }; + + let mut inst = self.reference_ctx.put_picture(slices)?; + instructions.append(&mut inst); + } + + ParsedNalu::Other(_) => {} + } } - instructions + Ok(instructions) } } diff --git a/vk-video/src/parser/au_splitter.rs b/vk-video/src/parser/au_splitter.rs index 580bd4b28..5abf6018a 100644 --- a/vk-video/src/parser/au_splitter.rs +++ b/vk-video/src/parser/au_splitter.rs @@ -1,31 +1,35 @@ use h264_reader::nal::slice::PicOrderCountLsb; -use super::Slice; +use super::nalu_parser::Slice; #[derive(Default)] pub(crate) struct AUSplitter { - buffered_nals: Vec, + buffered_nals: Vec<(Slice, Option)>, } impl AUSplitter { - pub(crate) fn put_slice(&mut self, slice: Slice) -> Option> { + pub(crate) fn put_slice( + &mut self, + slice: Slice, + pts: Option, + ) -> Option)>> { if self.is_new_au(&slice) { let au = std::mem::take(&mut self.buffered_nals); - self.buffered_nals.push(slice); + self.buffered_nals.push((slice, pts)); if !au.is_empty() { Some(au) } else { None } } else { - self.buffered_nals.push(slice); + self.buffered_nals.push((slice, pts)); None } } /// returns `true` if `slice` is a first slice in an Access Unit fn is_new_au(&self, slice: &Slice) -> bool { - let Some(last) = self.buffered_nals.last() else { + let Some((last, _)) = self.buffered_nals.last() else { return true; }; diff --git a/vk-video/src/parser/nalu_parser.rs b/vk-video/src/parser/nalu_parser.rs new file mode 100644 index 000000000..3f188cd7c --- /dev/null +++ b/vk-video/src/parser/nalu_parser.rs @@ -0,0 +1,159 @@ +use std::{ + io::Read, + sync::{mpsc, Arc}, +}; + +use h264_reader::{ + nal::{pps::PicParameterSet, slice::SliceHeader, sps::SeqParameterSet, Nal, RefNal}, + push::{AccumulatedNalHandler, NalInterest}, + Context, +}; + +use super::ParserError; + +pub(crate) struct NalReceiver { + parser_ctx: h264_reader::Context, + sender: mpsc::Sender>, +} + +impl AccumulatedNalHandler for NalReceiver { + fn nal(&mut self, nal: RefNal<'_>) -> NalInterest { + if !nal.is_complete() { + return NalInterest::Buffer; + } + + let result = self.handle_nal(nal); + self.sender.send(result).unwrap(); + + NalInterest::Ignore + } +} + +impl NalReceiver { + pub(crate) fn new(sender: mpsc::Sender>) -> Self { + Self { + sender, + parser_ctx: Context::default(), + } + } + + fn handle_nal(&mut self, nal: RefNal<'_>) -> Result { + let nal_unit_type = nal + .header() + .map_err(ParserError::NalHeaderParseError)? + .nal_unit_type(); + + match nal_unit_type { + h264_reader::nal::UnitType::SeqParameterSet => { + let parsed = h264_reader::nal::sps::SeqParameterSet::from_bits(nal.rbsp_bits()) + .map_err(ParserError::SpsParseError)?; + + // Perhaps this shouldn't be here, but this is the only place we process sps + // before sending them to the decoder. It also seems that this is the only thing we + // need to check about the sps. + if parsed.gaps_in_frame_num_value_allowed_flag { + // TODO: what else to do here? sure we'll throw an error, but shouldn't we also + // terminate the parser somehow? + // perhaps this should be considered in other places we throw errors too + Err(ParserError::GapsInFrameNumNotSupported) + } else { + self.parser_ctx.put_seq_param_set(parsed.clone()); + Ok(ParsedNalu::Sps(parsed.clone())) + } + } + + h264_reader::nal::UnitType::PicParameterSet => { + let parsed = h264_reader::nal::pps::PicParameterSet::from_bits( + &self.parser_ctx, + nal.rbsp_bits(), + ) + .map_err(ParserError::PpsParseError)?; + + self.parser_ctx.put_pic_param_set(parsed.clone()); + + Ok(ParsedNalu::Pps(parsed.clone())) + } + + h264_reader::nal::UnitType::SliceLayerWithoutPartitioningNonIdr + | h264_reader::nal::UnitType::SliceLayerWithoutPartitioningIdr => { + let (header, sps, pps) = h264_reader::nal::slice::SliceHeader::from_bits( + &self.parser_ctx, + &mut nal.rbsp_bits(), + nal.header().unwrap(), + ) + .map_err(ParserError::SliceParseError)?; + + let header = Arc::new(header); + + let mut rbsp_bytes = vec![0, 0, 0, 1]; + nal.reader().read_to_end(&mut rbsp_bytes).unwrap(); + let slice = Slice { + nal_header: nal.header().unwrap(), + header, + pps_id: pps.pic_parameter_set_id, + rbsp_bytes, + sps: sps.clone(), + pps: pps.clone(), + }; + + Ok(ParsedNalu::Slice(slice)) + } + + h264_reader::nal::UnitType::Unspecified(_) + | h264_reader::nal::UnitType::SliceDataPartitionALayer + | h264_reader::nal::UnitType::SliceDataPartitionBLayer + | h264_reader::nal::UnitType::SliceDataPartitionCLayer + | h264_reader::nal::UnitType::SEI + | h264_reader::nal::UnitType::AccessUnitDelimiter + | h264_reader::nal::UnitType::EndOfSeq + | h264_reader::nal::UnitType::EndOfStream + | h264_reader::nal::UnitType::FillerData + | h264_reader::nal::UnitType::SeqParameterSetExtension + | h264_reader::nal::UnitType::PrefixNALUnit + | h264_reader::nal::UnitType::SubsetSeqParameterSet + | h264_reader::nal::UnitType::DepthParameterSet + | h264_reader::nal::UnitType::SliceLayerWithoutPartitioningAux + | h264_reader::nal::UnitType::SliceExtension + | h264_reader::nal::UnitType::SliceExtensionViewComponent + | h264_reader::nal::UnitType::Reserved(_) => Ok(ParsedNalu::Other(format!( + "{:?}", + nal.header().unwrap().nal_unit_type() + ))), + } + } +} + +pub(crate) trait SpsExt { + fn max_frame_num(&self) -> i64; +} + +impl SpsExt for SeqParameterSet { + fn max_frame_num(&self) -> i64 { + 1 << self.log2_max_frame_num() + } +} + +#[derive(Debug)] +// one variant of this enum is only ever printed out in debug mode, but clippy detects this as it not being +// used. +#[allow(dead_code)] +pub enum ParsedNalu { + Sps(SeqParameterSet), + Pps(PicParameterSet), + Slice(Slice), + Other(String), +} + +#[derive(derivative::Derivative)] +#[derivative(Debug)] +pub struct Slice { + pub nal_header: h264_reader::nal::NalHeader, + pub pps_id: h264_reader::nal::pps::PicParamSetId, + pub header: Arc, + #[derivative(Debug = "ignore")] + pub rbsp_bytes: Vec, + #[derivative(Debug = "ignore")] + pub sps: h264_reader::nal::sps::SeqParameterSet, + #[derivative(Debug = "ignore")] + pub pps: h264_reader::nal::pps::PicParameterSet, +} diff --git a/vk-video/src/parser/nalu_splitter.rs b/vk-video/src/parser/nalu_splitter.rs new file mode 100644 index 000000000..289b99950 --- /dev/null +++ b/vk-video/src/parser/nalu_splitter.rs @@ -0,0 +1,47 @@ +use bytes::{BufMut, BytesMut}; + +#[derive(Debug, Default)] +pub(crate) struct NALUSplitter { + buffer: BytesMut, + pts: Option, +} + +fn find_nalu_start_code(buf: &[u8]) -> Option { + if buf.is_empty() { + return None; + }; + + buf.windows(3) + .enumerate() + .filter(|(_, window)| **window == [0, 0, 1]) + .filter(|(i, window)| !(*i == 0 || (*i == 1 && window[0] == 0))) + .map(|(i, _)| i + 3) + .next() +} + +impl NALUSplitter { + pub(crate) fn push( + &mut self, + bytestream: &[u8], + pts: Option, + ) -> Vec<(Vec, Option)> { + let mut output_pts = if self.buffer.is_empty() { + pts + } else { + self.pts + }; + + self.buffer.put(bytestream); + let mut result = Vec::new(); + + while let Some(i) = find_nalu_start_code(&self.buffer) { + let nalu = self.buffer.split_to(i); + result.push((nalu.to_vec(), output_pts)); + output_pts = pts; + } + + self.pts = pts; + + result + } +} diff --git a/vk-video/src/parser/reference_manager.rs b/vk-video/src/parser/reference_manager.rs index 4eb5f8d4f..33a9c5a48 100644 --- a/vk-video/src/parser/reference_manager.rs +++ b/vk-video/src/parser/reference_manager.rs @@ -10,14 +10,12 @@ use h264_reader::nal::{ }; use super::{ - DecodeInformation, DecoderInstruction, PictureInfo, ReferencePictureInfo, Slice, SpsExt, + nalu_parser::{Slice, SpsExt}, + DecodeInformation, DecoderInstruction, PictureInfo, ReferencePictureInfo, }; #[derive(Debug, thiserror::Error)] pub enum ReferenceManagementError { - #[error("B frames are not supported")] - BFramesNotSupported, - #[error("SI frames are not supported")] SIFramesNotSupported, @@ -34,6 +32,12 @@ pub enum ReferenceManagementError { #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ReferenceId(usize); +#[derive(Debug, Clone, Copy)] +enum BFrameReferenceListKind { + L0, + L1, +} + #[derive(Debug, Default)] #[allow(non_snake_case)] pub(crate) struct ReferenceContext { @@ -45,7 +49,6 @@ pub(crate) struct ReferenceContext { MaxLongTermFrameIdx: MaxLongTermFrameIdx, prevFrameNumOffset: i64, previous_picture_included_mmco_equal_5: bool, - current_picture_included_mmco_equal_5: bool, } #[derive(Debug, Default)] @@ -56,7 +59,7 @@ enum MaxLongTermFrameIdx { } impl ReferenceContext { - fn get_next_reference_id(&mut self) -> ReferenceId { + fn next_reference_id(&mut self) -> ReferenceId { let result = self.next_reference_id; self.next_reference_id = ReferenceId(result.0 + 1); result @@ -72,7 +75,6 @@ impl ReferenceContext { MaxLongTermFrameIdx: MaxLongTermFrameIdx::NoLongTermFrameIndices, prevFrameNumOffset: 0, previous_picture_included_mmco_equal_5: false, - current_picture_included_mmco_equal_5: false, }; } @@ -83,7 +85,7 @@ impl ReferenceContext { LongTermFrameIdx: u64, pic_order_cnt: [i32; 2], ) -> ReferenceId { - let id = self.get_next_reference_id(); + let id = self.next_reference_id(); self.pictures.long_term.push(LongTermReferencePicture { header, id, @@ -99,7 +101,7 @@ impl ReferenceContext { header: Arc, pic_order_cnt: [i32; 2], ) -> ReferenceId { - let id = self.get_next_reference_id(); + let id = self.next_reference_id(); self.pictures.short_term.push(ShortTermReferencePicture { header, id, @@ -110,17 +112,18 @@ impl ReferenceContext { pub(crate) fn put_picture( &mut self, - mut slices: Vec, - sps: &SeqParameterSet, - pps: &PicParameterSet, + mut slices: Vec<(Slice, Option)>, ) -> Result, ReferenceManagementError> { - let header = slices.last().unwrap().header.clone(); + let header = slices.last().unwrap().0.header.clone(); + let sps = slices.last().unwrap().0.sps.clone(); + let pps = slices.last().unwrap().0.pps.clone(); + let pts = slices.last().unwrap().1; // maybe this should be done in a different place, but if you think about it, there's not // really that many places to put this code in let mut rbsp_bytes = Vec::new(); let mut slice_indices = Vec::new(); - for slice in &mut slices { + for (slice, _) in &mut slices { if slice.rbsp_bytes.is_empty() { continue; } @@ -128,36 +131,55 @@ impl ReferenceContext { rbsp_bytes.append(&mut slice.rbsp_bytes); } - let decode_info = - self.decode_information_for_frame(header.clone(), slice_indices, rbsp_bytes, sps, pps)?; + let decode_info = self.decode_information_for_frame( + header.clone(), + slice_indices, + rbsp_bytes, + &sps, + &pps, + pts, + )?; let decoder_instructions = match &header.clone().dec_ref_pic_marking { Some(DecRefPicMarking::Idr { long_term_reference_flag, .. }) => self.reference_picture_marking_process_idr( - header, + header.clone(), decode_info, *long_term_reference_flag, )?, - Some(DecRefPicMarking::SlidingWindow) => { - self.reference_picture_marking_process_sliding_window(sps, header, decode_info)? - } + Some(DecRefPicMarking::SlidingWindow) => self + .reference_picture_marking_process_sliding_window( + &sps, + header.clone(), + decode_info, + )?, Some(DecRefPicMarking::Adaptive(memory_management_control_operations)) => self .reference_picture_marking_process_adaptive( - sps, - header, + &sps, + header.clone(), decode_info, memory_management_control_operations, )?, // this picture is not a reference - None => vec![DecoderInstruction::Decode { decode_info }], + None => { + let reference_id = self.next_reference_id(); + vec![ + DecoderInstruction::Decode { + decode_info, + reference_id, + }, + DecoderInstruction::Drop { + reference_ids: vec![reference_id], + }, + ] + } }; - self.previous_picture_included_mmco_equal_5 = self.current_picture_included_mmco_equal_5; - self.current_picture_included_mmco_equal_5 = false; + self.previous_picture_included_mmco_equal_5 = header.includes_mmco_equal_5(); Ok(decoder_instructions) } @@ -310,7 +332,6 @@ impl ReferenceContext { .collect(); self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::NoLongTermFrameIndices; - self.current_picture_included_mmco_equal_5 = true; decoder_instructions.push(DecoderInstruction::Drop { reference_ids }) } @@ -332,14 +353,17 @@ impl ReferenceContext { Some(long_term_frame_idx) => self.add_long_term_reference( header, long_term_frame_idx, - decode_info.picture_info.PicOrderCnt, + decode_info.picture_info.PicOrderCnt_as_reference_pic, + ), + None => self.add_short_term_reference( + header, + decode_info.picture_info.PicOrderCnt_as_reference_pic, ), - None => self.add_short_term_reference(header, decode_info.picture_info.PicOrderCnt), }; decoder_instructions.insert( 0, - DecoderInstruction::DecodeAndStoreAs { + DecoderInstruction::Decode { decode_info, reference_id, }, @@ -366,10 +390,12 @@ impl ReferenceContext { let num_short_term = self.pictures.short_term.len(); let num_long_term = self.pictures.long_term.len(); - let reference_id = - self.add_short_term_reference(header.clone(), decode_info.picture_info.PicOrderCnt); + let reference_id = self.add_short_term_reference( + header.clone(), + decode_info.picture_info.PicOrderCnt_as_reference_pic, + ); - let mut decoder_instructions = vec![DecoderInstruction::DecodeAndStoreAs { + let mut decoder_instructions = vec![DecoderInstruction::Decode { decode_info, reference_id, }]; @@ -410,10 +436,17 @@ impl ReferenceContext { let reference_id = if long_term_reference_flag { self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::Idx(0); - self.add_long_term_reference(header, 0, decode_info.picture_info.PicOrderCnt) + self.add_long_term_reference( + header, + 0, + decode_info.picture_info.PicOrderCnt_as_reference_pic, + ) } else { self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::NoLongTermFrameIndices; - self.add_short_term_reference(header, decode_info.picture_info.PicOrderCnt) + self.add_short_term_reference( + header, + decode_info.picture_info.PicOrderCnt_as_reference_pic, + ) }; Ok(vec![DecoderInstruction::Idr { @@ -422,6 +455,7 @@ impl ReferenceContext { }]) } + #[allow(non_snake_case)] fn decode_information_for_frame( &mut self, header: Arc, @@ -429,25 +463,21 @@ impl ReferenceContext { rbsp_bytes: Vec, sps: &SeqParameterSet, pps: &PicParameterSet, + pts: Option, ) -> Result { - let reference_list = match header.slice_type.family { + let PicOrderCnt_for_decoding = self.decode_pic_order_cnt(&header, sps)?; + let PicOrderCnt_as_reference_pic = if header.includes_mmco_equal_5() { + [0, 0] + } else { + PicOrderCnt_for_decoding + }; + + let (reference_list_l0, reference_list_l1) = match header.slice_type.family { h264_reader::nal::slice::SliceFamily::P => { - let num_ref_idx_l0_active = header - .num_ref_idx_active - .as_ref() - .map(|num| match num { - NumRefIdxActive::P { - num_ref_idx_l0_active_minus1, - } => Ok(*num_ref_idx_l0_active_minus1), - NumRefIdxActive::B { .. } => { - Err(ReferenceManagementError::BFramesNotSupported) - } - }) - .unwrap_or(Ok(pps.num_ref_idx_l0_default_active_minus1))? - + 1; + let num_ref_idx_l0_active = header.num_ref_idx_l0_active(pps); - let mut reference_list = - self.initialize_reference_picture_list_for_frame(&header, sps)?; + let mut reference_list_l0 = + self.initialize_reference_picture_list_for_p_frame(&header, sps)?; match &header.ref_pic_list_modification { Some(RefPicListModifications::P { @@ -456,7 +486,7 @@ impl ReferenceContext { self.modify_reference_picture_list( sps, &header, - &mut reference_list, + &mut reference_list_l0, ref_pic_list_modification_l0, )?; } @@ -468,13 +498,55 @@ impl ReferenceContext { ))?, } - reference_list.truncate(num_ref_idx_l0_active as usize); + reference_list_l0.truncate(num_ref_idx_l0_active as usize); - Some(reference_list) + (Some(reference_list_l0), None) } - h264_reader::nal::slice::SliceFamily::I => None, + h264_reader::nal::slice::SliceFamily::I => (None, None), h264_reader::nal::slice::SliceFamily::B => { - return Err(ReferenceManagementError::BFramesNotSupported)? + let num_ref_idx_l0_active = header.num_ref_idx_l0_active(pps); + let num_ref_idx_l1_active = header.num_ref_idx_l1_active(pps)?; + + let mut reference_list_l0 = self.initialize_reference_picture_list_for_b_frame( + PicOrderCnt_for_decoding, + BFrameReferenceListKind::L0, + )?; + let mut reference_list_l1 = self.initialize_reference_picture_list_for_b_frame( + PicOrderCnt_for_decoding, + BFrameReferenceListKind::L1, + )?; + + match &header.ref_pic_list_modification { + Some(RefPicListModifications::B { + ref_pic_list_modification_l0, + ref_pic_list_modification_l1, + }) => { + self.modify_reference_picture_list( + sps, + &header, + &mut reference_list_l0, + ref_pic_list_modification_l0, + )?; + + self.modify_reference_picture_list( + sps, + &header, + &mut reference_list_l1, + ref_pic_list_modification_l1 + )?; + } + + None + | Some(RefPicListModifications::I) + | Some(RefPicListModifications::P { .. }) => return Err(ReferenceManagementError::IncorrectData( + "a slice marked 'B' slice family contains a reference picture list for a different family".into() + ))?, + } + + reference_list_l0.truncate(num_ref_idx_l0_active as usize); + reference_list_l1.truncate(num_ref_idx_l1_active as usize); + + (Some(reference_list_l0), Some(reference_list_l1)) } h264_reader::nal::slice::SliceFamily::SP => { return Err(ReferenceManagementError::SPFramesNotSupported)? @@ -484,22 +556,9 @@ impl ReferenceContext { } }; - let pic_order_cnt = match sps.pic_order_cnt { - h264_reader::nal::sps::PicOrderCntType::TypeZero { - log2_max_pic_order_cnt_lsb_minus4, - } => self.decode_pic_order_cnt_type_zero(&header, log2_max_pic_order_cnt_lsb_minus4)?, - - h264_reader::nal::sps::PicOrderCntType::TypeOne { .. } => { - Err(ReferenceManagementError::PicOrderCntTypeNotSupported(1))? - } - - h264_reader::nal::sps::PicOrderCntType::TypeTwo => { - self.decode_pic_order_cnt_type_two(&header, sps)? - } - }; - Ok(DecodeInformation { - reference_list, + reference_list_l0, + reference_list_l1, header: header.clone(), slice_indices, rbsp_bytes, @@ -508,12 +567,34 @@ impl ReferenceContext { picture_info: PictureInfo { non_existing: false, used_for_long_term_reference: false, - PicOrderCnt: pic_order_cnt, + PicOrderCnt_for_decoding, + PicOrderCnt_as_reference_pic, FrameNum: header.frame_num, }, + pts, }) } + fn decode_pic_order_cnt( + &mut self, + header: &SliceHeader, + sps: &SeqParameterSet, + ) -> Result<[i32; 2], ReferenceManagementError> { + match sps.pic_order_cnt { + h264_reader::nal::sps::PicOrderCntType::TypeZero { + log2_max_pic_order_cnt_lsb_minus4, + } => self.decode_pic_order_cnt_type_zero(header, log2_max_pic_order_cnt_lsb_minus4), + + h264_reader::nal::sps::PicOrderCntType::TypeOne { .. } => { + Err(ReferenceManagementError::PicOrderCntTypeNotSupported(1)) + } + + h264_reader::nal::sps::PicOrderCntType::TypeTwo => { + self.decode_pic_order_cnt_type_two(header, sps) + } + } + } + #[allow(non_snake_case)] fn decode_pic_order_cnt_type_two( &mut self, @@ -612,7 +693,7 @@ impl ReferenceContext { Ok([pic_order_cnt; 2]) } - fn initialize_short_term_reference_picture_list_for_frame( + fn initialize_short_term_reference_picture_list_for_p_frame( &self, header: &SliceHeader, sps: &SeqParameterSet, @@ -640,12 +721,9 @@ impl ReferenceContext { .map(|(reference, numbers)| ReferencePictureInfo { id: reference.id, LongTermPicNum: None, - picture_info: PictureInfo { - FrameNum: numbers.FrameNum as u16, - used_for_long_term_reference: false, - non_existing: false, - PicOrderCnt: reference.pic_order_cnt, - }, + FrameNum: numbers.FrameNum as u16, + non_existing: false, + PicOrderCnt: reference.pic_order_cnt, }) .collect() } @@ -660,23 +738,20 @@ impl ReferenceContext { .map(|pic| ReferencePictureInfo { id: pic.id, LongTermPicNum: Some(pic.LongTermFrameIdx), - picture_info: PictureInfo { - used_for_long_term_reference: true, - non_existing: false, - FrameNum: pic.header.frame_num, - PicOrderCnt: pic.pic_order_cnt, - }, + PicOrderCnt: pic.pic_order_cnt, + non_existing: false, + FrameNum: pic.header.frame_num, }) .collect() } - fn initialize_reference_picture_list_for_frame( + fn initialize_reference_picture_list_for_p_frame( &self, header: &SliceHeader, sps: &SeqParameterSet, ) -> Result, ReferenceManagementError> { let short_term_reference_list = - self.initialize_short_term_reference_picture_list_for_frame(header, sps); + self.initialize_short_term_reference_picture_list_for_p_frame(header, sps); let long_term_reference_list = self.initialize_long_term_reference_picture_list_for_frame(); @@ -688,6 +763,60 @@ impl ReferenceContext { Ok(reference_list) } + #[allow(non_snake_case)] + fn initialize_reference_picture_list_for_b_frame( + &self, + CurrPicOrderCnt: [i32; 2], + list_kind: BFrameReferenceListKind, + ) -> Result, ReferenceManagementError> { + let short_term_reference_list = self + .initialize_short_term_reference_picture_list_for_b_frame(CurrPicOrderCnt, list_kind)?; + + let long_term_reference_list = self.initialize_long_term_reference_picture_list_for_frame(); + + let reference_list = short_term_reference_list + .into_iter() + .chain(long_term_reference_list) + .collect(); + + Ok(reference_list) + } + + #[allow(non_snake_case)] + fn initialize_short_term_reference_picture_list_for_b_frame( + &self, + CurrPicOrderCnt: [i32; 2], + list_kind: BFrameReferenceListKind, + ) -> Result, ReferenceManagementError> { + let mut reference_list = self + .pictures + .short_term + .iter() + .filter(|pic| match list_kind { + BFrameReferenceListKind::L0 => pic.pic_order_cnt < CurrPicOrderCnt, + BFrameReferenceListKind::L1 => pic.pic_order_cnt > CurrPicOrderCnt, + }) + .collect::>(); + + reference_list.sort_by_key(|pic| match list_kind { + BFrameReferenceListKind::L0 => -pic.pic_order_cnt[0], + BFrameReferenceListKind::L1 => pic.pic_order_cnt[0], + }); + + let reference_list = reference_list + .into_iter() + .map(|pic| ReferencePictureInfo { + LongTermPicNum: None, + FrameNum: pic.header.frame_num, + non_existing: false, + PicOrderCnt: pic.pic_order_cnt, + id: pic.id, + }) + .collect(); + + Ok(reference_list) + } + #[allow(non_snake_case)] fn modify_reference_picture_list( &self, @@ -745,19 +874,13 @@ impl ReferenceContext { format!("picture with LongTermPicNum = {picture_to_shift} is not present in the reference list during modification") ))?; - if reference_list[shifted_picture_idx] - .picture_info - .non_existing - { + if reference_list[shifted_picture_idx].non_existing { return Err(ReferenceManagementError::IncorrectData( "a short-term reference picture marked for shifting in the reference list modification process is marked as non-existing".into() )); } - if !reference_list[shifted_picture_idx] - .picture_info - .used_for_long_term_reference - { + if reference_list[shifted_picture_idx].LongTermPicNum.is_none() { return Err(ReferenceManagementError::IncorrectData( "a short-term reference picture marked for shifting in the long-term reference list modification process".into() )); @@ -808,36 +931,38 @@ impl ReferenceContext { picNumLXNoWrap }; - let shifted_picture_idx = reference_list + let mut shifted_picture_idx = reference_list .iter() .enumerate() - .find(|(_, picture_info)| decode_picture_numbers_for_short_term_ref(picture_info.picture_info.FrameNum.into(), header.frame_num.into(), sps).PicNum == picNumLX) + .find(|(_, picture_info)| decode_picture_numbers_for_short_term_ref(picture_info.FrameNum.into(), header.frame_num.into(), sps).PicNum == picNumLX) .map(|(i, _)| i) .ok_or(ReferenceManagementError::IncorrectData( format!("picture with picNumLX = {picNumLX} is not present in the reference list during modification") ))?; - if reference_list[shifted_picture_idx] - .picture_info - .non_existing - { + if reference_list[shifted_picture_idx].non_existing { return Err(ReferenceManagementError::IncorrectData( "a short-term reference picture marked for shifting in the reference list modification process is marked as non-existing".into() )); } - if reference_list[shifted_picture_idx] - .picture_info - .used_for_long_term_reference - { + if reference_list[shifted_picture_idx].LongTermPicNum.is_some() { return Err(ReferenceManagementError::IncorrectData( "a long-term reference picture marked for shifting in the short-term reference list modification process".into() )); } - let shifted_picture_info = reference_list.remove(shifted_picture_idx); - reference_list.insert(*refIdxLX, shifted_picture_info); + let shifted_picture_info = reference_list[shifted_picture_idx]; + if *refIdxLX <= reference_list.len() { + reference_list.insert(*refIdxLX, shifted_picture_info); + shifted_picture_idx = if *refIdxLX <= shifted_picture_idx { + shifted_picture_idx + 1 + } else { + shifted_picture_idx + }; + } *refIdxLX += 1; + reference_list.remove(shifted_picture_idx); Ok(()) } @@ -899,3 +1024,56 @@ struct ReferencePictures { long_term: Vec, short_term: Vec, } + +trait SliceHeaderExt { + fn num_ref_idx_l0_active(&self, pps: &PicParameterSet) -> u32; + fn num_ref_idx_l1_active(&self, pps: &PicParameterSet) + -> Result; + fn includes_mmco_equal_5(&self) -> bool; +} + +impl SliceHeaderExt for SliceHeader { + fn num_ref_idx_l0_active(&self, pps: &PicParameterSet) -> u32 { + self.num_ref_idx_active + .as_ref() + .map(|num| match num { + NumRefIdxActive::P { + num_ref_idx_l0_active_minus1, + } => *num_ref_idx_l0_active_minus1, + NumRefIdxActive::B { + num_ref_idx_l0_active_minus1, + .. + } => *num_ref_idx_l0_active_minus1, + }) + .unwrap_or(pps.num_ref_idx_l0_default_active_minus1) + + 1 + } + + fn num_ref_idx_l1_active( + &self, + pps: &PicParameterSet, + ) -> Result { + Ok( + self + .num_ref_idx_active + .as_ref() + .map(|num| match num { + NumRefIdxActive::P { .. } => Err(ReferenceManagementError::IncorrectData( + "requested num_ref_idx_l1_active, but the header contains the information for a P-frame, which does not include it".into() + )), + NumRefIdxActive::B { num_ref_idx_l1_active_minus1, .. } => Ok(*num_ref_idx_l1_active_minus1) + }) + .unwrap_or(Ok(pps.num_ref_idx_l1_default_active_minus1))? + 1 + ) + } + + fn includes_mmco_equal_5(&self) -> bool { + let Some(DecRefPicMarking::Adaptive(ref mmcos)) = self.dec_ref_pic_marking else { + return false; + }; + + mmcos + .iter() + .any(|mmco| matches!(mmco, MemoryManagementControlOperation::AllRefPicturesUnused)) + } +} diff --git a/vk-video/src/vulkan_decoder.rs b/vk-video/src/vulkan_decoder.rs index 985d9ca2c..65e86b70e 100644 --- a/vk-video/src/vulkan_decoder.rs +++ b/vk-video/src/vulkan_decoder.rs @@ -9,10 +9,12 @@ use wrappers::*; use crate::parser::{DecodeInformation, DecoderInstruction, ReferenceId}; +mod frame_sorter; mod session_resources; mod vulkan_ctx; mod wrappers; +pub(crate) use frame_sorter::FrameSorter; pub use vulkan_ctx::*; pub struct VulkanDecoder<'a> { @@ -22,7 +24,6 @@ pub struct VulkanDecoder<'a> { _command_pools: CommandPools, sync_structures: SyncStructures, reference_id_to_dpb_slot_index: std::collections::HashMap, - decode_query_pool: Option, } struct SyncStructures { @@ -39,13 +40,17 @@ struct CommandBuffers { /// this cannot outlive the image and semaphore it borrows, but it seems impossible to encode that /// in the lifetimes -struct DecodeOutput { +struct DecodeSubmission { image: vk::Image, dimensions: vk::Extent2D, current_layout: vk::ImageLayout, layer: u32, wait_semaphore: vk::Semaphore, _input_buffer: Buffer, + picture_order_cnt: i32, + max_num_reorder_frames: u64, + is_idr: bool, + pts: Option, } #[derive(Debug, thiserror::Error)] @@ -80,6 +85,15 @@ pub enum VulkanDecoderError { #[error("A vulkan decode operation failed with code {0:?}")] DecodeOperationFailed(vk::QueryResultStatusKHR), + #[error("Invalid input data for the decoder: {0}.")] + InvalidInputData(String), + + #[error("Profile changed during the stream")] + ProfileChangeUnsupported, + + #[error("Level changed during the stream")] + LevelChangeUnsupported, + #[error(transparent)] VulkanCtxError(#[from] VulkanCtxError), } @@ -113,19 +127,6 @@ impl<'a> VulkanDecoder<'a> { fence_memory_barrier_completed: Fence::new(vulkan_ctx.device.clone(), false)?, }; - let decode_query_pool = if vulkan_ctx - .queues - .h264_decode - .supports_result_status_queries() - { - Some(DecodeQueryPool::new( - vulkan_ctx.device.clone(), - H264ProfileInfo::decode_h264_yuv420().profile_info, - )?) - } else { - None - }; - Ok(Self { vulkan_ctx, video_session_resources: None, @@ -136,21 +137,34 @@ impl<'a> VulkanDecoder<'a> { vulkan_to_wgpu_transfer_buffer, }, sync_structures, - decode_query_pool, reference_id_to_dpb_slot_index: Default::default(), }) } } +pub(crate) struct DecodeResult { + frame: T, + pts: Option, + pic_order_cnt: i32, + max_num_reorder_frames: u64, + is_idr: bool, +} + impl VulkanDecoder<'_> { pub fn decode_to_bytes( &mut self, decoder_instructions: &[DecoderInstruction], - ) -> Result>, VulkanDecoderError> { + ) -> Result>>, VulkanDecoderError> { let mut result = Vec::new(); for instruction in decoder_instructions { if let Some(output) = self.decode(instruction)? { - result.push(self.download_output(output)?) + result.push(DecodeResult { + pts: output.pts, + is_idr: output.is_idr, + max_num_reorder_frames: output.max_num_reorder_frames, + pic_order_cnt: output.picture_order_cnt, + frame: self.download_output(output)?, + }) } } @@ -160,11 +174,17 @@ impl VulkanDecoder<'_> { pub fn decode_to_wgpu_textures( &mut self, decoder_instructions: &[DecoderInstruction], - ) -> Result, VulkanDecoderError> { + ) -> Result>, VulkanDecoderError> { let mut result = Vec::new(); for instruction in decoder_instructions { if let Some(output) = self.decode(instruction)? { - result.push(self.output_to_wgpu_texture(output)?) + result.push(DecodeResult { + pts: output.pts, + is_idr: output.is_idr, + max_num_reorder_frames: output.max_num_reorder_frames, + pic_order_cnt: output.picture_order_cnt, + frame: self.output_to_wgpu_texture(output)?, + }) } } @@ -174,20 +194,14 @@ impl VulkanDecoder<'_> { fn decode( &mut self, instruction: &DecoderInstruction, - ) -> Result, VulkanDecoderError> { + ) -> Result, VulkanDecoderError> { match instruction { - DecoderInstruction::Decode { .. } => { - return Err(VulkanDecoderError::DecoderInstructionNotSupported( - Box::new(instruction.clone()), - )) - } - - DecoderInstruction::DecodeAndStoreAs { + DecoderInstruction::Decode { decode_info, reference_id, } => { return self - .process_reference_p_frame(decode_info, *reference_id) + .process_reference_p_or_b_frame(decode_info, *reference_id) .map(Option::Some) } @@ -262,15 +276,15 @@ impl VulkanDecoder<'_> { &mut self, decode_information: &DecodeInformation, reference_id: ReferenceId, - ) -> Result { + ) -> Result { self.do_decode(decode_information, reference_id, true, true) } - fn process_reference_p_frame( + fn process_reference_p_or_b_frame( &mut self, decode_information: &DecodeInformation, reference_id: ReferenceId, - ) -> Result { + ) -> Result { self.do_decode(decode_information, reference_id, false, true) } @@ -280,7 +294,7 @@ impl VulkanDecoder<'_> { reference_id: ReferenceId, is_idr: bool, is_reference: bool, - ) -> Result { + ) -> Result { // upload data to a buffer let size = Self::pad_size_to_alignment( decode_information.rbsp_bytes.len() as u64, @@ -289,18 +303,19 @@ impl VulkanDecoder<'_> { .min_bitstream_buffer_offset_alignment, ); - let decode_buffer = Buffer::new_with_decode_data( - self.vulkan_ctx.allocator.clone(), - &decode_information.rbsp_bytes, - size, - )?; - // decode let video_session_resources = self .video_session_resources .as_mut() .ok_or(VulkanDecoderError::NoSession)?; + let decode_buffer = Buffer::new_with_decode_data( + self.vulkan_ctx.allocator.clone(), + &decode_information.rbsp_bytes, + size, + &video_session_resources.profile_info, + )?; + // IDR - remove all reference picures if is_idr { video_session_resources @@ -328,7 +343,7 @@ impl VulkanDecoder<'_> { ) }; - if let Some(pool) = self.decode_query_pool.as_ref() { + if let Some(pool) = video_session_resources.decode_query_pool.as_ref() { pool.reset(*self.command_buffers.decode_buffer); } @@ -418,7 +433,7 @@ impl VulkanDecoder<'_> { 0, ), }, - PicOrderCnt: decode_information.picture_info.PicOrderCnt, + PicOrderCnt: decode_information.picture_info.PicOrderCnt_for_decoding, seq_parameter_set_id: decode_information.sps_id, pic_parameter_set_id: decode_information.pps_id, frame_num: decode_information.header.frame_num, @@ -461,7 +476,7 @@ impl VulkanDecoder<'_> { .reference_slots(&pic_reference_slots) .push_next(&mut decode_h264_picture_info); - if let Some(pool) = self.decode_query_pool.as_ref() { + if let Some(pool) = video_session_resources.decode_query_pool.as_ref() { pool.begin_query(*self.command_buffers.decode_buffer); } @@ -472,7 +487,7 @@ impl VulkanDecoder<'_> { .cmd_decode_video_khr(*self.command_buffers.decode_buffer, &decode_info) }; - if let Some(pool) = self.decode_query_pool.as_ref() { + if let Some(pool) = video_session_resources.decode_query_pool.as_ref() { pool.end_query(*self.command_buffers.decode_buffer); } @@ -512,19 +527,23 @@ impl VulkanDecoder<'_> { height: sps.height()?, }; - Ok(DecodeOutput { + Ok(DecodeSubmission { image: target_image, wait_semaphore: *self.sync_structures.sem_decode_done, layer: target_layer as u32, current_layout: target_image_layout, dimensions, _input_buffer: decode_buffer, + picture_order_cnt: decode_information.picture_info.PicOrderCnt_for_decoding[0], + max_num_reorder_frames: video_session_resources.max_num_reorder_frames, + is_idr, + pts: decode_information.pts, }) } fn output_to_wgpu_texture( &self, - decode_output: DecodeOutput, + decode_output: DecodeSubmission, ) -> Result { let copy_extent = vk::Extent3D { width: decode_output.dimensions.width, @@ -696,8 +715,9 @@ impl VulkanDecoder<'_> { .wait_and_reset(u64::MAX)?; let result = self - .decode_query_pool + .video_session_resources .as_ref() + .and_then(|s| s.decode_query_pool.as_ref()) .map(|pool| pool.get_result_blocking()); if let Some(result) = result { @@ -759,7 +779,10 @@ impl VulkanDecoder<'_> { Ok(wgpu_texture) } - fn download_output(&self, decode_output: DecodeOutput) -> Result, VulkanDecoderError> { + fn download_output( + &self, + decode_output: DecodeSubmission, + ) -> Result, VulkanDecoderError> { let mut dst_buffer = self.copy_image_to_buffer( decode_output.image, decode_output.dimensions, @@ -790,10 +813,11 @@ impl VulkanDecoder<'_> { decode_information: &DecodeInformation, ) -> Vec { decode_information - .reference_list + .reference_list_l0 .iter() .flatten() - .map(|ref_info| ref_info.picture_info.into()) + .chain(decode_information.reference_list_l1.iter().flatten()) + .map(|&ref_info| ref_info.into()) .collect::>() } @@ -812,11 +836,12 @@ impl VulkanDecoder<'_> { references_dpb_slot_info: &'a mut [vk::VideoDecodeH264DpbSlotInfoKHR<'a>], decode_information: &'a DecodeInformation, ) -> Result>, VulkanDecoderError> { - let mut pic_reference_slots = Vec::new(); + let mut pic_reference_slots: Vec> = Vec::new(); for (ref_info, dpb_slot_info) in decode_information - .reference_list + .reference_list_l0 .iter() .flatten() + .chain(decode_information.reference_list_l1.iter().flatten()) .zip(references_dpb_slot_info.iter_mut()) { let i = *reference_id_to_dpb_slot_index @@ -833,7 +858,12 @@ impl VulkanDecoder<'_> { let reference = reference.push_next(dpb_slot_info); - pic_reference_slots.push(reference); + if pic_reference_slots + .iter() + .all(|r| r.slot_index != reference.slot_index) + { + pic_reference_slots.push(reference); + } } Ok(pic_reference_slots) @@ -957,41 +987,3 @@ impl VulkanDecoder<'_> { Ok(dst_buffer) } } - -pub(crate) struct H264ProfileInfo<'a> { - profile_info: vk::VideoProfileInfoKHR<'a>, - h264_info_ptr: *mut vk::VideoDecodeH264ProfileInfoKHR<'a>, -} - -impl H264ProfileInfo<'_> { - fn decode_h264_yuv420() -> Self { - let h264_profile_info = Box::leak(Box::new( - vk::VideoDecodeH264ProfileInfoKHR::default() - .std_profile_idc( - vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_BASELINE, - ) - .picture_layout(vk::VideoDecodeH264PictureLayoutFlagsKHR::PROGRESSIVE), - )); - - let h264_info_ptr = h264_profile_info as *mut _; - let profile_info = vk::VideoProfileInfoKHR::default() - .video_codec_operation(vk::VideoCodecOperationFlagsKHR::DECODE_H264) - .chroma_subsampling(vk::VideoChromaSubsamplingFlagsKHR::TYPE_420) - .luma_bit_depth(vk::VideoComponentBitDepthFlagsKHR::TYPE_8) - .chroma_bit_depth(vk::VideoComponentBitDepthFlagsKHR::TYPE_8) - .push_next(h264_profile_info); - - Self { - profile_info, - h264_info_ptr, - } - } -} - -impl<'a> Drop for H264ProfileInfo<'a> { - fn drop(&mut self) { - unsafe { - let _ = Box::from_raw(self.h264_info_ptr); - } - } -} diff --git a/vk-video/src/vulkan_decoder/frame_sorter.rs b/vk-video/src/vulkan_decoder/frame_sorter.rs new file mode 100644 index 000000000..78d38da6b --- /dev/null +++ b/vk-video/src/vulkan_decoder/frame_sorter.rs @@ -0,0 +1,69 @@ +use std::collections::BinaryHeap; + +use crate::Frame; + +use super::DecodeResult; + +impl PartialEq for DecodeResult { + fn eq(&self, other: &Self) -> bool { + self.pic_order_cnt.eq(&other.pic_order_cnt) + } +} + +impl Eq for DecodeResult {} + +impl PartialOrd for DecodeResult { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for DecodeResult { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.pic_order_cnt.cmp(&other.pic_order_cnt).reverse() + } +} + +pub(crate) struct FrameSorter { + frames: BinaryHeap>, +} + +impl FrameSorter { + pub(crate) fn new() -> Self { + Self { + frames: BinaryHeap::new(), + } + } + + pub(crate) fn put(&mut self, frame: DecodeResult) -> Vec> { + let max_num_reorder_frames = frame.max_num_reorder_frames as usize; + let is_idr = frame.is_idr; + let mut result = Vec::new(); + + if is_idr { + while !self.frames.is_empty() { + let frame = self.frames.pop().unwrap(); + + result.push(Frame { + frame: frame.frame, + pts: frame.pts, + }); + } + + self.frames.push(frame); + } else { + self.frames.push(frame); + + while self.frames.len() > max_num_reorder_frames { + let frame = self.frames.pop().unwrap(); + + result.push(Frame { + frame: frame.frame, + pts: frame.pts, + }); + } + } + + result + } +} diff --git a/vk-video/src/vulkan_decoder/session_resources.rs b/vk-video/src/vulkan_decoder/session_resources.rs index f8877d661..b57892e45 100644 --- a/vk-video/src/vulkan_decoder/session_resources.rs +++ b/vk-video/src/vulkan_decoder/session_resources.rs @@ -1,24 +1,56 @@ use std::collections::HashMap; use ash::vk; -use h264_reader::nal::{pps::PicParameterSet, sps::SeqParameterSet}; +use h264_reader::nal::{ + pps::PicParameterSet, + sps::{Profile, SeqParameterSet}, +}; use images::DecodingImages; use parameters::VideoSessionParametersManager; use super::{ - CommandBuffer, Fence, H264ProfileInfo, SeqParameterSetExt, VideoSession, VulkanCtx, - VulkanDecoderError, + h264_level_idc_to_max_dpb_mbs, vk_to_h264_level_idc, CommandBuffer, DecodeQueryPool, Fence, + H264ProfileInfo, SeqParameterSetExt, VideoSession, VulkanCtx, VulkanDecoderError, }; mod images; mod parameters; pub(super) struct VideoSessionResources<'a> { + pub(crate) profile_info: H264ProfileInfo<'a>, pub(crate) video_session: VideoSession, pub(crate) parameters_manager: VideoSessionParametersManager, pub(crate) decoding_images: DecodingImages<'a>, pub(crate) sps: HashMap, pub(crate) pps: HashMap<(u8, u8), PicParameterSet>, + pub(crate) decode_query_pool: Option, + pub(crate) level_idc: u8, + pub(crate) max_num_reorder_frames: u64, +} + +fn calculate_max_num_reorder_frames(sps: &SeqParameterSet) -> Result { + let fallback_max_num_reorder_frames = if [44u8, 86, 100, 110, 122, 244] + .contains(&sps.profile_idc.into()) + && sps.constraint_flags.flag3() + { + 0 + } else if let Profile::Baseline = sps.profile() { + 0 + } else { + h264_level_idc_to_max_dpb_mbs(sps.level_idc)? + / ((sps.pic_width_in_mbs_minus1 as u64 + 1) + * (sps.pic_height_in_map_units_minus1 as u64 + 1)) + .min(16) + }; + + let max_num_reorder_frames = sps + .vui_parameters + .as_ref() + .and_then(|v| v.bitstream_restrictions.as_ref()) + .map(|b| b.max_num_reorder_frames as u64) + .unwrap_or(fallback_max_num_reorder_frames); + + Ok(max_num_reorder_frames) } impl VideoSessionResources<'_> { @@ -28,19 +60,28 @@ impl VideoSessionResources<'_> { sps: SeqParameterSet, fence_memory_barrier_completed: &Fence, ) -> Result { - let profile = H264ProfileInfo::decode_h264_yuv420(); + let profile_info = H264ProfileInfo::from_sps_decode(&sps)?; + + let level_idc = sps.level_idc; + let max_level_idc = vk_to_h264_level_idc(vulkan_ctx.h264_caps.max_level_idc)?; + + if level_idc > max_level_idc { + return Err(VulkanDecoderError::InvalidInputData( + format!("stream has level_idc = {level_idc}, while the GPU can decode at most {max_level_idc}") + )); + } let width = sps.width()?; let height = sps.height()?; - let max_coded_extent = vk::Extent2D { width, height }; // +1 for current frame let max_dpb_slots = sps.max_num_ref_frames + 1; let max_active_references = sps.max_num_ref_frames; + let max_num_reorder_frames = calculate_max_num_reorder_frames(&sps)?; let video_session = VideoSession::new( vulkan_ctx, - &profile.profile_info, + &profile_info.profile_info, max_coded_extent, max_dpb_slots, max_active_references, @@ -54,6 +95,7 @@ impl VideoSessionResources<'_> { let decoding_images = Self::new_decoding_images( vulkan_ctx, + &profile_info, max_coded_extent, max_dpb_slots, decode_buffer, @@ -61,13 +103,29 @@ impl VideoSessionResources<'_> { )?; let sps = HashMap::from_iter([(sps.id().id(), sps)]); + let decode_query_pool = if vulkan_ctx + .queues + .h264_decode + .supports_result_status_queries() + { + Some(DecodeQueryPool::new( + vulkan_ctx.device.clone(), + profile_info.profile_info, + )?) + } else { + None + }; Ok(VideoSessionResources { + profile_info, video_session, parameters_manager, decoding_images, sps, pps: HashMap::new(), + decode_query_pool, + level_idc, + max_num_reorder_frames, }) } @@ -78,7 +136,15 @@ impl VideoSessionResources<'_> { sps: SeqParameterSet, fence_memory_barrier_completed: &Fence, ) -> Result<(), VulkanDecoderError> { - let profile = H264ProfileInfo::decode_h264_yuv420(); + let new_profile = H264ProfileInfo::from_sps_decode(&sps)?; + + if self.profile_info != new_profile { + return Err(VulkanDecoderError::ProfileChangeUnsupported); + } + + if self.level_idc != sps.level_idc { + return Err(VulkanDecoderError::LevelChangeUnsupported); + } let width = sps.width()?; let height = sps.height()?; @@ -99,7 +165,7 @@ impl VideoSessionResources<'_> { self.video_session = VideoSession::new( vulkan_ctx, - &profile.profile_info, + &self.profile_info.profile_info, max_coded_extent, max_dpb_slots, max_active_references, @@ -112,6 +178,7 @@ impl VideoSessionResources<'_> { self.decoding_images = Self::new_decoding_images( vulkan_ctx, + &self.profile_info, max_coded_extent, max_dpb_slots, decode_buffer, @@ -134,13 +201,12 @@ impl VideoSessionResources<'_> { fn new_decoding_images<'a>( vulkan_ctx: &VulkanCtx, + profile: &H264ProfileInfo, max_coded_extent: vk::Extent2D, max_dpb_slots: u32, decode_buffer: &CommandBuffer, fence_memory_barrier_completed: &Fence, ) -> Result, VulkanDecoderError> { - let profile = H264ProfileInfo::decode_h264_yuv420(); - // FIXME: usually, sps arrives either at the start of the stream (when all spses are sent // at the begginning of the stream) or right before an IDR. It is however possible for an // sps nal to arrive in between P-frames. This would cause us to loose the reference diff --git a/vk-video/src/vulkan_decoder/session_resources/images.rs b/vk-video/src/vulkan_decoder/session_resources/images.rs index c62afbd50..79b0e60f1 100644 --- a/vk-video/src/vulkan_decoder/session_resources/images.rs +++ b/vk-video/src/vulkan_decoder/session_resources/images.rs @@ -157,7 +157,7 @@ impl<'a> DecodingImages<'a> { pub(crate) fn new( vulkan_ctx: &VulkanCtx, - profile: H264ProfileInfo, + profile: &H264ProfileInfo, dpb_format: &vk::VideoFormatPropertiesKHR<'a>, dst_format: &Option>, dimensions: vk::Extent2D, @@ -182,7 +182,7 @@ impl<'a> DecodingImages<'a> { dpb_format, dimensions, dpb_image_usage, - &profile, + profile, max_dpb_slots, if dst_format.is_some() { None @@ -202,7 +202,7 @@ impl<'a> DecodingImages<'a> { &dst_format, dimensions, dst_image_usage, - &profile, + profile, 1, Some(&queue_indices), vk::ImageLayout::VIDEO_DECODE_DST_KHR, diff --git a/vk-video/src/vulkan_decoder/vulkan_ctx.rs b/vk-video/src/vulkan_decoder/vulkan_ctx.rs index 4aa4bb185..0785f1ff7 100644 --- a/vk-video/src/vulkan_decoder/vulkan_ctx.rs +++ b/vk-video/src/vulkan_decoder/vulkan_ctx.rs @@ -4,11 +4,10 @@ use std::{ }; use ash::{vk, Entry}; -use tracing::{debug, error}; +use tracing::{debug, error, warn}; use super::{ - Allocator, CommandBuffer, CommandPool, DebugMessenger, Device, H264ProfileInfo, Instance, - VulkanDecoderError, + Allocator, CommandBuffer, CommandPool, DebugMessenger, Device, Instance, VulkanDecoderError, }; const REQUIRED_EXTENSIONS: &[&CStr] = &[ @@ -55,6 +54,7 @@ pub struct VulkanCtx { pub(crate) video_capabilities: vk::VideoCapabilitiesKHR<'static>, pub(crate) h264_dpb_format_properties: vk::VideoFormatPropertiesKHR<'static>, pub(crate) h264_dst_format_properties: Option>, + pub(crate) h264_caps: vk::VideoDecodeH264CapabilitiesKHR<'static>, pub wgpu_ctx: WgpuCtx, } @@ -233,6 +233,7 @@ impl VulkanCtx { h264_dpb_format_properties, h264_dst_format_properties, video_capabilities, + h264_caps, } = find_device(&physical_devices, &instance, REQUIRED_EXTENSIONS)?; let wgpu_adapter = wgpu_instance @@ -374,6 +375,7 @@ impl VulkanCtx { video_capabilities, h264_dpb_format_properties, h264_dst_format_properties, + h264_caps, wgpu_ctx, }) } @@ -391,6 +393,7 @@ struct ChosenDevice<'a> { h264_dpb_format_properties: vk::VideoFormatPropertiesKHR<'a>, h264_dst_format_properties: Option>, video_capabilities: vk::VideoCapabilitiesKHR<'a>, + h264_caps: vk::VideoDecodeH264CapabilitiesKHR<'a>, } fn find_device<'a>( @@ -408,7 +411,7 @@ fn find_device<'a>( let extensions = unsafe { instance.enumerate_device_extension_properties(device)? }; if vk_13_features.synchronization2 == 0 { - error!( + warn!( "device {:?} does not support the required synchronization2 feature", properties.device_name_as_c_str()? ); @@ -427,7 +430,7 @@ fn find_device<'a>( true }) }) { - error!( + warn!( "device {:?} does not support the required extensions", properties.device_name_as_c_str()? ); @@ -453,7 +456,16 @@ fn find_device<'a>( unsafe { instance.get_physical_device_queue_family_properties2(device, &mut queues) }; - let profile_info = H264ProfileInfo::decode_h264_yuv420(); + let mut h264_profile_info = vk::VideoDecodeH264ProfileInfoKHR::default() + .picture_layout(vk::VideoDecodeH264PictureLayoutFlagsKHR::PROGRESSIVE) + .std_profile_idc(vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_HIGH); + + let profile_info = vk::VideoProfileInfoKHR::default() + .video_codec_operation(vk::VideoCodecOperationFlagsKHR::DECODE_H264) + .chroma_subsampling(vk::VideoChromaSubsamplingFlagsKHR::TYPE_420) + .luma_bit_depth(vk::VideoComponentBitDepthFlagsKHR::TYPE_8) + .chroma_bit_depth(vk::VideoComponentBitDepthFlagsKHR::TYPE_8) + .push_next(&mut h264_profile_info); let mut h264_caps = vk::VideoDecodeH264CapabilitiesKHR::default(); let mut decode_caps = vk::VideoDecodeCapabilitiesKHR { @@ -468,9 +480,7 @@ fn find_device<'a>( .video_queue_instance_ext .fp() .get_physical_device_video_capabilities_khr)( - device, - &profile_info.profile_info, - &mut caps, + device, &profile_info, &mut caps ) .result()? }; @@ -485,6 +495,10 @@ fn find_device<'a>( .max_dpb_slots(caps.max_dpb_slots) .max_active_reference_pictures(caps.max_active_reference_pictures) .std_header_version(caps.std_header_version); + + let h264_caps = vk::VideoDecodeH264CapabilitiesKHR::default() + .max_level_idc(h264_caps.max_level_idc) + .field_offset_granularity(h264_caps.field_offset_granularity); debug!("video_caps: {caps:#?}"); let flags = decode_caps.flags; @@ -623,6 +637,7 @@ fn find_device<'a>( h264_dpb_format_properties, h264_dst_format_properties, video_capabilities, + h264_caps, }); } @@ -632,11 +647,11 @@ fn find_device<'a>( fn query_video_format_properties<'a>( device: vk::PhysicalDevice, video_queue_instance_ext: &ash::khr::video_queue::Instance, - profile_info: &H264ProfileInfo, + profile_info: &vk::VideoProfileInfoKHR<'_>, image_usage: vk::ImageUsageFlags, ) -> Result>, VulkanCtxError> { - let mut profile_list_info = vk::VideoProfileListInfoKHR::default() - .profiles(std::slice::from_ref(&profile_info.profile_info)); + let mut profile_list_info = + vk::VideoProfileListInfoKHR::default().profiles(std::slice::from_ref(profile_info)); let format_info = vk::PhysicalDeviceVideoFormatInfoKHR::default() .image_usage(image_usage) diff --git a/vk-video/src/vulkan_decoder/wrappers/mem.rs b/vk-video/src/vulkan_decoder/wrappers/mem.rs index 5876702ec..2a651922a 100644 --- a/vk-video/src/vulkan_decoder/wrappers/mem.rs +++ b/vk-video/src/vulkan_decoder/wrappers/mem.rs @@ -179,12 +179,9 @@ impl Buffer { allocator: Arc, data: &[u8], buffer_size: u64, + profile_info: &H264ProfileInfo, ) -> Result { - let mut decode_buffer = Buffer::new_decode( - allocator.clone(), - buffer_size, - &H264ProfileInfo::decode_h264_yuv420(), - )?; + let mut decode_buffer = Buffer::new_decode(allocator.clone(), buffer_size, profile_info)?; unsafe { let mem = allocator.map_memory(&mut decode_buffer.allocation)?; diff --git a/vk-video/src/vulkan_decoder/wrappers/parameter_sets.rs b/vk-video/src/vulkan_decoder/wrappers/parameter_sets.rs index 2229662e3..8098583b5 100644 --- a/vk-video/src/vulkan_decoder/wrappers/parameter_sets.rs +++ b/vk-video/src/vulkan_decoder/wrappers/parameter_sets.rs @@ -197,6 +197,64 @@ impl ChromaFormatExt for h264_reader::nal::sps::ChromaFormat { } } +pub(crate) fn vk_to_h264_level_idc( + level_idc: vk::native::StdVideoH264LevelIdc, +) -> Result { + match level_idc { + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_1_0 => Ok(10), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_1_1 => Ok(11), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_1_2 => Ok(12), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_1_3 => Ok(13), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_2_0 => Ok(20), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_2_1 => Ok(21), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_2_2 => Ok(22), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_3_0 => Ok(30), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_3_1 => Ok(31), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_3_2 => Ok(32), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_4_0 => Ok(40), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_4_1 => Ok(41), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_4_2 => Ok(42), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_5_0 => Ok(50), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_5_1 => Ok(51), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_5_2 => Ok(52), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_6_0 => Ok(60), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_6_1 => Ok(61), + vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_6_2 => Ok(62), + _ => Err(VulkanDecoderError::InvalidInputData(format!( + "unknown StdVideoH264LevelIdc: {level_idc}" + ))), + } +} + +/// As per __Table A-1 Level limits__ in the H.264 spec +/// `mbs` means macroblocks here +pub(crate) fn h264_level_idc_to_max_dpb_mbs(level_idc: u8) -> Result { + match level_idc { + 10 => Ok(396), + 11 => Ok(900), + 12 => Ok(2_376), + 13 => Ok(2_376), + 20 => Ok(2_376), + 21 => Ok(4_752), + 22 => Ok(8_100), + 30 => Ok(8_100), + 31 => Ok(18_000), + 32 => Ok(20_480), + 40 => Ok(32_768), + 41 => Ok(32_768), + 42 => Ok(34_816), + 50 => Ok(110_400), + 51 => Ok(184_320), + 52 => Ok(184_320), + 60 => Ok(696_320), + 61 => Ok(696_320), + 62 => Ok(696_320), + _ => Err(VulkanDecoderError::InvalidInputData(format!( + "unknown h264 level_idc: {level_idc}" + ))), + } +} + fn h264_level_idc_to_vk(level_idc: u8) -> u32 { match level_idc { 10 => vk::native::StdVideoH264LevelIdc_STD_VIDEO_H264_LEVEL_IDC_1_0, @@ -222,6 +280,129 @@ fn h264_level_idc_to_vk(level_idc: u8) -> u32 { } } +fn h264_profile_idc_to_vk( + profile: h264_reader::nal::sps::Profile, +) -> vk::native::StdVideoH264ProfileIdc { + match profile { + h264_reader::nal::sps::Profile::Baseline => { + vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_BASELINE + } + h264_reader::nal::sps::Profile::Main => { + vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_MAIN + } + h264_reader::nal::sps::Profile::High => { + vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_HIGH + } + h264_reader::nal::sps::Profile::High444 => { + vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE + } + h264_reader::nal::sps::Profile::High422 + | h264_reader::nal::sps::Profile::High10 + | h264_reader::nal::sps::Profile::Extended + | h264_reader::nal::sps::Profile::ScalableBase + | h264_reader::nal::sps::Profile::ScalableHigh + | h264_reader::nal::sps::Profile::MultiviewHigh + | h264_reader::nal::sps::Profile::StereoHigh + | h264_reader::nal::sps::Profile::MFCDepthHigh + | h264_reader::nal::sps::Profile::MultiviewDepthHigh + | h264_reader::nal::sps::Profile::EnhancedMultiviewDepthHigh + | h264_reader::nal::sps::Profile::Unknown(_) => { + vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_INVALID + } + } +} + +pub(crate) struct H264ProfileInfo<'a> { + pub(crate) profile_info: vk::VideoProfileInfoKHR<'a>, + h264_info_ptr: *mut vk::VideoDecodeH264ProfileInfoKHR<'a>, +} + +impl PartialEq for H264ProfileInfo<'_> { + fn eq(&self, other: &Self) -> bool { + unsafe { + other.profile_info.chroma_subsampling == self.profile_info.chroma_subsampling + && other.profile_info.luma_bit_depth == self.profile_info.luma_bit_depth + && other.profile_info.chroma_bit_depth == self.profile_info.chroma_bit_depth + && (*other.h264_info_ptr).std_profile_idc == (*self.h264_info_ptr).std_profile_idc + && (*other.h264_info_ptr).picture_layout == (*self.h264_info_ptr).picture_layout + } + } +} + +impl Eq for H264ProfileInfo<'_> {} + +impl H264ProfileInfo<'_> { + pub(crate) fn from_sps_decode(sps: &SeqParameterSet) -> Result { + let profile_idc = h264_profile_idc_to_vk(sps.profile()); + + if profile_idc == vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_INVALID { + return Err(VulkanDecoderError::InvalidInputData( + "unsupported h264 profile".into(), + )); + } + + let h264_profile_info = Box::leak(Box::new( + vk::VideoDecodeH264ProfileInfoKHR::default() + .std_profile_idc(profile_idc) + .picture_layout(vk::VideoDecodeH264PictureLayoutFlagsKHR::PROGRESSIVE), + )); + + let chroma_subsampling = match sps.chroma_info.chroma_format { + h264_reader::nal::sps::ChromaFormat::YUV420 => { + vk::VideoChromaSubsamplingFlagsKHR::TYPE_420 + } + h264_reader::nal::sps::ChromaFormat::Monochrome + | h264_reader::nal::sps::ChromaFormat::YUV422 + | h264_reader::nal::sps::ChromaFormat::YUV444 + | h264_reader::nal::sps::ChromaFormat::Invalid(_) => { + return Err(VulkanDecoderError::InvalidInputData(format!( + "unsupported chroma format: {:?}", + sps.chroma_info.chroma_format + ))) + } + }; + + let luma_bit_depth = if sps.chroma_info.bit_depth_luma_minus8 + 8 == 8 { + vk::VideoComponentBitDepthFlagsKHR::TYPE_8 + } else { + return Err(VulkanDecoderError::InvalidInputData(format!( + "unsupported luma bit length: {}", + sps.chroma_info.bit_depth_luma_minus8 + 8 + ))); + }; + + let chroma_bit_depth = if sps.chroma_info.bit_depth_chroma_minus8 + 8 == 8 { + vk::VideoComponentBitDepthFlagsKHR::TYPE_8 + } else { + return Err(VulkanDecoderError::InvalidInputData(format!( + "unsupported chroma bit length: {}", + sps.chroma_info.bit_depth_chroma_minus8 + 8 + ))); + }; + + let h264_info_ptr = h264_profile_info as *mut _; + let profile_info = vk::VideoProfileInfoKHR::default() + .video_codec_operation(vk::VideoCodecOperationFlagsKHR::DECODE_H264) + .chroma_subsampling(chroma_subsampling) + .luma_bit_depth(luma_bit_depth) + .chroma_bit_depth(chroma_bit_depth) + .push_next(h264_profile_info); + + Ok(Self { + profile_info, + h264_info_ptr, + }) + } +} + +impl<'a> Drop for H264ProfileInfo<'a> { + fn drop(&mut self) { + unsafe { + let _ = Box::from_raw(self.h264_info_ptr); + } + } +} + pub(crate) struct VkPictureParameterSet { pub(crate) pps: vk::native::StdVideoH264PictureParameterSet, } diff --git a/vk-video/src/vulkan_decoder/wrappers/video.rs b/vk-video/src/vulkan_decoder/wrappers/video.rs index e548f6ea8..315441719 100644 --- a/vk-video/src/vulkan_decoder/wrappers/video.rs +++ b/vk-video/src/vulkan_decoder/wrappers/video.rs @@ -185,6 +185,26 @@ impl Drop for VideoSession { } } +impl From for vk::native::StdVideoDecodeH264ReferenceInfo { + fn from(picture_info: crate::parser::ReferencePictureInfo) -> Self { + vk::native::StdVideoDecodeH264ReferenceInfo { + flags: vk::native::StdVideoDecodeH264ReferenceInfoFlags { + __bindgen_padding_0: [0; 3], + _bitfield_align_1: [], + _bitfield_1: vk::native::StdVideoDecodeH264ReferenceInfoFlags::new_bitfield_1( + 0, + 0, + picture_info.LongTermPicNum.is_some().into(), + picture_info.non_existing.into(), + ), + }, + FrameNum: picture_info.FrameNum, + PicOrderCnt: picture_info.PicOrderCnt, + reserved: 0, + } + } +} + impl From for vk::native::StdVideoDecodeH264ReferenceInfo { fn from(picture_info: crate::parser::PictureInfo) -> Self { vk::native::StdVideoDecodeH264ReferenceInfo { @@ -199,7 +219,7 @@ impl From for vk::native::StdVideoDecodeH264Referenc ), }, FrameNum: picture_info.FrameNum, - PicOrderCnt: picture_info.PicOrderCnt, + PicOrderCnt: picture_info.PicOrderCnt_as_reference_pic, reserved: 0, } } From 57d96dcadd23f41cd26986be61e8a3bb77149531 Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:52:41 +0100 Subject: [PATCH 16/51] Remove spec-compliant reference picture list init and modification. (#845) --- vk-video/src/parser.rs | 3 +- vk-video/src/parser/reference_manager.rs | 394 ++--------------------- vk-video/src/vulkan_decoder.rs | 6 +- 3 files changed, 32 insertions(+), 371 deletions(-) diff --git a/vk-video/src/parser.rs b/vk-video/src/parser.rs index 03648e8fc..fce05ef5f 100644 --- a/vk-video/src/parser.rs +++ b/vk-video/src/parser.rs @@ -21,8 +21,7 @@ mod reference_manager; #[derivative(Debug)] #[allow(non_snake_case)] pub struct DecodeInformation { - pub(crate) reference_list_l0: Option>, - pub(crate) reference_list_l1: Option>, + pub(crate) reference_list: Option>, #[derivative(Debug = "ignore")] pub(crate) rbsp_bytes: Vec, pub(crate) slice_indices: Vec, diff --git a/vk-video/src/parser/reference_manager.rs b/vk-video/src/parser/reference_manager.rs index 33a9c5a48..a8a5dccfc 100644 --- a/vk-video/src/parser/reference_manager.rs +++ b/vk-video/src/parser/reference_manager.rs @@ -2,10 +2,7 @@ use std::sync::Arc; use h264_reader::nal::{ pps::PicParameterSet, - slice::{ - DecRefPicMarking, MemoryManagementControlOperation, ModificationOfPicNums, NumRefIdxActive, - RefPicListModifications, SliceHeader, - }, + slice::{DecRefPicMarking, MemoryManagementControlOperation, SliceHeader}, sps::SeqParameterSet, }; @@ -32,12 +29,6 @@ pub enum ReferenceManagementError { #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ReferenceId(usize); -#[derive(Debug, Clone, Copy)] -enum BFrameReferenceListKind { - L0, - L1, -} - #[derive(Debug, Default)] #[allow(non_snake_case)] pub(crate) struct ReferenceContext { @@ -472,93 +463,21 @@ impl ReferenceContext { PicOrderCnt_for_decoding }; - let (reference_list_l0, reference_list_l1) = match header.slice_type.family { - h264_reader::nal::slice::SliceFamily::P => { - let num_ref_idx_l0_active = header.num_ref_idx_l0_active(pps); - - let mut reference_list_l0 = - self.initialize_reference_picture_list_for_p_frame(&header, sps)?; - - match &header.ref_pic_list_modification { - Some(RefPicListModifications::P { - ref_pic_list_modification_l0, - }) => { - self.modify_reference_picture_list( - sps, - &header, - &mut reference_list_l0, - ref_pic_list_modification_l0, - )?; - } - - None - | Some(RefPicListModifications::I) - | Some(RefPicListModifications::B { .. }) => return Err(ReferenceManagementError::IncorrectData( - "a slice marked 'P' slice family contains a reference picture list for a different family".into() - ))?, - } - - reference_list_l0.truncate(num_ref_idx_l0_active as usize); - - (Some(reference_list_l0), None) - } - h264_reader::nal::slice::SliceFamily::I => (None, None), - h264_reader::nal::slice::SliceFamily::B => { - let num_ref_idx_l0_active = header.num_ref_idx_l0_active(pps); - let num_ref_idx_l1_active = header.num_ref_idx_l1_active(pps)?; - - let mut reference_list_l0 = self.initialize_reference_picture_list_for_b_frame( - PicOrderCnt_for_decoding, - BFrameReferenceListKind::L0, - )?; - let mut reference_list_l1 = self.initialize_reference_picture_list_for_b_frame( - PicOrderCnt_for_decoding, - BFrameReferenceListKind::L1, - )?; - - match &header.ref_pic_list_modification { - Some(RefPicListModifications::B { - ref_pic_list_modification_l0, - ref_pic_list_modification_l1, - }) => { - self.modify_reference_picture_list( - sps, - &header, - &mut reference_list_l0, - ref_pic_list_modification_l0, - )?; - - self.modify_reference_picture_list( - sps, - &header, - &mut reference_list_l1, - ref_pic_list_modification_l1 - )?; - } - - None - | Some(RefPicListModifications::I) - | Some(RefPicListModifications::P { .. }) => return Err(ReferenceManagementError::IncorrectData( - "a slice marked 'B' slice family contains a reference picture list for a different family".into() - ))?, - } - - reference_list_l0.truncate(num_ref_idx_l0_active as usize); - reference_list_l1.truncate(num_ref_idx_l1_active as usize); - - (Some(reference_list_l0), Some(reference_list_l1)) + let reference_list = match header.slice_type.family { + h264_reader::nal::slice::SliceFamily::P | h264_reader::nal::slice::SliceFamily::B => { + Some(self.reference_list_for_frame(&header, sps)?) } + h264_reader::nal::slice::SliceFamily::I => None, h264_reader::nal::slice::SliceFamily::SP => { - return Err(ReferenceManagementError::SPFramesNotSupported)? + return Err(ReferenceManagementError::SPFramesNotSupported) } h264_reader::nal::slice::SliceFamily::SI => { - return Err(ReferenceManagementError::SIFramesNotSupported)? + return Err(ReferenceManagementError::SIFramesNotSupported) } }; Ok(DecodeInformation { - reference_list_l0, - reference_list_l1, + reference_list, header: header.clone(), slice_indices, rbsp_bytes, @@ -693,48 +612,35 @@ impl ReferenceContext { Ok([pic_order_cnt; 2]) } - fn initialize_short_term_reference_picture_list_for_p_frame( + fn short_term_reference_list_for_frame( &self, header: &SliceHeader, sps: &SeqParameterSet, ) -> Vec { - let mut short_term_reference_list = self - .pictures + self.pictures .short_term .iter() .map(|reference| { - ( - reference, - decode_picture_numbers_for_short_term_ref( - reference.header.frame_num.into(), - header.frame_num.into(), - sps, - ), - ) - }) - .collect::>(); - - short_term_reference_list.sort_by_key(|(_, numbers)| -numbers.PicNum); - - short_term_reference_list - .into_iter() - .map(|(reference, numbers)| ReferencePictureInfo { - id: reference.id, - LongTermPicNum: None, - FrameNum: numbers.FrameNum as u16, - non_existing: false, - PicOrderCnt: reference.pic_order_cnt, + let numbers = decode_picture_numbers_for_short_term_ref( + reference.header.frame_num.into(), + header.frame_num.into(), + sps, + ); + ReferencePictureInfo { + id: reference.id, + LongTermPicNum: None, + FrameNum: numbers.FrameNum as u16, + non_existing: false, + PicOrderCnt: reference.pic_order_cnt, + } }) .collect() } - fn initialize_long_term_reference_picture_list_for_frame(&self) -> Vec { - let mut long_term_reference_list = self.pictures.long_term.clone(); - - long_term_reference_list.sort_by_key(|pic| pic.LongTermFrameIdx); - - long_term_reference_list - .into_iter() + fn long_term_reference_list_for_frame(&self) -> Vec { + self.pictures + .long_term + .iter() .map(|pic| ReferencePictureInfo { id: pic.id, LongTermPicNum: Some(pic.LongTermFrameIdx), @@ -745,34 +651,14 @@ impl ReferenceContext { .collect() } - fn initialize_reference_picture_list_for_p_frame( + fn reference_list_for_frame( &self, header: &SliceHeader, sps: &SeqParameterSet, ) -> Result, ReferenceManagementError> { - let short_term_reference_list = - self.initialize_short_term_reference_picture_list_for_p_frame(header, sps); - - let long_term_reference_list = self.initialize_long_term_reference_picture_list_for_frame(); - - let reference_list = short_term_reference_list - .into_iter() - .chain(long_term_reference_list) - .collect::>(); - - Ok(reference_list) - } - - #[allow(non_snake_case)] - fn initialize_reference_picture_list_for_b_frame( - &self, - CurrPicOrderCnt: [i32; 2], - list_kind: BFrameReferenceListKind, - ) -> Result, ReferenceManagementError> { - let short_term_reference_list = self - .initialize_short_term_reference_picture_list_for_b_frame(CurrPicOrderCnt, list_kind)?; + let short_term_reference_list = self.short_term_reference_list_for_frame(header, sps); - let long_term_reference_list = self.initialize_long_term_reference_picture_list_for_frame(); + let long_term_reference_list = self.long_term_reference_list_for_frame(); let reference_list = short_term_reference_list .into_iter() @@ -781,191 +667,6 @@ impl ReferenceContext { Ok(reference_list) } - - #[allow(non_snake_case)] - fn initialize_short_term_reference_picture_list_for_b_frame( - &self, - CurrPicOrderCnt: [i32; 2], - list_kind: BFrameReferenceListKind, - ) -> Result, ReferenceManagementError> { - let mut reference_list = self - .pictures - .short_term - .iter() - .filter(|pic| match list_kind { - BFrameReferenceListKind::L0 => pic.pic_order_cnt < CurrPicOrderCnt, - BFrameReferenceListKind::L1 => pic.pic_order_cnt > CurrPicOrderCnt, - }) - .collect::>(); - - reference_list.sort_by_key(|pic| match list_kind { - BFrameReferenceListKind::L0 => -pic.pic_order_cnt[0], - BFrameReferenceListKind::L1 => pic.pic_order_cnt[0], - }); - - let reference_list = reference_list - .into_iter() - .map(|pic| ReferencePictureInfo { - LongTermPicNum: None, - FrameNum: pic.header.frame_num, - non_existing: false, - PicOrderCnt: pic.pic_order_cnt, - id: pic.id, - }) - .collect(); - - Ok(reference_list) - } - - #[allow(non_snake_case)] - fn modify_reference_picture_list( - &self, - sps: &SeqParameterSet, - header: &SliceHeader, - reference_list: &mut Vec, - ref_pic_list_modifications: &[ModificationOfPicNums], - ) -> Result<(), ReferenceManagementError> { - // 0 is Subtract, 1 is Add, 2 is LongTermRef - let mut refIdxL0 = 0; - let mut picNumL0Pred = header.frame_num as i64; - - for ref_pic_list_modification in ref_pic_list_modifications { - match ref_pic_list_modification { - ModificationOfPicNums::Subtract(_) | ModificationOfPicNums::Add(_) => { - self.modify_short_term_reference_picture_list( - sps, - header, - reference_list, - ref_pic_list_modification, - &mut refIdxL0, - &mut picNumL0Pred, - )?; - } - - ModificationOfPicNums::LongTermRef(long_term_pic_num) => { - self.modify_long_term_reference_picture_list( - reference_list, - *long_term_pic_num, - &mut refIdxL0, - )?; - } - } - } - - Ok(()) - } - - #[allow(non_snake_case)] - fn modify_long_term_reference_picture_list( - &self, - reference_list: &mut Vec, - picture_to_shift: u32, - refIdxLX: &mut usize, - ) -> Result<(), ReferenceManagementError> { - let shifted_picture_idx = reference_list - .iter() - .enumerate() - .find(|(_, pic)| match pic.LongTermPicNum { - Some(num) => num == picture_to_shift.into(), - None => false, - }) - .map(|(i, _)| i) - .ok_or(ReferenceManagementError::IncorrectData( - format!("picture with LongTermPicNum = {picture_to_shift} is not present in the reference list during modification") - ))?; - - if reference_list[shifted_picture_idx].non_existing { - return Err(ReferenceManagementError::IncorrectData( - "a short-term reference picture marked for shifting in the reference list modification process is marked as non-existing".into() - )); - } - - if reference_list[shifted_picture_idx].LongTermPicNum.is_none() { - return Err(ReferenceManagementError::IncorrectData( - "a short-term reference picture marked for shifting in the long-term reference list modification process".into() - )); - } - - let shifted_picture = reference_list.remove(shifted_picture_idx); - reference_list.insert(*refIdxLX, shifted_picture); - *refIdxLX += 1; - - Ok(()) - } - - #[allow(non_snake_case)] - fn modify_short_term_reference_picture_list( - &self, - sps: &SeqParameterSet, - header: &SliceHeader, - reference_list: &mut Vec, - ref_pic_list_modification: &ModificationOfPicNums, - refIdxLX: &mut usize, - picNumLXPred: &mut i64, - ) -> Result<(), ReferenceManagementError> { - let picNumLXNoWrap = match *ref_pic_list_modification { - ModificationOfPicNums::Subtract(abs_diff_pic_num_minus_1) => { - let abs_diff_pic_num = abs_diff_pic_num_minus_1 as i64 + 1; - if *picNumLXPred - abs_diff_pic_num < 0 { - *picNumLXPred - abs_diff_pic_num + sps.max_frame_num() - } else { - *picNumLXPred - abs_diff_pic_num - } - } - ModificationOfPicNums::Add(abs_diff_pic_num_minus_1) => { - let abs_diff_pic_num = abs_diff_pic_num_minus_1 as i64 + 1; - if *picNumLXPred + abs_diff_pic_num >= sps.max_frame_num() { - *picNumLXPred + abs_diff_pic_num - sps.max_frame_num() - } else { - *picNumLXPred + abs_diff_pic_num - } - } - ModificationOfPicNums::LongTermRef(_) => return Ok(()), - }; - - *picNumLXPred = picNumLXNoWrap; - - let picNumLX = if picNumLXNoWrap > header.frame_num as i64 { - picNumLXNoWrap - sps.max_frame_num() - } else { - picNumLXNoWrap - }; - - let mut shifted_picture_idx = reference_list - .iter() - .enumerate() - .find(|(_, picture_info)| decode_picture_numbers_for_short_term_ref(picture_info.FrameNum.into(), header.frame_num.into(), sps).PicNum == picNumLX) - .map(|(i, _)| i) - .ok_or(ReferenceManagementError::IncorrectData( - format!("picture with picNumLX = {picNumLX} is not present in the reference list during modification") - ))?; - - if reference_list[shifted_picture_idx].non_existing { - return Err(ReferenceManagementError::IncorrectData( - "a short-term reference picture marked for shifting in the reference list modification process is marked as non-existing".into() - )); - } - - if reference_list[shifted_picture_idx].LongTermPicNum.is_some() { - return Err(ReferenceManagementError::IncorrectData( - "a long-term reference picture marked for shifting in the short-term reference list modification process".into() - )); - } - - let shifted_picture_info = reference_list[shifted_picture_idx]; - if *refIdxLX <= reference_list.len() { - reference_list.insert(*refIdxLX, shifted_picture_info); - shifted_picture_idx = if *refIdxLX <= shifted_picture_idx { - shifted_picture_idx + 1 - } else { - shifted_picture_idx - }; - } - *refIdxLX += 1; - reference_list.remove(shifted_picture_idx); - - Ok(()) - } } #[derive(Debug)] @@ -1026,47 +727,10 @@ struct ReferencePictures { } trait SliceHeaderExt { - fn num_ref_idx_l0_active(&self, pps: &PicParameterSet) -> u32; - fn num_ref_idx_l1_active(&self, pps: &PicParameterSet) - -> Result; fn includes_mmco_equal_5(&self) -> bool; } impl SliceHeaderExt for SliceHeader { - fn num_ref_idx_l0_active(&self, pps: &PicParameterSet) -> u32 { - self.num_ref_idx_active - .as_ref() - .map(|num| match num { - NumRefIdxActive::P { - num_ref_idx_l0_active_minus1, - } => *num_ref_idx_l0_active_minus1, - NumRefIdxActive::B { - num_ref_idx_l0_active_minus1, - .. - } => *num_ref_idx_l0_active_minus1, - }) - .unwrap_or(pps.num_ref_idx_l0_default_active_minus1) - + 1 - } - - fn num_ref_idx_l1_active( - &self, - pps: &PicParameterSet, - ) -> Result { - Ok( - self - .num_ref_idx_active - .as_ref() - .map(|num| match num { - NumRefIdxActive::P { .. } => Err(ReferenceManagementError::IncorrectData( - "requested num_ref_idx_l1_active, but the header contains the information for a P-frame, which does not include it".into() - )), - NumRefIdxActive::B { num_ref_idx_l1_active_minus1, .. } => Ok(*num_ref_idx_l1_active_minus1) - }) - .unwrap_or(Ok(pps.num_ref_idx_l1_default_active_minus1))? + 1 - ) - } - fn includes_mmco_equal_5(&self) -> bool { let Some(DecRefPicMarking::Adaptive(ref mmcos)) = self.dec_ref_pic_marking else { return false; diff --git a/vk-video/src/vulkan_decoder.rs b/vk-video/src/vulkan_decoder.rs index 65e86b70e..099c92d10 100644 --- a/vk-video/src/vulkan_decoder.rs +++ b/vk-video/src/vulkan_decoder.rs @@ -813,10 +813,9 @@ impl VulkanDecoder<'_> { decode_information: &DecodeInformation, ) -> Vec { decode_information - .reference_list_l0 + .reference_list .iter() .flatten() - .chain(decode_information.reference_list_l1.iter().flatten()) .map(|&ref_info| ref_info.into()) .collect::>() } @@ -838,10 +837,9 @@ impl VulkanDecoder<'_> { ) -> Result>, VulkanDecoderError> { let mut pic_reference_slots: Vec> = Vec::new(); for (ref_info, dpb_slot_info) in decode_information - .reference_list_l0 + .reference_list .iter() .flatten() - .chain(decode_information.reference_list_l1.iter().flatten()) .zip(references_dpb_slot_info.iter_mut()) { let i = *reference_id_to_dpb_slot_index From 368457eaa8634d1c5a83c2ddfbb5581b6493f862 Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Mon, 4 Nov 2024 15:01:01 +0100 Subject: [PATCH 17/51] Implement layouts for border,border-radius,box-shadow (#842) --- compositor_api/src/types/component.rs | 80 +++-- compositor_api/src/types/from_component.rs | 41 +++ compositor_render/src/scene/components.rs | 16 +- .../src/scene/components/interpolation.rs | 44 ++- .../src/scene/components/position.rs | 27 ++ compositor_render/src/scene/layout.rs | 16 +- .../src/scene/rescaler_component.rs | 21 +- .../scene/rescaler_component/interpolation.rs | 12 + .../src/scene/rescaler_component/layout.rs | 87 +++-- .../src/scene/tiles_component/layout.rs | 17 +- compositor_render/src/scene/types.rs | 78 +++++ compositor_render/src/scene/view_component.rs | 17 +- .../src/scene/view_component/interpolation.rs | 12 + .../src/scene/view_component/layout.rs | 78 +++-- .../src/transformations/layout.rs | 68 +++- .../transformations/layout/apply_layouts.wgsl | 94 ++++-- .../src/transformations/layout/flatten.rs | 310 ++++++++++++++---- .../src/transformations/layout/params.rs | 61 ++-- .../wgpu/format/interleaved_yuv_to_rgba.wgsl | 11 +- .../src/wgpu/format/nv12_to_rgba.wgsl | 11 +- .../examples/raw_channel_output.rs | 2 +- .../examples/rescaler_border_transition.rs | 154 +++++++++ .../examples/view_border_transition.rs | 166 ++++++++++ schemas/scene.schema.json | 142 +++++++- .../rescaler/border_radius.scene.json | 22 ++ ...border_radius_border_box_shadow.scene.json | 32 ++ ...dius_border_box_shadow_rescaled.scene.json | 37 +++ .../border_radius_box_shadow.scene.json | 30 ++ ...us_box_shadow_fill_input_stream.scene.json | 33 ++ ...ius_box_shadow_fit_input_stream.scene.json | 33 ++ .../rescaler/border_width.scene.json | 23 ++ snapshot_tests/rescaler/box_shadow.scene.json | 29 ++ .../nested_border_width_radius.scene.json | 37 +++ ...ted_border_width_radius_aligned.scene.json | 37 +++ snapshot_tests/snapshots | 2 +- snapshot_tests/view/border_radius.scene.json | 19 ++ ...border_radius_border_box_shadow.scene.json | 29 ++ ...dius_border_box_shadow_rescaled.scene.json | 34 ++ ...w_rescaled_and_hidden_by_parent.scene.json | 41 +++ .../view/border_radius_box_shadow.scene.json | 27 ++ ..._radius_box_shadow_overflow_fit.scene.json | 36 ++ ...dius_box_shadow_overflow_hidden.scene.json | 35 ++ ...ox_shadow_rescaler_input_stream.scene.json | 40 +++ snapshot_tests/view/border_width.scene.json | 20 ++ snapshot_tests/view/box_shadow.scene.json | 26 ++ .../view/box_shadow_sibling.scene.json | 52 +++ .../nested_border_width_radius.scene.json | 42 +++ ...ted_border_width_radius_aligned.scene.json | 42 +++ ...border_width_radius_multi_child.scene.json | 74 +++++ ...border_radius_border_box_shadow.scene.json | 19 ++ src/bin/update_snapshots/main.rs | 3 +- src/snapshot_tests.rs | 2 +- src/snapshot_tests/tests.rs | 230 ++++++++++++- 53 files changed, 2390 insertions(+), 261 deletions(-) create mode 100644 compositor_render/src/scene/components/position.rs create mode 100644 integration_tests/examples/rescaler_border_transition.rs create mode 100644 integration_tests/examples/view_border_transition.rs create mode 100644 snapshot_tests/rescaler/border_radius.scene.json create mode 100644 snapshot_tests/rescaler/border_radius_border_box_shadow.scene.json create mode 100644 snapshot_tests/rescaler/border_radius_border_box_shadow_rescaled.scene.json create mode 100644 snapshot_tests/rescaler/border_radius_box_shadow.scene.json create mode 100644 snapshot_tests/rescaler/border_radius_box_shadow_fill_input_stream.scene.json create mode 100644 snapshot_tests/rescaler/border_radius_box_shadow_fit_input_stream.scene.json create mode 100644 snapshot_tests/rescaler/border_width.scene.json create mode 100644 snapshot_tests/rescaler/box_shadow.scene.json create mode 100644 snapshot_tests/rescaler/nested_border_width_radius.scene.json create mode 100644 snapshot_tests/rescaler/nested_border_width_radius_aligned.scene.json create mode 100644 snapshot_tests/view/border_radius.scene.json create mode 100644 snapshot_tests/view/border_radius_border_box_shadow.scene.json create mode 100644 snapshot_tests/view/border_radius_border_box_shadow_rescaled.scene.json create mode 100644 snapshot_tests/view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent.scene.json create mode 100644 snapshot_tests/view/border_radius_box_shadow.scene.json create mode 100644 snapshot_tests/view/border_radius_box_shadow_overflow_fit.scene.json create mode 100644 snapshot_tests/view/border_radius_box_shadow_overflow_hidden.scene.json create mode 100644 snapshot_tests/view/border_radius_box_shadow_rescaler_input_stream.scene.json create mode 100644 snapshot_tests/view/border_width.scene.json create mode 100644 snapshot_tests/view/box_shadow.scene.json create mode 100644 snapshot_tests/view/box_shadow_sibling.scene.json create mode 100644 snapshot_tests/view/nested_border_width_radius.scene.json create mode 100644 snapshot_tests/view/nested_border_width_radius_aligned.scene.json create mode 100644 snapshot_tests/view/nested_border_width_radius_multi_child.scene.json create mode 100644 snapshot_tests/view/root_border_radius_border_box_shadow.scene.json diff --git a/compositor_api/src/types/component.rs b/compositor_api/src/types/component.rs index b08762531..d8cac4430 100644 --- a/compositor_api/src/types/component.rs +++ b/compositor_api/src/types/component.rs @@ -36,14 +36,14 @@ pub struct View { /// List of component's children. pub children: Option>, - /// Width of a component in pixels. Exact behavior might be different based on the parent - /// component: + /// Width of a component in pixels (without a border). Exact behavior might be different + /// based on the parent component: /// - If the parent component is a layout, check sections "Absolute positioning" and "Static /// positioning" of that component. /// - If the parent component is not a layout, then this field is required. pub width: Option, - /// Height of a component in pixels. Exact behavior might be different based on the parent - /// component: + /// Height of a component in pixels (without a border). Exact behavior might be different + /// based on the parent component: /// - If the parent component is a layout, check sections "Absolute positioning" and "Static /// positioning" of that component. /// - If the parent component is not a layout, then this field is required. @@ -52,16 +52,16 @@ pub struct View { /// Direction defines how static children are positioned inside a View component. pub direction: Option, - /// Distance in pixels between this component's top edge and its parent's top edge. + /// Distance in pixels between this component's top edge and its parent's top edge (including a border). /// If this field is defined, then the component will ignore a layout defined by its parent. pub top: Option, - /// Distance in pixels between this component's left edge and its parent's left edge. + /// Distance in pixels between this component's left edge and its parent's left edge (including a border). /// If this field is defined, this element will be absolutely positioned, instead of being /// laid out by its parent. pub left: Option, - /// Distance in pixels between the bottom edge of this component and the bottom edge of its parent. - /// If this field is defined, this element will be absolutely positioned, instead of being - /// laid out by its parent. + /// Distance in pixels between the bottom edge of this component and the bottom edge of its + /// parent (including a border). If this field is defined, this element will be absolutely + /// positioned, instead of being laid out by its parent. pub bottom: Option, /// Distance in pixels between this component's right edge and its parent's right edge. /// If this field is defined, this element will be absolutely positioned, instead of being @@ -80,6 +80,27 @@ pub struct View { /// (**default=`"#00000000"`**) Background color in a `"#RRGGBBAA"` format. pub background_color_rgba: Option, + + /// (**default=`0.0`**) Radius of a rounded corner. + pub border_radius: Option, + + /// (**default=`0.0`**) Border width. + pub border_width: Option, + + /// (**default=`"#00000000"`**) Border color in a `"#RRGGBBAA"` format. + pub border_color_rgba: Option, + + /// List of box shadows. + pub box_shadow: Option>, +} + +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct BoxShadow { + pub offset_x: Option, + pub offset_y: Option, + pub color_rgba: Option, + pub blur_radius: Option, } #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] @@ -126,29 +147,29 @@ pub struct Rescaler { /// (**default=`"center"`**) Vertical alignment. pub vertical_align: Option, - /// Width of a component in pixels. Exact behavior might be different based on the parent - /// component: + /// Width of a component in pixels (without a border). Exact behavior might be different + /// based on the parent component: /// - If the parent component is a layout, check sections "Absolute positioning" and "Static /// positioning" of that component. /// - If the parent component is not a layout, then this field is required. pub width: Option, - /// Height of a component in pixels. Exact behavior might be different based on the parent - /// component: + /// Height of a component in pixels (without a border). Exact behavior might be different + /// based on the parent component: /// - If the parent component is a layout, check sections "Absolute positioning" and "Static /// positioning" of that component. /// - If the parent component is not a layout, then this field is required. pub height: Option, - /// Distance in pixels between this component's top edge and its parent's top edge. + /// Distance in pixels between this component's top edge and its parent's top edge (including a border). /// If this field is defined, then the component will ignore a layout defined by its parent. pub top: Option, - /// Distance in pixels between this component's left edge and its parent's left edge. + /// Distance in pixels between this component's left edge and its parent's left edge (including a border). /// If this field is defined, this element will be absolutely positioned, instead of being /// laid out by its parent. pub left: Option, - /// Distance in pixels between this component's bottom edge and its parent's bottom edge. - /// If this field is defined, this element will be absolutely positioned, instead of being - /// laid out by its parent. + /// Distance in pixels between the bottom edge of this component and the bottom edge of its + /// parent (including a border). If this field is defined, this element will be absolutely + /// positioned, instead of being laid out by its parent. pub bottom: Option, /// Distance in pixels between this component's right edge and its parent's right edge. /// If this field is defined, this element will be absolutely positioned, instead of being @@ -161,6 +182,18 @@ pub struct Rescaler { /// Defines how this component will behave during a scene update. This will only have an /// effect if the previous scene already contained a `Rescaler` component with the same id. pub transition: Option, + + /// (**default=`0.0`**) Radius of a rounded corner. + pub border_radius: Option, + + /// (**default=`0.0`**) Border width. + pub border_width: Option, + + /// (**default=`"#00000000"`**) Border color in a `"#RRGGBBAA"` format. + pub border_color_rgba: Option, + + /// List of box shadows. + pub box_shadow: Option>, } #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] @@ -183,7 +216,8 @@ pub struct WebView { /// List of component's children. pub children: Option>, - /// Id of a web renderer instance. It identifies an instance registered using a [`register web renderer`](../routes.md#register-web-renderer-instance) request. + /// Id of a web renderer instance. It identifies an instance registered using a + /// [`register web renderer`](../routes.md#register-web-renderer-instance) request. /// /// :::warning /// You can only refer to specific instances in one Component at a time. @@ -217,8 +251,10 @@ pub struct Shader { /// @group(1) @binding(0) var /// ``` /// :::note - /// This object's structure must match the structure defined in a shader source code. Currently, we do not handle memory layout automatically. - /// To achieve the correct memory alignment, you might need to pad your data with additional fields. See [WGSL documentation](https://www.w3.org/TR/WGSL/#alignment-and-size) for more details. + /// This object's structure must match the structure defined in a shader source code. + /// Currently, we do not handle memory layout automatically. To achieve the correct memory + /// alignment, you might need to pad your data with additional fields. See + /// [WGSL documentation](https://www.w3.org/TR/WGSL/#alignment-and-size) for more details. /// ::: pub shader_param: Option, /// Resolution of a texture where shader will be executed. @@ -378,4 +414,6 @@ pub struct Tiles { /// Defines how this component will behave during a scene update. This will only have an /// effect if the previous scene already contained a `Tiles` component with the same id. pub transition: Option, + + pub border_radius: Option, } diff --git a/compositor_api/src/types/from_component.rs b/compositor_api/src/types/from_component.rs index 66a4346ac..5bc2ad9fb 100644 --- a/compositor_api/src/types/from_component.rs +++ b/compositor_api/src/types/from_component.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use compositor_render::scene; +use compositor_render::scene::BorderRadius; use compositor_render::scene::Position; use compositor_render::MAX_NODE_RESOLUTION; @@ -101,6 +102,18 @@ impl TryFrom for scene::ViewComponent { .map(TryInto::try_into) .unwrap_or(Ok(scene::RGBAColor(0, 0, 0, 0)))?, transition: view.transition.map(TryInto::try_into).transpose()?, + border_radius: BorderRadius::new_with_radius(view.border_radius.unwrap_or(0.0)), + border_width: view.border_width.unwrap_or(0.0), + border_color: view + .border_color_rgba + .map(TryInto::try_into) + .unwrap_or(Ok(scene::RGBAColor(0, 0, 0, 0)))?, + box_shadow: view + .box_shadow + .unwrap_or_default() + .into_iter() + .map(TryInto::try_into) + .collect::>()?, }) } } @@ -165,6 +178,18 @@ impl TryFrom for scene::RescalerComponent { .unwrap_or(VerticalAlign::Center) .into(), transition: rescaler.transition.map(TryInto::try_into).transpose()?, + border_radius: BorderRadius::new_with_radius(rescaler.border_radius.unwrap_or(0.0)), + border_width: rescaler.border_width.unwrap_or(0.0), + border_color: rescaler + .border_color_rgba + .map(TryInto::try_into) + .unwrap_or(Ok(scene::RGBAColor(0, 0, 0, 0)))?, + box_shadow: rescaler + .box_shadow + .unwrap_or_default() + .into_iter() + .map(TryInto::try_into) + .collect::>()?, }) } } @@ -339,3 +364,19 @@ impl TryFrom for scene::TilesComponent { Ok(result) } } + +impl TryFrom for scene::BoxShadow { + type Error = TypeError; + + fn try_from(value: BoxShadow) -> Result { + Ok(Self { + offset_x: value.offset_x.unwrap_or(0.0), + offset_y: value.offset_y.unwrap_or(0.0), + blur_radius: value.blur_radius.unwrap_or(0.0), + color: value + .color_rgba + .map(TryInto::try_into) + .unwrap_or(Ok(scene::RGBAColor(255, 255, 255, 255)))?, + }) + } +} diff --git a/compositor_render/src/scene/components.rs b/compositor_render/src/scene/components.rs index e0396c054..1ad769a45 100644 --- a/compositor_render/src/scene/components.rs +++ b/compositor_render/src/scene/components.rs @@ -3,10 +3,12 @@ use std::{fmt::Display, sync::Arc, time::Duration}; use crate::{InputId, RendererId}; use super::{ - AbsolutePosition, Component, HorizontalAlign, InterpolationKind, RGBAColor, Size, VerticalAlign, + AbsolutePosition, BorderRadius, BoxShadow, Component, HorizontalAlign, InterpolationKind, + RGBAColor, Size, VerticalAlign, }; mod interpolation; +mod position; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ComponentId(pub Arc); @@ -140,6 +142,12 @@ pub struct ViewComponent { pub overflow: Overflow, pub background_color: RGBAColor, + + pub border_radius: BorderRadius, + pub border_width: f32, + pub border_color: RGBAColor, + + pub box_shadow: Vec, } #[derive(Debug, Clone, Copy)] @@ -181,6 +189,12 @@ pub struct RescalerComponent { pub mode: RescaleMode, pub horizontal_align: HorizontalAlign, pub vertical_align: VerticalAlign, + + pub border_radius: BorderRadius, + pub border_width: f32, + pub border_color: RGBAColor, + + pub box_shadow: Vec, } #[derive(Debug, Clone, Copy)] diff --git a/compositor_render/src/scene/components/interpolation.rs b/compositor_render/src/scene/components/interpolation.rs index d2872457b..a01e95c6e 100644 --- a/compositor_render/src/scene/components/interpolation.rs +++ b/compositor_render/src/scene/components/interpolation.rs @@ -1,4 +1,7 @@ -use crate::scene::types::interpolation::{ContinuousValue, InterpolationState}; +use crate::scene::{ + types::interpolation::{ContinuousValue, InterpolationState}, + BorderRadius, BoxShadow, +}; use super::{AbsolutePosition, Position}; @@ -46,3 +49,42 @@ impl ContinuousValue for AbsolutePosition { } } } + +impl ContinuousValue for BorderRadius { + fn interpolate(start: &Self, end: &Self, state: InterpolationState) -> Self { + Self { + top_left: ContinuousValue::interpolate(&start.top_left, &end.top_left, state), + top_right: ContinuousValue::interpolate(&start.top_right, &end.top_right, state), + bottom_right: ContinuousValue::interpolate( + &start.bottom_right, + &end.bottom_right, + state, + ), + bottom_left: ContinuousValue::interpolate(&start.bottom_left, &end.bottom_left, state), + } + } +} + +impl ContinuousValue for Vec { + fn interpolate(start: &Self, end: &Self, state: InterpolationState) -> Self { + start + .iter() + .zip(end.iter()) + // interpolate as long both lists have entries + .map(|(start, end)| ContinuousValue::interpolate(start, end, state)) + // add remaining elements if end is longer + .chain(end.iter().skip(usize::min(start.len(), end.len())).copied()) + .collect() + } +} + +impl ContinuousValue for BoxShadow { + fn interpolate(start: &Self, end: &Self, state: InterpolationState) -> Self { + Self { + offset_x: ContinuousValue::interpolate(&start.offset_x, &end.offset_x, state), + offset_y: ContinuousValue::interpolate(&start.offset_y, &end.offset_y, state), + blur_radius: ContinuousValue::interpolate(&start.blur_radius, &end.blur_radius, state), + color: end.color, + } + } +} diff --git a/compositor_render/src/scene/components/position.rs b/compositor_render/src/scene/components/position.rs new file mode 100644 index 000000000..0525293d2 --- /dev/null +++ b/compositor_render/src/scene/components/position.rs @@ -0,0 +1,27 @@ +use crate::scene::AbsolutePosition; + +use super::Position; + +impl Position { + pub(crate) fn with_border(self, border_width: f32) -> Self { + match self { + Position::Static { width, height } => Self::Static { + width: width.map(|w| w + 2.0 * border_width), + height: height.map(|h| h + 2.0 * border_width), + }, + Position::Absolute(AbsolutePosition { + width, + height, + position_horizontal, + position_vertical, + rotation_degrees, + }) => Self::Absolute(AbsolutePosition { + width: width.map(|w| w + 2.0 * border_width), + height: height.map(|h| h + 2.0 * border_width), + position_horizontal, + position_vertical, + rotation_degrees, + }), + } + } +} diff --git a/compositor_render/src/scene/layout.rs b/compositor_render/src/scene/layout.rs index 8a2ab7d09..710661c46 100644 --- a/compositor_render/src/scene/layout.rs +++ b/compositor_render/src/scene/layout.rs @@ -7,8 +7,8 @@ use crate::{ use super::{ rescaler_component::StatefulRescalerComponent, tiles_component::StatefulTilesComponent, - view_component::StatefulViewComponent, AbsolutePosition, ComponentId, HorizontalPosition, - Position, Size, StatefulComponent, VerticalPosition, + view_component::StatefulViewComponent, AbsolutePosition, BorderRadius, ComponentId, + HorizontalPosition, Position, RGBAColor, Size, StatefulComponent, VerticalPosition, }; #[derive(Debug, Clone)] @@ -49,6 +49,7 @@ impl StatefulLayoutComponent { } } + // External position of a component (includes border, padding, ...) pub(super) fn position(&self, pts: Duration) -> Position { match self { StatefulLayoutComponent::View(view) => view.position(pts), @@ -177,6 +178,7 @@ impl StatefulLayoutComponent { let rotation_degrees = position.rotation_degrees; let content = Self::layout_content(child, 0); let crop = None; + let mask = None; match child { StatefulComponent::Layout(layout_component) => { @@ -194,10 +196,15 @@ impl StatefulLayoutComponent { scale_x: 1.0, scale_y: 1.0, crop, + mask, content, child_nodes_count, children: vec![children_layouts], + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], } } _non_layout_components => { @@ -215,10 +222,15 @@ impl StatefulLayoutComponent { scale_x: 1.0, scale_y: 1.0, crop, + mask, content, child_nodes_count, children: vec![], + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], } } } diff --git a/compositor_render/src/scene/rescaler_component.rs b/compositor_render/src/scene/rescaler_component.rs index 259dcf60e..4bd40d8d5 100644 --- a/compositor_render/src/scene/rescaler_component.rs +++ b/compositor_render/src/scene/rescaler_component.rs @@ -8,8 +8,8 @@ use super::{ scene_state::BuildStateTreeCtx, transition::{TransitionOptions, TransitionState}, types::interpolation::ContinuousValue, - Component, ComponentId, HorizontalAlign, IntermediateNode, Position, RescaleMode, SceneError, - Size, StatefulComponent, VerticalAlign, + BorderRadius, BoxShadow, Component, ComponentId, HorizontalAlign, IntermediateNode, Position, + RGBAColor, RescaleMode, SceneError, Size, StatefulComponent, VerticalAlign, }; mod interpolation; @@ -31,6 +31,12 @@ struct RescalerComponentParam { mode: RescaleMode, horizontal_align: HorizontalAlign, vertical_align: VerticalAlign, + + border_radius: BorderRadius, + border_width: f32, + border_color: RGBAColor, + + box_shadow: Vec, } impl StatefulRescalerComponent { @@ -52,7 +58,8 @@ impl StatefulRescalerComponent { } pub(super) fn position(&self, pts: Duration) -> Position { - self.transition_snapshot(pts).position + let rescaler = self.transition_snapshot(pts); + rescaler.position.with_border(rescaler.border_width) } pub(super) fn component_id(&self) -> Option<&ComponentId> { @@ -107,7 +114,7 @@ impl RescalerComponent { previous_state.and_then(|s| s.transition.clone()), ctx.last_render_pts, ); - let view = StatefulRescalerComponent { + let rescaler = StatefulRescalerComponent { start, end: RescalerComponentParam { id: self.id, @@ -115,12 +122,16 @@ impl RescalerComponent { mode: self.mode, horizontal_align: self.horizontal_align, vertical_align: self.vertical_align, + border_radius: self.border_radius, + border_width: self.border_width, + border_color: self.border_color, + box_shadow: self.box_shadow, }, transition, child: Box::new(Component::stateful_component(*self.child, ctx)?), }; Ok(StatefulComponent::Layout( - StatefulLayoutComponent::Rescaler(view), + StatefulLayoutComponent::Rescaler(rescaler), )) } } diff --git a/compositor_render/src/scene/rescaler_component/interpolation.rs b/compositor_render/src/scene/rescaler_component/interpolation.rs index 019100c9b..78dc02482 100644 --- a/compositor_render/src/scene/rescaler_component/interpolation.rs +++ b/compositor_render/src/scene/rescaler_component/interpolation.rs @@ -10,6 +10,18 @@ impl ContinuousValue for RescalerComponentParam { mode: end.mode, horizontal_align: end.horizontal_align, vertical_align: end.vertical_align, + border_radius: ContinuousValue::interpolate( + &start.border_radius, + &end.border_radius, + state, + ), + border_width: ContinuousValue::interpolate( + &start.border_width, + &end.border_width, + state, + ), + border_color: end.border_color, + box_shadow: ContinuousValue::interpolate(&start.box_shadow, &end.box_shadow, state), } } } diff --git a/compositor_render/src/scene/rescaler_component/layout.rs b/compositor_render/src/scene/rescaler_component/layout.rs index cdf71b5db..7127ff103 100644 --- a/compositor_render/src/scene/rescaler_component/layout.rs +++ b/compositor_render/src/scene/rescaler_component/layout.rs @@ -2,10 +2,10 @@ use std::time::Duration; use crate::{ scene::{ - layout::StatefulLayoutComponent, HorizontalAlign, RescaleMode, Size, StatefulComponent, - VerticalAlign, + layout::StatefulLayoutComponent, BorderRadius, HorizontalAlign, RGBAColor, RescaleMode, + Size, StatefulComponent, VerticalAlign, }, - transformations::layout::{Crop, LayoutContent, NestedLayout}, + transformations::layout::{LayoutContent, Mask, NestedLayout}, }; use super::RescalerComponentParam; @@ -17,50 +17,58 @@ impl RescalerComponentParam { child: &mut StatefulComponent, pts: Duration, ) -> NestedLayout { + let content_size = Size { + width: f32::max(size.width - (2.0 * self.border_width), 0.0), + height: f32::max(size.height - (2.0 * self.border_width), 0.0), + }; let child_width = child.width(pts); let child_height = child.height(pts); match (child_width, child_height) { - (None, None) => self.layout_with_scale(size, child, pts, 1.0), + (None, None) => self.layout_with_scale(content_size, child, pts, 1.0), (None, Some(child_height)) => { - self.layout_with_scale(size, child, pts, size.height / child_height) + self.layout_with_scale(content_size, child, pts, content_size.height / child_height) } (Some(child_width), None) => { - self.layout_with_scale(size, child, pts, size.width / child_width) + self.layout_with_scale(content_size, child, pts, content_size.width / child_width) } (Some(child_width), Some(child_height)) => { let scale = match self.mode { - RescaleMode::Fit => { - f32::min(size.width / child_width, size.height / child_height) - } - RescaleMode::Fill => { - f32::max(size.width / child_width, size.height / child_height) - } + RescaleMode::Fit => f32::min( + content_size.width / child_width, + content_size.height / child_height, + ), + RescaleMode::Fill => f32::max( + content_size.width / child_width, + content_size.height / child_height, + ), }; - self.layout_with_scale(size, child, pts, scale) + self.layout_with_scale(content_size, child, pts, scale) } } } fn layout_with_scale( &self, - size: Size, + max_size: Size, // without borders child: &mut StatefulComponent, pts: Duration, scale: f32, ) -> NestedLayout { + let child_width = child.width(pts); + let child_height = child.height(pts); let (content, children, child_nodes_count) = match child { StatefulComponent::Layout(layout_component) => { - let children_layouts = layout_component.layout( + let children_layout = layout_component.layout( Size { - width: size.width / scale, - height: size.height / scale, + width: child_width.unwrap_or(max_size.width / scale), + height: child_height.unwrap_or(max_size.height / scale), }, pts, ); - let child_nodes_count = children_layouts.child_nodes_count; + let child_nodes_count = children_layout.child_nodes_count; ( LayoutContent::None, - vec![children_layouts], + vec![children_layout], child_nodes_count, ) } @@ -71,63 +79,74 @@ impl RescalerComponentParam { VerticalAlign::Top => 0.0, VerticalAlign::Bottom => child .height(pts) - .map(|height| size.height - (height * scale)) + .map(|height| max_size.height - (height * scale)) .unwrap_or(0.0), VerticalAlign::Center | VerticalAlign::Justified => child .height(pts) - .map(|height| (size.height - (height * scale)) / 2.0) + .map(|height| (max_size.height - (height * scale)) / 2.0) .unwrap_or(0.0), }; let left = match self.horizontal_align { HorizontalAlign::Left => 0.0, HorizontalAlign::Right => child .width(pts) - .map(|width| (size.width - (width * scale))) + .map(|width| (max_size.width - (width * scale))) .unwrap_or(0.0), HorizontalAlign::Center | HorizontalAlign::Justified => child .width(pts) - .map(|width| (size.width - (width * scale)) / (2.0)) + .map(|width| (max_size.width - (width * scale)) / (2.0)) .unwrap_or(0.0), }; let width = child .width(pts) .map(|child_width| child_width * scale) - .unwrap_or(size.width); + .unwrap_or(max_size.width); let height = child .height(pts) .map(|child_height| child_height * scale) - .unwrap_or(size.height); + .unwrap_or(max_size.height); NestedLayout { top: 0.0, left: 0.0, - width: size.width, - height: size.height, + width: max_size.width + (self.border_width * 2.0), + height: max_size.height + (self.border_width * 2.0), rotation_degrees: 0.0, scale_x: 1.0, scale_y: 1.0, - crop: Some(Crop { - top: 0.0, - left: 0.0, - width: size.width, - height: size.height, + crop: None, + mask: Some(Mask { + radius: self.border_radius - self.border_width, + top: self.border_width, + left: self.border_width, + width: max_size.width, + height: max_size.height, }), content: LayoutContent::None, children: vec![NestedLayout { - top, - left, + top: top + self.border_width, + left: left + self.border_width, width, height, rotation_degrees: 0.0, scale_x: scale, scale_y: scale, crop: None, + mask: None, content, child_nodes_count, children, + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], }], child_nodes_count, + border_width: self.border_width, + border_color: self.border_color, + border_radius: self.border_radius, + box_shadow: self.box_shadow.clone(), } } } diff --git a/compositor_render/src/scene/tiles_component/layout.rs b/compositor_render/src/scene/tiles_component/layout.rs index d7080be78..adc76c173 100644 --- a/compositor_render/src/scene/tiles_component/layout.rs +++ b/compositor_render/src/scene/tiles_component/layout.rs @@ -1,7 +1,7 @@ use std::time::Duration; use crate::{ - scene::{layout::StatefulLayoutComponent, RGBAColor, Size, StatefulComponent}, + scene::{layout::StatefulLayoutComponent, BorderRadius, RGBAColor, Size, StatefulComponent}, transformations::layout::{LayoutContent, NestedLayout}, }; @@ -29,9 +29,14 @@ pub(super) fn layout_tiles( scale_x: 1.0, scale_y: 1.0, crop: None, + mask: None, content: LayoutContent::Color(background_color), child_nodes_count: children.iter().map(|l| l.child_nodes_count).sum(), children, + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], } } @@ -64,9 +69,14 @@ fn layout_child(child: &mut StatefulComponent, tile: Option, pts: Duration scale_x: 1.0, scale_y: 1.0, crop: None, + mask: None, content: LayoutContent::None, child_nodes_count: children_layouts.child_nodes_count, children: vec![children_layouts], + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], } } _ => { @@ -81,9 +91,14 @@ fn layout_child(child: &mut StatefulComponent, tile: Option, pts: Duration scale_x: 1.0, scale_y: 1.0, crop: None, + mask: None, content: StatefulLayoutComponent::layout_content(child, 0), child_nodes_count: 1, children: vec![], + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], } } } diff --git a/compositor_render/src/scene/types.rs b/compositor_render/src/scene/types.rs index 66ff62f83..e0f243a9f 100644 --- a/compositor_render/src/scene/types.rs +++ b/compositor_render/src/scene/types.rs @@ -1,3 +1,5 @@ +use std::ops::{Add, Div, Mul, Sub}; + mod convert; pub(crate) mod interpolation; @@ -74,3 +76,79 @@ pub enum InterpolationKind { Bounce, CubicBezier { x1: f64, y1: f64, x2: f64, y2: f64 }, } + +#[derive(Debug, Clone, Copy)] +pub struct BorderRadius { + pub top_left: f32, + pub top_right: f32, + pub bottom_right: f32, + pub bottom_left: f32, +} + +impl BorderRadius { + pub const ZERO: BorderRadius = BorderRadius { + top_left: 0.0, + top_right: 0.0, + bottom_right: 0.0, + bottom_left: 0.0, + }; + + pub fn new_with_radius(radius: f32) -> Self { + Self { + top_left: radius, + top_right: radius, + bottom_right: radius, + bottom_left: radius, + } + } +} + +impl Mul for BorderRadius { + type Output = BorderRadius; + + fn mul(self, rhs: f32) -> Self::Output { + Self { + top_left: self.top_left * rhs, + top_right: self.top_right * rhs, + bottom_right: self.bottom_right * rhs, + bottom_left: self.bottom_left * rhs, + } + } +} + +impl Div for BorderRadius { + type Output = BorderRadius; + + fn div(self, rhs: f32) -> Self::Output { + self * (1.0 / rhs) + } +} + +impl Add for BorderRadius { + type Output = BorderRadius; + + fn add(self, rhs: f32) -> Self::Output { + Self { + top_left: f32::max(self.top_left + rhs, 0.0), + top_right: f32::max(self.top_right + rhs, 0.0), + bottom_right: f32::max(self.bottom_right + rhs, 0.0), + bottom_left: f32::max(self.bottom_left + rhs, 0.0), + } + } +} + +impl Sub for BorderRadius { + type Output = BorderRadius; + + fn sub(self, rhs: f32) -> Self::Output { + self + (-rhs) + } +} + +#[derive(Debug, Clone, Copy)] +pub struct BoxShadow { + pub offset_x: f32, + pub offset_y: f32, + pub blur_radius: f32, + pub color: RGBAColor, +} diff --git a/compositor_render/src/scene/view_component.rs b/compositor_render/src/scene/view_component.rs index 885cdd42e..ab133031b 100644 --- a/compositor_render/src/scene/view_component.rs +++ b/compositor_render/src/scene/view_component.rs @@ -8,8 +8,8 @@ use super::{ scene_state::BuildStateTreeCtx, transition::{TransitionOptions, TransitionState}, types::interpolation::ContinuousValue, - Component, ComponentId, IntermediateNode, Overflow, Position, RGBAColor, SceneError, Size, - StatefulComponent, + BorderRadius, BoxShadow, Component, ComponentId, IntermediateNode, Overflow, Position, + RGBAColor, SceneError, Size, StatefulComponent, }; mod interpolation; @@ -32,6 +32,11 @@ struct ViewComponentParam { overflow: Overflow, background_color: RGBAColor, + border_radius: BorderRadius, + border_width: f32, + border_color: RGBAColor, + + box_shadow: Vec, } impl StatefulViewComponent { @@ -51,8 +56,10 @@ impl StatefulViewComponent { self.children.iter_mut().collect() } + /// External position of a component (includes border) pub(super) fn position(&self, pts: Duration) -> Position { - self.view(pts).position + let view = self.view(pts); + view.position.with_border(view.border_width) } pub(super) fn component_id(&self) -> Option<&ComponentId> { @@ -119,6 +126,10 @@ impl ViewComponent { position: self.position, background_color: self.background_color, overflow: self.overflow, + border_radius: self.border_radius, + border_width: self.border_width, + border_color: self.border_color, + box_shadow: self.box_shadow, }, transition, children: self diff --git a/compositor_render/src/scene/view_component/interpolation.rs b/compositor_render/src/scene/view_component/interpolation.rs index b1fb958f6..e5afa293f 100644 --- a/compositor_render/src/scene/view_component/interpolation.rs +++ b/compositor_render/src/scene/view_component/interpolation.rs @@ -10,6 +10,18 @@ impl ContinuousValue for ViewComponentParam { position: ContinuousValue::interpolate(&start.position, &end.position, state), background_color: end.background_color, overflow: end.overflow, + border_radius: ContinuousValue::interpolate( + &start.border_radius, + &end.border_radius, + state, + ), + border_width: ContinuousValue::interpolate( + &start.border_width, + &end.border_width, + state, + ), + border_color: end.border_color, + box_shadow: ContinuousValue::interpolate(&start.box_shadow, &end.box_shadow, state), } } } diff --git a/compositor_render/src/scene/view_component/layout.rs b/compositor_render/src/scene/view_component/layout.rs index 2ace2fbaa..8b356f1a3 100644 --- a/compositor_render/src/scene/view_component/layout.rs +++ b/compositor_render/src/scene/view_component/layout.rs @@ -2,10 +2,10 @@ use std::time::Duration; use crate::{ scene::{ - layout::StatefulLayoutComponent, Overflow, Position, Size, StatefulComponent, - ViewChildrenDirection, + layout::StatefulLayoutComponent, BorderRadius, Overflow, Position, RGBAColor, Size, + StatefulComponent, ViewChildrenDirection, }, - transformations::layout::{Crop, LayoutContent, NestedLayout}, + transformations::layout::{LayoutContent, Mask, NestedLayout}, }; use super::ViewComponentParam; @@ -22,36 +22,52 @@ struct StaticChildLayoutOpts { /// For direction=column defines height of a static component static_child_size: f32, parent_size: Size, + /// border width before rescaling, it is used to calculate top/left offset correctly + /// when `overflow: fit` is set + parent_border_width: f32, } impl ViewComponentParam { pub(super) fn layout( &self, - size: Size, + size: Size, // how much size component has available(includes space for border) children: &mut [StatefulComponent], pts: Duration, ) -> NestedLayout { - let static_child_size = self.static_child_size(size, children, pts); - let (scale, crop) = match self.overflow { - Overflow::Visible => (1.0, None), + let content_size = Size { + width: f32::max(size.width - 2.0 * self.border_width, 0.0), + height: f32::max(size.height - 2.0 * self.border_width, 0.0), + }; + let static_child_size = self.static_child_size(content_size, children, pts); + let (scale, crop, mask) = match self.overflow { + Overflow::Visible => (1.0, None, None), Overflow::Hidden => ( 1.0, - Some(Crop { - top: 0.0, - left: 0.0, - width: size.width, - height: size.height, + None, + Some(Mask { + radius: self.border_radius - self.border_width, + top: self.border_width, + left: self.border_width, + width: content_size.width, + height: content_size.height, }), ), Overflow::Fit => ( - self.scale_factor_for_overflow_fit(size, children, pts), + self.scale_factor_for_overflow_fit(content_size, children, pts), None, + Some(Mask { + radius: self.border_radius - self.border_width, + top: self.border_width, + left: self.border_width, + width: content_size.width, + height: content_size.height, + }), ), }; // offset along x or y direction (depends on self.direction) where next // child component should be placed - let mut static_offset = 0.0; + let mut static_offset = self.border_width / scale; let children: Vec<_> = children .iter_mut() @@ -72,7 +88,8 @@ impl ViewComponentParam { height, static_offset, static_child_size, - parent_size: size, + parent_size: content_size, + parent_border_width: self.border_width / scale, }, pts, ); @@ -97,9 +114,14 @@ impl ViewComponentParam { scale_x: scale, scale_y: scale, crop, + mask, content: LayoutContent::Color(self.background_color), child_nodes_count: children.iter().map(|l| l.child_nodes_count).sum(), children, + border_width: self.border_width, + border_color: self.border_color, + border_radius: self.border_radius, + box_shadow: self.box_shadow.clone(), } } @@ -114,18 +136,18 @@ impl ViewComponentParam { ViewChildrenDirection::Row => { let width = opts.width.unwrap_or(opts.static_child_size); let height = opts.height.unwrap_or(opts.parent_size.height); - let top = 0.0; + let top = opts.parent_border_width; let left = static_offset; static_offset += width; - (top as f32, left, width, height) + (top, left, width, height) } ViewChildrenDirection::Column => { let height = opts.height.unwrap_or(opts.static_child_size); let width = opts.width.unwrap_or(opts.parent_size.width); let top = static_offset; - let left = 0.0; + let left = opts.parent_border_width; static_offset += height; - (top, left as f32, width, height) + (top, left, width, height) } }; let layout = match child { @@ -140,9 +162,14 @@ impl ViewComponentParam { scale_x: 1.0, scale_y: 1.0, crop: None, + mask: None, content: LayoutContent::None, child_nodes_count: children_layouts.child_nodes_count, children: vec![children_layouts], + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], } } _ => NestedLayout { @@ -154,9 +181,14 @@ impl ViewComponentParam { scale_x: 1.0, scale_y: 1.0, crop: None, + mask: None, content: StatefulLayoutComponent::layout_content(child, 0), child_nodes_count: 1, children: vec![], + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], }, }; (layout, static_offset) @@ -165,6 +197,8 @@ impl ViewComponentParam { /// Calculate a size of a static child component that does not have it explicitly defined. /// Returned value represents width if the direction is `ViewChildrenDirection::Row` or /// height if the direction is `ViewChildrenDirection::Column`. + /// + /// size represents dimensions of content (without a border). fn static_child_size(&self, size: Size, children: &[StatefulComponent], pts: Duration) -> f32 { let max_size = match self.direction { super::ViewChildrenDirection::Row => size.width, @@ -190,7 +224,7 @@ impl ViewComponentParam { fn scale_factor_for_overflow_fit( &self, - size: Size, + content_size: Size, children: &[StatefulComponent], pts: Duration, ) -> f32 { @@ -198,8 +232,8 @@ impl ViewComponentParam { .sum_static_children_sizes(children, pts) .max(0.000000001); // avoid division by 0 let (max_size, max_alternative_size) = match self.direction { - super::ViewChildrenDirection::Row => (size.width, size.height), - super::ViewChildrenDirection::Column => (size.height, size.width), + super::ViewChildrenDirection::Row => (content_size.width, content_size.height), + super::ViewChildrenDirection::Column => (content_size.height, content_size.width), }; let max_alternative_size_for_child = Self::static_children_iter(children, pts) .map(|child| match self.direction { diff --git a/compositor_render/src/transformations/layout.rs b/compositor_render/src/transformations/layout.rs index 1f3b2c168..d09904b41 100644 --- a/compositor_render/src/transformations/layout.rs +++ b/compositor_render/src/transformations/layout.rs @@ -1,7 +1,7 @@ use std::{sync::Arc, time::Duration}; use crate::{ - scene::{RGBAColor, Size}, + scene::{BorderRadius, BoxShadow, RGBAColor, Size}, state::RenderCtx, wgpu::texture::NodeTexture, Resolution, @@ -28,6 +28,8 @@ pub(crate) struct LayoutNode { shader: Arc, } +/// When rendering we cut this fragment from texture and stretch it on +/// the expected position #[derive(Debug, Clone)] pub struct Crop { pub top: f32, @@ -37,15 +39,7 @@ pub struct Crop { } #[derive(Debug, Clone)] -pub struct BorderRadius { - pub top_left: f32, - pub top_right: f32, - pub bottom_right: f32, - pub bottom_left: f32, -} - -#[derive(Debug, Clone)] -pub struct ParentMask { +pub struct Mask { pub radius: BorderRadius, // position of parent on the output frame pub top: f32, @@ -56,13 +50,25 @@ pub struct ParentMask { #[derive(Debug, Clone)] struct RenderLayout { + // top-left corner, includes border top: f32, left: f32, + + // size on the output texture, includes border width: f32, height: f32, + + // Defines what should be cut from the content. + // - for texture defines part of the texture that will be stretched to + // the `self.width/self.height`. It might cut off border radius. + // - for box shadow + + // Rotated around the center rotation_degrees: f32, + // border radius needs to applied before cropping, so we can't just make it a part of a parent + // mask border_radius: BorderRadius, - parent_masks: Vec, + masks: Vec, content: RenderLayoutContent, } @@ -75,9 +81,9 @@ enum RenderLayoutContent { }, ChildNode { index: usize, - crop: Crop, border_color: RGBAColor, border_width: f32, + crop: Crop, }, #[allow(dead_code)] BoxShadow { color: RGBAColor, blur_radius: f32 }, @@ -92,19 +98,44 @@ pub enum LayoutContent { #[derive(Debug, Clone)] pub struct NestedLayout { + // top-left corner, includes border of current element + // (0, 0) represents top-left corner of a parent (inner corner if parent has border too) + // + // e.g. if parent layout and current layout have border 10 and current layout is at (0, 0) then + // their top and left edges will be next to each other without overlapping pub top: f32, pub left: f32, + + // size on the output texture, includes border pub width: f32, pub height: f32, + pub rotation_degrees: f32, /// scale will affect content/children, but not the properties of current layout like - /// top/left/widht/height + /// top/left/width/height pub scale_x: f32, pub scale_y: f32, /// Crop is applied before scaling. + /// + /// If you need to scale before cropping use 2 nested layouts: + /// - child to scale + /// - parent to crop + /// + /// Depending on content + /// - For texture it describes what chunk of texture should be cut and stretched on + /// width/height + /// - For layout it cuts of part of it (defined in coordinates system of this component) pub crop: Option, + /// Everything outside this mask should not be rendered. Coordinates are relative to + /// the layouts top-left corner (and not to the 0,0 point that top-left are defined in) + pub mask: Option, pub content: LayoutContent, + pub border_width: f32, + pub border_color: RGBAColor, + pub border_radius: BorderRadius, + pub box_shadow: Vec, + pub(crate) children: Vec, /// Describes how many children of this component are nodes. This value also /// counts `layout` if its content is a `LayoutContent::ChildNode`. @@ -138,10 +169,8 @@ impl LayoutNode { .map(|node_texture| node_texture.resolution()) .collect(); let output_resolution = self.layout_provider.resolution(pts); - let layouts = self - .layout_provider - .layouts(pts, &input_resolutions) - .flatten(&input_resolutions, output_resolution); + let layouts = self.layout_provider.layouts(pts, &input_resolutions); + let layouts = layouts.flatten(&input_resolutions, output_resolution); let textures: Vec> = layouts .iter() @@ -178,9 +207,14 @@ impl NestedLayout { scale_x: 1.0, scale_y: 1.0, crop: None, + mask: None, content: LayoutContent::None, children: vec![], child_nodes_count, + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + border_radius: BorderRadius::ZERO, + box_shadow: vec![], } } } diff --git a/compositor_render/src/transformations/layout/apply_layouts.wgsl b/compositor_render/src/transformations/layout/apply_layouts.wgsl index deeb135b8..8fb19918a 100644 --- a/compositor_render/src/transformations/layout/apply_layouts.wgsl +++ b/compositor_render/src/transformations/layout/apply_layouts.wgsl @@ -11,7 +11,7 @@ struct VertexOutput { // texture coordinates in texture coordiantes [0, 0] (top-left) X [1, 1] (bottom-right) @location(0) tex_coords: vec2, // Position relative to center of the rectangle in [-rect_width/2, rect_width/2] X [-rect_height/2, height/2] - @location(2) center_position: vec2 + @location(2) center_position: vec2, } struct BoxShadowParams { @@ -58,7 +58,7 @@ struct ColorParams { border_width: f32, } -struct ParentBorderRadius { +struct ParentMask { radius: vec4, top: f32, left: f32, @@ -70,7 +70,7 @@ struct LayoutInfo { // 0 -> Texture, 1 -> Color, 2 -> BoxShadow layout_type: u32, index: u32, - parent_masks_len: u32 + masks_len: u32 } @@ -81,7 +81,7 @@ struct LayoutInfo { @group(1) @binding(2) var color_params: array; @group(1) @binding(3) var box_shadow_params: array; -@group(2) @binding(0) var parent_masks: array; +@group(2) @binding(0) var masks: array; @group(3) @binding(0) var sampler_: sampler; @@ -186,6 +186,7 @@ fn vs_main(input: VertexInput) -> VertexOutput { texture_params[layout_info.index].crop_width, texture_params[layout_info.index].crop_height ); + output.position = vertices_transformation * vec4(input.position, 1.0); output.tex_coords = (texture_transformation * vec4(input.tex_coords, 0.0, 1.0)).xy; let rect_size = vec2(texture_params[layout_info.index].width, texture_params[layout_info.index].height); @@ -230,6 +231,8 @@ fn vs_main(input: VertexInput) -> VertexOutput { // Signed distance function for rounded rectangle https://iquilezles.org/articles/distfunctions // adapted from https://www.shadertoy.com/view/4llXD7 +// Distance from outside is positive and inside it is negative +// // dist - signed distance from the center of the rectangle in pixels // size - size of the rectangle in pixels // radius - radius of the corners in pixels [top-left, top-right, bottom-right, bottom-left] @@ -240,8 +243,8 @@ fn roundedRectSDF(dist: vec2, size: vec2, radius: vec4, rotation: // wierd hack to get the radius of the nearest corner stored in r.x var r: vec2 = vec2(0.0, 0.0); - r = select(radius.yz, radius.xw, dist.x < 0.0 ); - r.x = select(r.y, r.x, dist.y < 0.0 ); + r = select(radius.yz, radius.xw, dist.x < 0.0); + r.x = select(r.x, r.y, dist.y < 0.0); let q = abs(dist) - half_size + r.x; return min(max(q.x, q.y), 0.0) + length(max(q, vec2(0.0, 0.0))) - r.x; @@ -249,9 +252,26 @@ fn roundedRectSDF(dist: vec2, size: vec2, radius: vec4, rotation: @fragment fn fs_main(input: VertexOutput) -> @location(0) vec4 { - let transparent = vec4(0.0, 0.0, 0.0, 0.0); - // TODO: Add parent mask handling - let parent_mask_alpha = 1.0; + let transparent = vec4(1.0, 1.0, 1.0, 0.0); + + var mask_alpha = 1.0; + + for (var i = 0; i < i32(layout_info.masks_len); i++) { + let radius = masks[i].radius; + let top = masks[i].top; + let left = masks[i].left; + let width = masks[i].width; + let height = masks[i].height; + let size = vec2(width, height); + + let distance = roundedRectSDF( + vec2(left, top) + (size / 2.0) - input.position.xy, + size, + radius, + 0.0, + ); + mask_alpha = mask_alpha * smoothstep(-0.5, 0.5 , -distance); + } switch layout_info.layout_type { case 0u: { @@ -265,19 +285,30 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { let border_color = texture_params[layout_info.index].border_color; let size = vec2(width, height); - let edge_distance = roundedRectSDF( + let edge_distance = -roundedRectSDF( input.center_position, size, border_radius, rotation_degrees ); - let smoothed_alpha = 1.0 - smoothstep(0.0, 2.0, edge_distance); - let border_alpha = 1.0 - smoothstep(-border_width + 1.0, -border_width, edge_distance); - - let mixed_background = mix(transparent, sample, min(smoothed_alpha, parent_mask_alpha)); - let mixed_border = mix(mixed_background, border_color, min(border_alpha, smoothed_alpha)); - return mixed_border; + if (border_width < 1.0) { + let content_alpha = smoothstep(-0.5, 0.5, edge_distance); + return vec4(sample.rgb, sample.a * content_alpha * mask_alpha); + } else if (mask_alpha < 0.01) { + return vec4(0, 0, 0, 0); + } else { + if (edge_distance > border_width / 2.0) { + // border <-> content + let border_alpha = smoothstep(border_width - 0.5, border_width + 0.5, edge_distance); + let border_or_content = mix(border_color, sample, border_alpha); + return vec4(border_or_content.rgb, border_or_content.a * mask_alpha); + } else { + // border <-> outside + let content_alpha = smoothstep(-0.5, 0.5, edge_distance); + return vec4(border_color.rgb, border_color.a * content_alpha * mask_alpha); + } + } } case 1u: { let color = color_params[layout_info.index].color; @@ -290,19 +321,28 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { let border_color = color_params[layout_info.index].border_color; let size = vec2(width, height); - let edge_distance = roundedRectSDF( + let edge_distance = -roundedRectSDF( input.center_position, size, border_radius, rotation_degrees ); - let smoothed_alpha = 1.0 - smoothstep(0.0, 2.0, edge_distance); - let border_alpha = 1.0 - smoothstep(-border_width + 1.0, -border_width, edge_distance); - - let mixed_background = mix(transparent, color, min(smoothed_alpha, parent_mask_alpha)); - let mixed_border = mix(mixed_background, border_color, border_alpha); - return mixed_border; + if (border_width < 1.0) { + let content_alpha = smoothstep(-0.5, 0.5, edge_distance); + return vec4(color.rgb, color.a * content_alpha * mask_alpha); + } else { + if (edge_distance > border_width / 2.0) { + // border <-> content + let border_alpha = smoothstep(border_width, border_width + 1.0, edge_distance); + let border_or_content = mix(border_color, color, border_alpha); + return vec4(border_or_content.rgb, border_or_content.a * mask_alpha); + } else { + // border <-> outside + let content_alpha = smoothstep(-0.5, 0.5, edge_distance); + return vec4(border_color.rgb, border_color.a * content_alpha * mask_alpha); + } + } } case 2u: { let color = box_shadow_params[layout_info.index].color; @@ -314,16 +354,16 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { let blur_radius = box_shadow_params[layout_info.index].blur_radius; let size = vec2(width, height); - let edge_distance = roundedRectSDF( + let edge_distance = -roundedRectSDF( input.center_position, size, border_radius, rotation_degrees ); + + let blur_alpha = smoothstep(0.0, blur_radius, edge_distance) * mask_alpha; - let smoothed_alpha = 1.0 - smoothstep(0.0, blur_radius, edge_distance); - let mixed_background = mix(transparent, color, min(smoothed_alpha, parent_mask_alpha)); - return mixed_background; + return vec4(color.rgb, color.a * blur_alpha); } default { return vec4(0.0, 0.0, 0.0, 0.0); diff --git a/compositor_render/src/transformations/layout/flatten.rs b/compositor_render/src/transformations/layout/flatten.rs index 7d03fef91..fe4215ab4 100644 --- a/compositor_render/src/transformations/layout/flatten.rs +++ b/compositor_render/src/transformations/layout/flatten.rs @@ -1,6 +1,10 @@ +use std::{iter, mem}; + use crate::{scene::RGBAColor, Resolution}; -use super::{Crop, LayoutContent, NestedLayout, RenderLayout, RenderLayoutContent}; +use super::{ + BoxShadow, Crop, LayoutContent, Mask, NestedLayout, RenderLayout, RenderLayoutContent, +}; impl NestedLayout { pub(super) fn flatten( @@ -8,14 +12,20 @@ impl NestedLayout { input_resolutions: &[Option], resolution: Resolution, ) -> Vec { - let layouts = self.inner_flatten(0); - layouts + let (shadow, layouts) = self.inner_flatten(0, vec![]); + shadow .into_iter() + .chain(layouts) .filter(|layout| Self::should_render(layout, input_resolutions, resolution)) + .map(NestedLayout::fix_final_render_layout) .collect() } - fn inner_flatten(mut self, child_index_offset: usize) -> Vec { + fn inner_flatten( + mut self, + child_index_offset: usize, + parent_masks: Vec, + ) -> (Vec, Vec) { let mut child_index_offset = child_index_offset; if let LayoutContent::ChildNode { index, size } = self.content { self.content = LayoutContent::ChildNode { @@ -24,20 +34,90 @@ impl NestedLayout { }; child_index_offset += 1 } - let layout = self.render_layout(); - let children: Vec<_> = std::mem::take(&mut self.children) + let layout = self.render_layout(&parent_masks); + // It is separated because box shadows of all siblings need to be rendered before + // this layout and it's siblings + let box_shadow_layouts = self + .box_shadow + .iter() + .map(|shadow| self.box_shadow_layout(shadow, &parent_masks)) + .collect(); + + let parent_masks = match &self.mask { + Some(mask) => parent_masks + .iter() + .chain(iter::once(mask)) + .cloned() + .collect(), + None => parent_masks.clone(), + }; + let parent_masks = self.child_parent_masks(&parent_masks); + + let (children_shadow, children_layouts): (Vec<_>, Vec<_>) = + std::mem::take(&mut self.children) + .into_iter() + .map(|child| { + let child_nodes_count = child.child_nodes_count; + let (shadows, layouts) = + child.inner_flatten(child_index_offset, parent_masks.clone()); + child_index_offset += child_nodes_count; + (shadows, layouts) + }) + .unzip(); + let children_shadow = children_shadow .into_iter() - .flat_map(|child| { - let child_nodes_count = child.child_nodes_count; - let layouts = child.inner_flatten(child_index_offset); - child_index_offset += child_nodes_count; - layouts - }) + .flatten() + .map(|l| self.flatten_child(l)) + .collect(); + let children_layouts = children_layouts + .into_iter() + .flatten() .map(|l| self.flatten_child(l)) .collect(); - [vec![layout], children].concat() + + ( + box_shadow_layouts, + [vec![layout], children_shadow, children_layouts].concat(), + ) } + // Final pass on each render layout, it applies following modifications: + // - If border_width is between 0 and 1 set it to 1. + // - Remove masks that don't do anything + fn fix_final_render_layout(mut layout: RenderLayout) -> RenderLayout { + fn filter_mask(layout: &RenderLayout, mask: Mask) -> Option { + let max_top_border = f32::max(mask.radius.top_left, mask.radius.top_right); + let max_bottom_border = f32::max(mask.radius.bottom_left, mask.radius.bottom_right); + let max_left_border = f32::max(mask.radius.top_left, mask.radius.bottom_left); + let max_right_border = f32::max(mask.radius.top_right, mask.radius.bottom_right); + let should_skip = mask.top + max_top_border <= layout.top + && mask.left + max_left_border <= layout.left + && mask.left + mask.width - max_right_border >= layout.left + layout.width + && mask.top + mask.height - max_bottom_border >= layout.top + layout.height; + match should_skip { + true => None, + false => Some(mask), + } + } + match &mut layout.content { + RenderLayoutContent::Color { border_width, .. } + | RenderLayoutContent::ChildNode { border_width, .. } => { + if *border_width < 1.0 { + *border_width = 0.0 + } + } + _ => (), + }; + layout.masks = mem::take(&mut layout.masks) + .into_iter() + .filter_map(|mask| filter_mask(&layout, mask)) + .collect(); + layout + } + + // Decides if layout will affect the output of the stream, if not this layout will not be + // passed to the shader. + // Layouts are in absolute units at this point. fn should_render( layout: &RenderLayout, input_resolutions: &[Option], @@ -53,10 +133,17 @@ impl NestedLayout { match &layout.content { RenderLayoutContent::Color { color: RGBAColor(_, _, _, 0), - .. - } => false, + border_color: RGBAColor(_, _, _, border_alpha), + border_width, + } => *border_alpha != 0 || *border_width > 0.0, RenderLayoutContent::Color { .. } => true, - RenderLayoutContent::ChildNode { crop, index, .. } => { + RenderLayoutContent::ChildNode { + crop, + index, + border_color: RGBAColor(_, _, _, _), + border_width: _, + } => { + // TODO: handle a case when only border is visible (currently impossible) let size = input_resolutions.get(*index).copied().flatten(); if let Some(size) = size { if crop.left > size.width as f32 || crop.top > size.height as f32 { @@ -68,28 +155,59 @@ impl NestedLayout { } true } - - #[allow(clippy::todo)] - RenderLayoutContent::BoxShadow { .. } => todo!(), + RenderLayoutContent::BoxShadow { + color: RGBAColor(_, _, _, 0), + .. + } => false, + RenderLayoutContent::BoxShadow { .. } => true, } } - fn flatten_child(&self, layout: RenderLayout) -> RenderLayout { + // parent_masks - in self coordinates + fn flatten_child(&self, child: RenderLayout) -> RenderLayout { + // scale factor used if we need to scale something that can't be + // scaled separately for horizontal and vertical direction. + let unified_scale = f32::min(self.scale_x, self.scale_y); + match &self.crop { None => RenderLayout { - top: self.top + (layout.top * self.scale_y), - left: self.left + (layout.left * self.scale_x), - width: layout.width * self.scale_x, - height: layout.height * self.scale_y, - rotation_degrees: layout.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct - content: layout.content, - border_radius: super::BorderRadius { - top_left: 0.0, - top_right: 0.0, - bottom_right: 0.0, - bottom_left: 0.0, + top: self.top + (child.top * self.scale_y), + left: self.left + (child.left * self.scale_x), + width: child.width * self.scale_x, + height: child.height * self.scale_y, + rotation_degrees: child.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct + content: match child.content { + RenderLayoutContent::Color { + color, + border_color, + border_width, + } => RenderLayoutContent::Color { + color, + border_color, + border_width: border_width * unified_scale, + }, + RenderLayoutContent::ChildNode { + index, + border_color, + border_width, + crop, + } => RenderLayoutContent::ChildNode { + index, + border_color, + border_width: border_width * unified_scale, + crop, + }, + RenderLayoutContent::BoxShadow { color, blur_radius } => { + RenderLayoutContent::BoxShadow { + color, + blur_radius: blur_radius * unified_scale, + } + } }, - parent_masks: Vec::new(), + // TODO: This will not work correctly for layouts that are not proportionally + // scaled + border_radius: child.border_radius * unified_scale, + masks: self.parent_parent_masks(&child.masks), }, Some(crop) => { // Below values are only correct if `crop` is in the same coordinate @@ -99,13 +217,13 @@ impl NestedLayout { // Value in coordinates of `self` (relative to it's top-left corner). Represents // a position after cropping and translated back to (layout.top, layout.left). - let cropped_top = f32::max(layout.top - crop.top, 0.0); - let cropped_left = f32::max(layout.left - crop.left, 0.0); - let cropped_bottom = f32::min(layout.top + layout.height - crop.top, crop.height); - let cropped_right = f32::min(layout.left + layout.width - crop.left, crop.width); + let cropped_top = f32::max(child.top - crop.top, 0.0); + let cropped_left = f32::max(child.left - crop.left, 0.0); + let cropped_bottom = f32::min(child.top + child.height - crop.top, crop.height); + let cropped_right = f32::min(child.left + child.width - crop.left, crop.width); let cropped_width = cropped_right - cropped_left; let cropped_height = cropped_bottom - cropped_top; - match layout.content { + match child.content.clone() { RenderLayoutContent::Color { color, border_color, @@ -116,19 +234,14 @@ impl NestedLayout { left: self.left + (cropped_left * self.scale_x), width: cropped_width * self.scale_x, height: cropped_height * self.scale_y, - rotation_degrees: layout.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct + rotation_degrees: child.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct content: RenderLayoutContent::Color { color, border_color, - border_width, + border_width: border_width * unified_scale, }, - border_radius: super::BorderRadius { - top_left: 0.0, - top_right: 0.0, - bottom_right: 0.0, - bottom_left: 0.0, - }, - parent_masks: Vec::new(), + border_radius: child.border_radius * unified_scale, + masks: self.parent_parent_masks(&child.masks), } } RenderLayoutContent::ChildNode { @@ -140,13 +253,13 @@ impl NestedLayout { // Calculate how much top/left coordinates changed when cropping. It represents // how much was removed in layout coordinates. Ignore the change of a position that // was a result of a translation after cropping. - let top_diff = f32::max(crop.top - layout.top, 0.0); - let left_diff = f32::max(crop.left - layout.left, 0.0); + let top_diff = f32::max(crop.top - child.top, 0.0); + let left_diff = f32::max(crop.left - child.left, 0.0); // Factor to translate from `layout` coordinates to child node coord. // The same factor holds for translations from `self.layout`. - let horizontal_scale_factor = child_crop.width / layout.width; - let vertical_scale_factor = child_crop.height / layout.height; + let horizontal_scale_factor = child_crop.width / child.width; + let vertical_scale_factor = child_crop.height / child.height; let crop = Crop { top: child_crop.top + (top_diff * vertical_scale_factor), @@ -160,30 +273,42 @@ impl NestedLayout { left: self.left + (cropped_left * self.scale_x), width: cropped_width * self.scale_x, height: cropped_height * self.scale_y, - rotation_degrees: layout.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct + rotation_degrees: child.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct content: RenderLayoutContent::ChildNode { index, crop, border_color, border_width, }, - border_radius: super::BorderRadius { - top_left: 0.0, - top_right: 0.0, - bottom_right: 0.0, - bottom_left: 0.0, + border_radius: child.border_radius * unified_scale, + masks: self.parent_parent_masks(&child.masks), + } + } + RenderLayoutContent::BoxShadow { color, blur_radius } => { + RenderLayout { + top: self.top + (cropped_top * self.scale_y), + left: self.left + (cropped_left * self.scale_x), + width: cropped_width * self.scale_x, + height: cropped_height * self.scale_y, + rotation_degrees: child.rotation_degrees + self.rotation_degrees, // TODO: not exactly correct + content: RenderLayoutContent::BoxShadow { + color, + blur_radius: blur_radius * unified_scale, }, - parent_masks: Vec::new(), + border_radius: child.border_radius * unified_scale, + masks: self.parent_parent_masks(&child.masks), } } - #[allow(clippy::todo)] - RenderLayoutContent::BoxShadow { .. } => todo!(), } } } } - fn render_layout(&self) -> RenderLayout { + /// Calculate RenderLayout for self (without children) + /// Resulting layout is in coordinates: + /// - relative self's parent top-left corner. + /// - before parent scaling is applied + fn render_layout(&self, parent_masks: &[Mask]) -> RenderLayout { RenderLayout { top: self.top, left: self.left, @@ -193,8 +318,8 @@ impl NestedLayout { content: match self.content { LayoutContent::Color(color) => RenderLayoutContent::Color { color, - border_color: RGBAColor(0, 0, 0, 0), - border_width: 0.0, + border_color: self.border_color, + border_width: self.border_width, }, LayoutContent::ChildNode { index, size } => RenderLayoutContent::ChildNode { index, @@ -204,22 +329,63 @@ impl NestedLayout { width: size.width, height: size.height, }, - border_color: RGBAColor(0, 0, 0, 0), - border_width: 0.0, + border_color: self.border_color, + border_width: self.border_width, }, LayoutContent::None => RenderLayoutContent::Color { color: RGBAColor(0, 0, 0, 0), - border_color: RGBAColor(0, 0, 0, 0), - border_width: 0.0, + border_color: self.border_color, + border_width: self.border_width, }, }, - border_radius: super::BorderRadius { - top_left: 0.0, - top_right: 0.0, - bottom_right: 0.0, - bottom_left: 0.0, + border_radius: self.border_radius, + masks: parent_masks.to_vec(), + } + } + + /// calculate RenderLayout for one of self box shadows + fn box_shadow_layout(&self, box_shadow: &BoxShadow, parent_masks: &[Mask]) -> RenderLayout { + RenderLayout { + top: self.top + box_shadow.offset_y - 0.5 * box_shadow.blur_radius, + left: self.left + box_shadow.offset_x - 0.5 * box_shadow.blur_radius, + width: self.width + box_shadow.blur_radius, + height: self.height + box_shadow.blur_radius, + rotation_degrees: self.rotation_degrees, // TODO: this is incorrect + border_radius: self.border_radius + box_shadow.blur_radius, + content: RenderLayoutContent::BoxShadow { + color: box_shadow.color, + blur_radius: box_shadow.blur_radius * 2.0, // TODO: 2.0 is empirically selected + // value }, - parent_masks: Vec::new(), + masks: parent_masks.to_vec(), } } + + /// Calculate ParentMasks in coordinates of child NestedLayout. + fn child_parent_masks(&self, masks: &[Mask]) -> Vec { + masks + .iter() + .map(|mask| Mask { + radius: mask.radius / f32::min(self.scale_x, self.scale_y), + top: (mask.top - self.top) / self.scale_y, + left: (mask.left - self.left) / self.scale_x, + width: mask.width / self.scale_x, + height: mask.height / self.scale_y, + }) + .collect() + } + + /// Translates parent mask from child coordinates to parent. Reverse operation to `child_parent_masks`. + fn parent_parent_masks(&self, masks: &[Mask]) -> Vec { + masks + .iter() + .map(|mask| Mask { + radius: mask.radius * f32::min(self.scale_x, self.scale_y), + top: (mask.top * self.scale_y) + self.top, + left: (mask.left * self.scale_x) + self.left, + width: mask.width * self.scale_x, + height: mask.height * self.scale_y, + }) + .collect() + } } diff --git a/compositor_render/src/transformations/layout/params.rs b/compositor_render/src/transformations/layout/params.rs index 1acad221a..18f04ddd1 100644 --- a/compositor_render/src/transformations/layout/params.rs +++ b/compositor_render/src/transformations/layout/params.rs @@ -8,7 +8,7 @@ use crate::{scene::RGBAColor, wgpu::WgpuCtx, Resolution}; use super::{BorderRadius, RenderLayout}; -const MAX_PARENT_BORDER_RADISUES: usize = 20; +const MAX_MASKS: usize = 20; const MAX_LAYOUTS_COUNT: usize = 100; const TEXTURE_PARAMS_BUFFER_SIZE: usize = MAX_LAYOUTS_COUNT * 80; const COLOR_PARAMS_SIZE: usize = MAX_LAYOUTS_COUNT * 80; @@ -18,7 +18,7 @@ const BOX_SHADOW_PARAMS_SIZE: usize = MAX_LAYOUTS_COUNT * 80; pub struct LayoutInfo { pub layout_type: u32, pub index: u32, - pub parent_border_radiuses_len: u32, + pub masks_len: u32, } impl LayoutInfo { @@ -26,7 +26,7 @@ impl LayoutInfo { let mut result = [0u8; 16]; result[0..4].copy_from_slice(&self.layout_type.to_le_bytes()); result[4..8].copy_from_slice(&self.index.to_le_bytes()); - result[8..12].copy_from_slice(&self.parent_border_radiuses_len.to_le_bytes()); + result[8..12].copy_from_slice(&self.masks_len.to_le_bytes()); result } } @@ -201,10 +201,10 @@ impl ParamsBindGroups { height, rotation_degrees, border_radius, - parent_masks: parent_border_radiuses, + masks, content, } = layout; - let border_radius_bytes = borders_radius_to_bytes(border_radius.clone()); + let border_radius_bytes = borders_radius_to_bytes(*border_radius); match content { super::RenderLayoutContent::Color { @@ -215,7 +215,7 @@ impl ParamsBindGroups { let layout_info = LayoutInfo { layout_type: 1, index: color_params.len() as u32, - parent_border_radiuses_len: parent_border_radiuses.len() as u32, + masks_len: masks.len() as u32, }; let mut color_params_bytes = [0u8; 80]; color_params_bytes[0..16].copy_from_slice(&border_radius_bytes); @@ -239,7 +239,7 @@ impl ParamsBindGroups { let layout_info = LayoutInfo { layout_type: 0, index: texture_params.len() as u32, - parent_border_radiuses_len: parent_border_radiuses.len() as u32, + masks_len: masks.len() as u32, }; let mut texture_params_bytes = [0u8; 80]; texture_params_bytes[0..16].copy_from_slice(&border_radius_bytes); @@ -261,7 +261,7 @@ impl ParamsBindGroups { let layout_info = LayoutInfo { layout_type: 2, index: box_shadow_params.len() as u32, - parent_border_radiuses_len: parent_border_radiuses.len() as u32, + masks_len: masks.len() as u32, }; let mut box_shadow_params_bytes = [0u8; 64]; box_shadow_params_bytes[0..16].copy_from_slice(&border_radius_bytes); @@ -277,49 +277,39 @@ impl ParamsBindGroups { layout_infos.push(layout_info); } } - if parent_border_radiuses.len() > MAX_PARENT_BORDER_RADISUES { + if masks.len() > MAX_MASKS { error!( - "Max parent border radiuses count ({}) exceeded ({}). Slkipping rendering some og them.", - MAX_PARENT_BORDER_RADISUES, - parent_border_radiuses.len() + "Max parent border radiuses count ({}) exceeded ({}). Skipping rendering some og them.", + MAX_MASKS, + masks.len() ); } - let mut parent_border_radiuses_bytes = Vec::new(); + let mut masks_bytes = Vec::new(); - for parent_border_radius in parent_border_radiuses.iter().take(20) { - let mut parent_border_radius_bytes = [0u8; 32]; - parent_border_radius_bytes[0..16].copy_from_slice(&borders_radius_to_bytes( - parent_border_radius.radius.clone(), - )); - parent_border_radius_bytes[16..20] - .copy_from_slice(&parent_border_radius.top.to_le_bytes()); - parent_border_radius_bytes[20..24] - .copy_from_slice(&parent_border_radius.left.to_le_bytes()); - parent_border_radius_bytes[24..28] - .copy_from_slice(&parent_border_radius.width.to_le_bytes()); - parent_border_radius_bytes[28..32] - .copy_from_slice(&parent_border_radius.height.to_le_bytes()); + for mask in masks.iter().take(20) { + let mut mask_bytes = [0u8; 32]; + mask_bytes[0..16].copy_from_slice(&borders_radius_to_bytes(mask.radius)); + mask_bytes[16..20].copy_from_slice(&mask.top.to_le_bytes()); + mask_bytes[20..24].copy_from_slice(&mask.left.to_le_bytes()); + mask_bytes[24..28].copy_from_slice(&mask.width.to_le_bytes()); + mask_bytes[28..32].copy_from_slice(&mask.height.to_le_bytes()); - parent_border_radiuses_bytes.push(parent_border_radius_bytes); + masks_bytes.push(mask_bytes); } - parent_border_radiuses_bytes.resize_with(20, || [0u8; 32]); + masks_bytes.resize_with(20, || [0u8; 32]); match self.bind_groups_2.get(index) { Some((_bg, buffer)) => { - ctx.queue - .write_buffer(buffer, 0, &parent_border_radiuses_bytes.concat()); + ctx.queue.write_buffer(buffer, 0, &masks_bytes.concat()); } None => { error!("Not enought parent border radiuses bind groups preallocated"); } } - ctx.queue.write_buffer( - &self.bind_groups_2[index].1, - 0, - &parent_border_radiuses_bytes.concat(), - ); + ctx.queue + .write_buffer(&self.bind_groups_2[index].1, 0, &masks_bytes.concat()); } texture_params.resize_with(100, || [0u8; 80]); color_params.resize_with(100, || [0u8; 80]); @@ -358,7 +348,6 @@ fn borders_radius_to_bytes(border_radius: BorderRadius) -> [u8; 16] { fn color_to_bytes(color: RGBAColor) -> [u8; 16] { let RGBAColor(r, g, b, a) = color; - let mut result = [0u8; 16]; result[0..4].copy_from_slice(&srgb_to_linear(r).to_le_bytes()); result[4..8].copy_from_slice(&srgb_to_linear(g).to_le_bytes()); diff --git a/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.wgsl b/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.wgsl index 232e0ccc3..55dc34de0 100644 --- a/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.wgsl +++ b/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.wgsl @@ -21,6 +21,14 @@ fn vs_main(input: VertexInput) -> VertexOutput { @group(0) @binding(0) var texture: texture_2d; @group(1) @binding(0) var sampler_: sampler; +fn srgb_to_linear(srgb: vec3) -> vec3 { + let cutoff = step(srgb, vec3(0.04045)); + let higher = pow((srgb + vec3(0.055))/vec3(1.055), vec3(2.4)); + let lower = srgb/vec3(12.92); + + return mix(higher, lower, cutoff); +} + @fragment fn fs_main(input: VertexOutput) -> @location(0) vec4 { var dimensions = textureDimensions(texture); @@ -48,5 +56,6 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { let g = y - 0.34414 * (u - 128.0 / 255.0) - 0.71414 * (v - 128.0 / 255.0); let b = y + 1.77200 * (u - 128.0 / 255.0); - return vec4(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0), 1.0); + let srgb = vec3(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0)); + return vec4(srgb_to_linear(srgb), 1.0); } diff --git a/compositor_render/src/wgpu/format/nv12_to_rgba.wgsl b/compositor_render/src/wgpu/format/nv12_to_rgba.wgsl index 17173d020..5883784b0 100644 --- a/compositor_render/src/wgpu/format/nv12_to_rgba.wgsl +++ b/compositor_render/src/wgpu/format/nv12_to_rgba.wgsl @@ -23,6 +23,14 @@ fn vs_main(input: VertexInput) -> VertexOutput { @group(1) @binding(0) var sampler_: sampler; +fn srgb_to_linear(srgb: vec3) -> vec3 { + let cutoff = step(srgb, vec3(0.04045)); + let higher = pow((srgb + vec3(0.055))/vec3(1.055), vec3(2.4)); + let lower = srgb/vec3(12.92); + + return mix(higher, lower, cutoff); +} + @fragment fn fs_main(input: VertexOutput) -> @location(0) vec4 { var y = textureSample(y_texture, sampler_, input.tex_coords).x; @@ -34,5 +42,6 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { let g = y - 0.34414 * (u - 128.0 / 255.0) - 0.71414 * (v - 128.0 / 255.0); let b = y + 1.77200 * (u - 128.0 / 255.0); - return vec4(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0), 1.0); + let srgb = vec3(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0)); + return vec4(srgb_to_linear(srgb), 1.0); } diff --git a/integration_tests/examples/raw_channel_output.rs b/integration_tests/examples/raw_channel_output.rs index a22c655a8..a82a2dad2 100644 --- a/integration_tests/examples/raw_channel_output.rs +++ b/integration_tests/examples/raw_channel_output.rs @@ -68,8 +68,8 @@ fn main() { download_root: config.download_root, output_sample_rate: config.output_sample_rate, wgpu_features: config.required_wgpu_features, - wgpu_ctx: Some((wgpu_device.clone(), wgpu_queue.clone())), load_system_fonts: Some(true), + wgpu_ctx: Some((wgpu_device.clone(), wgpu_queue.clone())), }) .unwrap_or_else(|err| { panic!( diff --git a/integration_tests/examples/rescaler_border_transition.rs b/integration_tests/examples/rescaler_border_transition.rs new file mode 100644 index 000000000..5e38a5b2e --- /dev/null +++ b/integration_tests/examples/rescaler_border_transition.rs @@ -0,0 +1,154 @@ +use anyhow::Result; +use compositor_api::types::Resolution; +use serde_json::json; +use std::{ + thread::{self}, + time::Duration, +}; + +use integration_tests::{ + examples::{self, run_example, TestSample}, + ffmpeg::{start_ffmpeg_receive, start_ffmpeg_send}, +}; + +const VIDEO_RESOLUTION: Resolution = Resolution { + width: 1280, + height: 720, +}; + +const IP: &str = "127.0.0.1"; +const INPUT_PORT: u16 = 8002; +const OUTPUT_PORT: u16 = 8004; + +fn main() { + run_example(client_code); +} + +fn client_code() -> Result<()> { + start_ffmpeg_receive(Some(OUTPUT_PORT), None)?; + + examples::post( + "input/input_1/register", + &json!({ + "type": "rtp_stream", + "port": INPUT_PORT, + "video": { + "decoder": "ffmpeg_h264" + } + }), + )?; + + examples::post( + "image/example_image/register", + &json!({ + "asset_type": "gif", + "url": "https://gifdb.com/images/high/rust-logo-on-fire-o41c0v9om8drr8dv.gif", + }), + )?; + + let scene1 = json!({ + "type": "view", + "background_color_rgba": "#42daf5ff", + "children": [ + { + "type": "rescaler", + "id": "resized", + "width": VIDEO_RESOLUTION.width, + "height": VIDEO_RESOLUTION.height, + "top": 0.0, + "right": 0.0, + "mode": "fill", + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_y": 40, + "offset_x": 0, + "blur_radius": 40, + "color_rgba": "#00000088", + } + ], + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + ] + }); + + let scene2 = json!({ + "type": "view", + "background_color_rgba": "#42daf5ff", + "children": [ + { + "type": "rescaler", + "id": "resized", + "width": 300, + "height": 300, + "top": (VIDEO_RESOLUTION.height as f32 - 330.0) / 2.0 , + "right": (VIDEO_RESOLUTION.width as f32 - 330.0) / 2.0, + "mode": "fill", + "border_radius": 50, + "border_width": 15, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_y": 40, + "offset_x": 0, + "blur_radius": 40, + "color_rgba": "#00000088", + } + ], + "transition": { + "duration_ms": 1500, + "easing_function": { + "function_name": "cubic_bezier", + "points": [0.33, 1, 0.68, 1] + } + }, + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + ] + }); + + examples::post( + "output/output_1/register", + &json!({ + "type": "rtp_stream", + "ip": IP, + "port": OUTPUT_PORT, + "video": { + "resolution": { + "width": VIDEO_RESOLUTION.width, + "height": VIDEO_RESOLUTION.height, + }, + "encoder": { + "type": "ffmpeg_h264", + "preset": "ultrafast" + }, + "initial": { + "root": scene1 + } + } + }), + )?; + + examples::post("start", &json!({}))?; + + start_ffmpeg_send(IP, Some(INPUT_PORT), None, TestSample::TestPattern)?; + + thread::sleep(Duration::from_secs(5)); + + examples::post( + "output/output_1/update", + &json!({ + "video": { + "root": scene2, + } + }), + )?; + + Ok(()) +} diff --git a/integration_tests/examples/view_border_transition.rs b/integration_tests/examples/view_border_transition.rs new file mode 100644 index 000000000..72ed6f2fd --- /dev/null +++ b/integration_tests/examples/view_border_transition.rs @@ -0,0 +1,166 @@ +use anyhow::Result; +use compositor_api::types::Resolution; +use serde_json::json; +use std::{ + thread::{self}, + time::Duration, +}; + +use integration_tests::{ + examples::{self, run_example, TestSample}, + ffmpeg::{start_ffmpeg_receive, start_ffmpeg_send}, +}; + +const VIDEO_RESOLUTION: Resolution = Resolution { + width: 1280, + height: 720, +}; + +const IP: &str = "127.0.0.1"; +const INPUT_PORT: u16 = 8002; +const OUTPUT_PORT: u16 = 8004; + +fn main() { + run_example(client_code); +} + +fn client_code() -> Result<()> { + start_ffmpeg_receive(Some(OUTPUT_PORT), None)?; + + examples::post( + "input/input_1/register", + &json!({ + "type": "rtp_stream", + "port": INPUT_PORT, + "video": { + "decoder": "ffmpeg_h264" + } + }), + )?; + + examples::post( + "image/example_image/register", + &json!({ + "asset_type": "gif", + "url": "https://gifdb.com/images/high/rust-logo-on-fire-o41c0v9om8drr8dv.gif", + }), + )?; + + let scene1 = json!({ + "type": "view", + "background_color_rgba": "#42daf5ff", + "children": [ + { + "type": "view", + "id": "resized", + "width": VIDEO_RESOLUTION.width, + "height": VIDEO_RESOLUTION.height, + "top": 0.0, + "right": 0.0, + "background_color_rgba": "#0000FFFF", + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_y": 40, + "offset_x": 0, + "blur_radius": 40, + "color_rgba": "#00000088", + } + ], + "children": [ + { + "type": "rescaler", + "mode": "fill", + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + ] + } + ] + }); + + let scene2 = json!({ + "type": "view", + "background_color_rgba": "#42daf5ff", + "children": [ + { + "type": "view", + "id": "resized", + "width": 300, + "height": 300, + "top": (VIDEO_RESOLUTION.height as f32 - 330.0) / 2.0 , + "right": (VIDEO_RESOLUTION.width as f32 - 330.0) / 2.0, + "border_radius": 50, + "border_width": 15, + "background_color_rgba": "#0000FFFF", + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_y": 40, + "offset_x": 0, + "blur_radius": 40, + "color_rgba": "#00000088", + } + ], + "transition": { + "duration_ms": 1500, + "easing_function": { + "function_name": "cubic_bezier", + "points": [0.33, 1, 0.68, 1] + } + }, + "children": [ + { + "type": "rescaler", + "mode": "fill", + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + ] + } + ] + }); + + examples::post( + "output/output_1/register", + &json!({ + "type": "rtp_stream", + "ip": IP, + "port": OUTPUT_PORT, + "video": { + "resolution": { + "width": VIDEO_RESOLUTION.width, + "height": VIDEO_RESOLUTION.height, + }, + "encoder": { + "type": "ffmpeg_h264", + "preset": "ultrafast" + }, + "initial": { + "root": scene1 + } + } + }), + )?; + + examples::post("start", &json!({}))?; + + start_ffmpeg_send(IP, Some(INPUT_PORT), None, TestSample::TestPattern)?; + + thread::sleep(Duration::from_secs(5)); + + examples::post( + "output/output_1/update", + &json!({ + "video": { + "root": scene2, + } + }), + )?; + + Ok(()) +} diff --git a/schemas/scene.schema.json b/schemas/scene.schema.json index 0b2d97ccf..63b743f06 100644 --- a/schemas/scene.schema.json +++ b/schemas/scene.schema.json @@ -116,7 +116,7 @@ } }, "width": { - "description": "Width of a component in pixels. Exact behavior might be different based on the parent\ncomponent:\n- If the parent component is a layout, check sections \"Absolute positioning\" and \"Static\npositioning\" of that component.\n- If the parent component is not a layout, then this field is required.", + "description": "Width of a component in pixels (without a border). Exact behavior might be different\nbased on the parent component:\n- If the parent component is a layout, check sections \"Absolute positioning\" and \"Static\npositioning\" of that component.\n- If the parent component is not a layout, then this field is required.", "type": [ "number", "null" @@ -124,7 +124,7 @@ "format": "float" }, "height": { - "description": "Height of a component in pixels. Exact behavior might be different based on the parent\ncomponent:\n- If the parent component is a layout, check sections \"Absolute positioning\" and \"Static\npositioning\" of that component.\n- If the parent component is not a layout, then this field is required.", + "description": "Height of a component in pixels (without a border). Exact behavior might be different\nbased on the parent component:\n- If the parent component is a layout, check sections \"Absolute positioning\" and \"Static\npositioning\" of that component.\n- If the parent component is not a layout, then this field is required.", "type": [ "number", "null" @@ -143,7 +143,7 @@ ] }, "top": { - "description": "Distance in pixels between this component's top edge and its parent's top edge.\nIf this field is defined, then the component will ignore a layout defined by its parent.", + "description": "Distance in pixels between this component's top edge and its parent's top edge (including a border).\nIf this field is defined, then the component will ignore a layout defined by its parent.", "type": [ "number", "null" @@ -151,7 +151,7 @@ "format": "float" }, "left": { - "description": "Distance in pixels between this component's left edge and its parent's left edge.\nIf this field is defined, this element will be absolutely positioned, instead of being\nlaid out by its parent.", + "description": "Distance in pixels between this component's left edge and its parent's left edge (including a border).\nIf this field is defined, this element will be absolutely positioned, instead of being\nlaid out by its parent.", "type": [ "number", "null" @@ -159,7 +159,7 @@ "format": "float" }, "bottom": { - "description": "Distance in pixels between the bottom edge of this component and the bottom edge of its parent.\nIf this field is defined, this element will be absolutely positioned, instead of being\nlaid out by its parent.", + "description": "Distance in pixels between the bottom edge of this component and the bottom edge of its\nparent (including a border). If this field is defined, this element will be absolutely\npositioned, instead of being laid out by its parent.", "type": [ "number", "null" @@ -214,6 +214,43 @@ "type": "null" } ] + }, + "border_radius": { + "description": "(**default=`0.0`**) Radius of a rounded corner.", + "type": [ + "number", + "null" + ], + "format": "float" + }, + "border_width": { + "description": "(**default=`0.0`**) Border width.", + "type": [ + "number", + "null" + ], + "format": "float" + }, + "border_color_rgba": { + "description": "(**default=`\"#00000000\"`**) Border color in a `\"#RRGGBBAA\"` format.", + "anyOf": [ + { + "$ref": "#/definitions/RGBAColor" + }, + { + "type": "null" + } + ] + }, + "box_shadow": { + "description": "List of box shadows.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/BoxShadow" + } } }, "additionalProperties": false @@ -254,7 +291,7 @@ } }, "instance_id": { - "description": "Id of a web renderer instance. It identifies an instance registered using a [`register web renderer`](../routes.md#register-web-renderer-instance) request.\n\n:::warning\nYou can only refer to specific instances in one Component at a time.\n:::", + "description": "Id of a web renderer instance. It identifies an instance registered using a\n[`register web renderer`](../routes.md#register-web-renderer-instance) request.\n\n:::warning\nYou can only refer to specific instances in one Component at a time.\n:::", "allOf": [ { "$ref": "#/definitions/RendererId" @@ -308,7 +345,7 @@ ] }, "shader_param": { - "description": "Object that will be serialized into a `struct` and passed inside the shader as:\n\n```wgsl\n@group(1) @binding(0) var\n```\n:::note\nThis object's structure must match the structure defined in a shader source code. Currently, we do not handle memory layout automatically.\nTo achieve the correct memory alignment, you might need to pad your data with additional fields. See [WGSL documentation](https://www.w3.org/TR/WGSL/#alignment-and-size) for more details.\n:::", + "description": "Object that will be serialized into a `struct` and passed inside the shader as:\n\n```wgsl\n@group(1) @binding(0) var\n```\n:::note\nThis object's structure must match the structure defined in a shader source code.\nCurrently, we do not handle memory layout automatically. To achieve the correct memory\nalignment, you might need to pad your data with additional fields. See\n[WGSL documentation](https://www.w3.org/TR/WGSL/#alignment-and-size) for more details.\n:::", "anyOf": [ { "$ref": "#/definitions/ShaderParam" @@ -633,6 +670,13 @@ "type": "null" } ] + }, + "border_radius": { + "type": [ + "number", + "null" + ], + "format": "float" } }, "additionalProperties": false @@ -703,7 +747,7 @@ ] }, "width": { - "description": "Width of a component in pixels. Exact behavior might be different based on the parent\ncomponent:\n- If the parent component is a layout, check sections \"Absolute positioning\" and \"Static\npositioning\" of that component.\n- If the parent component is not a layout, then this field is required.", + "description": "Width of a component in pixels (without a border). Exact behavior might be different\nbased on the parent component:\n- If the parent component is a layout, check sections \"Absolute positioning\" and \"Static\npositioning\" of that component.\n- If the parent component is not a layout, then this field is required.", "type": [ "number", "null" @@ -711,7 +755,7 @@ "format": "float" }, "height": { - "description": "Height of a component in pixels. Exact behavior might be different based on the parent\ncomponent:\n- If the parent component is a layout, check sections \"Absolute positioning\" and \"Static\npositioning\" of that component.\n- If the parent component is not a layout, then this field is required.", + "description": "Height of a component in pixels (without a border). Exact behavior might be different\nbased on the parent component:\n- If the parent component is a layout, check sections \"Absolute positioning\" and \"Static\npositioning\" of that component.\n- If the parent component is not a layout, then this field is required.", "type": [ "number", "null" @@ -719,7 +763,7 @@ "format": "float" }, "top": { - "description": "Distance in pixels between this component's top edge and its parent's top edge.\nIf this field is defined, then the component will ignore a layout defined by its parent.", + "description": "Distance in pixels between this component's top edge and its parent's top edge (including a border).\nIf this field is defined, then the component will ignore a layout defined by its parent.", "type": [ "number", "null" @@ -727,7 +771,7 @@ "format": "float" }, "left": { - "description": "Distance in pixels between this component's left edge and its parent's left edge.\nIf this field is defined, this element will be absolutely positioned, instead of being\nlaid out by its parent.", + "description": "Distance in pixels between this component's left edge and its parent's left edge (including a border).\nIf this field is defined, this element will be absolutely positioned, instead of being\nlaid out by its parent.", "type": [ "number", "null" @@ -735,7 +779,7 @@ "format": "float" }, "bottom": { - "description": "Distance in pixels between this component's bottom edge and its parent's bottom edge.\nIf this field is defined, this element will be absolutely positioned, instead of being\nlaid out by its parent.", + "description": "Distance in pixels between the bottom edge of this component and the bottom edge of its\nparent (including a border). If this field is defined, this element will be absolutely\npositioned, instead of being laid out by its parent.", "type": [ "number", "null" @@ -768,6 +812,43 @@ "type": "null" } ] + }, + "border_radius": { + "description": "(**default=`0.0`**) Radius of a rounded corner.", + "type": [ + "number", + "null" + ], + "format": "float" + }, + "border_width": { + "description": "(**default=`0.0`**) Border width.", + "type": [ + "number", + "null" + ], + "format": "float" + }, + "border_color_rgba": { + "description": "(**default=`\"#00000000\"`**) Border color in a `\"#RRGGBBAA\"` format.", + "anyOf": [ + { + "$ref": "#/definitions/RGBAColor" + }, + { + "type": "null" + } + ] + }, + "box_shadow": { + "description": "List of box shadows.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/BoxShadow" + } } }, "additionalProperties": false @@ -907,6 +988,43 @@ "RGBAColor": { "type": "string" }, + "BoxShadow": { + "type": "object", + "properties": { + "offset_x": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "offset_y": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "color_rgba": { + "anyOf": [ + { + "$ref": "#/definitions/RGBAColor" + }, + { + "type": "null" + } + ] + }, + "blur_radius": { + "type": [ + "number", + "null" + ], + "format": "float" + } + }, + "additionalProperties": false + }, "RendererId": { "type": "string" }, diff --git a/snapshot_tests/rescaler/border_radius.scene.json b/snapshot_tests/rescaler/border_radius.scene.json new file mode 100644 index 000000000..d870231f7 --- /dev/null +++ b/snapshot_tests/rescaler/border_radius.scene.json @@ -0,0 +1,22 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "child": { + "type": "view", + "background_color_rgba": "#FF0000FF" + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/border_radius_border_box_shadow.scene.json b/snapshot_tests/rescaler/border_radius_border_box_shadow.scene.json new file mode 100644 index 000000000..669378200 --- /dev/null +++ b/snapshot_tests/rescaler/border_radius_border_box_shadow.scene.json @@ -0,0 +1,32 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ], + "child": { + "type": "view", + "background_color_rgba": "#FF0000FF" + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/border_radius_border_box_shadow_rescaled.scene.json b/snapshot_tests/rescaler/border_radius_border_box_shadow_rescaled.scene.json new file mode 100644 index 000000000..0f1084b6d --- /dev/null +++ b/snapshot_tests/rescaler/border_radius_border_box_shadow_rescaled.scene.json @@ -0,0 +1,37 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "width": 600, + "height": 300, + "horizontal_align": "center", + "vertical_align": "center", + "child": { + "type": "rescaler", + "width": 200, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 20, + "offset_y": 20, + "blur_radius": 5, + "color_rgba": "#00FF00FF" + } + ], + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/border_radius_box_shadow.scene.json b/snapshot_tests/rescaler/border_radius_box_shadow.scene.json new file mode 100644 index 000000000..e226b108c --- /dev/null +++ b/snapshot_tests/rescaler/border_radius_box_shadow.scene.json @@ -0,0 +1,30 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ], + "child": { + "type": "view", + "background_color_rgba": "#FF0000FF" + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/border_radius_box_shadow_fill_input_stream.scene.json b/snapshot_tests/rescaler/border_radius_box_shadow_fill_input_stream.scene.json new file mode 100644 index 000000000..813b30e26 --- /dev/null +++ b/snapshot_tests/rescaler/border_radius_box_shadow_fill_input_stream.scene.json @@ -0,0 +1,33 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "mode": "fill", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ], + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/border_radius_box_shadow_fit_input_stream.scene.json b/snapshot_tests/rescaler/border_radius_box_shadow_fit_input_stream.scene.json new file mode 100644 index 000000000..ff9cc6e93 --- /dev/null +++ b/snapshot_tests/rescaler/border_radius_box_shadow_fit_input_stream.scene.json @@ -0,0 +1,33 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "mode": "fit", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ], + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/border_width.scene.json b/snapshot_tests/rescaler/border_width.scene.json new file mode 100644 index 000000000..8705ebd2c --- /dev/null +++ b/snapshot_tests/rescaler/border_width.scene.json @@ -0,0 +1,23 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "child": { + "type": "view", + "background_color_rgba": "#FF0000FF" + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/box_shadow.scene.json b/snapshot_tests/rescaler/box_shadow.scene.json new file mode 100644 index 000000000..dcfd76a9d --- /dev/null +++ b/snapshot_tests/rescaler/box_shadow.scene.json @@ -0,0 +1,29 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ], + "child": { + "type": "view", + "background_color_rgba": "#FF0000FF" + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/nested_border_width_radius.scene.json b/snapshot_tests/rescaler/nested_border_width_radius.scene.json new file mode 100644 index 000000000..342e39a0b --- /dev/null +++ b/snapshot_tests/rescaler/nested_border_width_radius.scene.json @@ -0,0 +1,37 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FF0000FF", + "child": { + "type": "rescaler", + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#00FF00FF", + "child": { + "type": "rescaler", + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#0000FFFF", + "mode": "fill", + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + } + } + ] + } + } +} diff --git a/snapshot_tests/rescaler/nested_border_width_radius_aligned.scene.json b/snapshot_tests/rescaler/nested_border_width_radius_aligned.scene.json new file mode 100644 index 000000000..03b0e49c2 --- /dev/null +++ b/snapshot_tests/rescaler/nested_border_width_radius_aligned.scene.json @@ -0,0 +1,37 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 80, + "border_width": 20, + "border_color_rgba": "#FF0000FF", + "child": { + "type": "rescaler", + "border_radius": 60, + "border_width": 20, + "border_color_rgba": "#00FF00FF", + "child": { + "type": "rescaler", + "border_radius": 40, + "border_width": 20, + "border_color_rgba": "#0000FFFF", + "mode": "fill", + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + } + } + ] + } + } +} diff --git a/snapshot_tests/snapshots b/snapshot_tests/snapshots index f00123f1a..fd3ef30ac 160000 --- a/snapshot_tests/snapshots +++ b/snapshot_tests/snapshots @@ -1 +1 @@ -Subproject commit f00123f1a4b6c6e643beb22e7836bf605f2e6c93 +Subproject commit fd3ef30acb19aded98515cad20a16b0c5c89d7a9 diff --git a/snapshot_tests/view/border_radius.scene.json b/snapshot_tests/view/border_radius.scene.json new file mode 100644 index 000000000..c1ee5d386 --- /dev/null +++ b/snapshot_tests/view/border_radius.scene.json @@ -0,0 +1,19 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50 + } + ] + } + } +} diff --git a/snapshot_tests/view/border_radius_border_box_shadow.scene.json b/snapshot_tests/view/border_radius_border_box_shadow.scene.json new file mode 100644 index 000000000..93ba6bcd2 --- /dev/null +++ b/snapshot_tests/view/border_radius_border_box_shadow.scene.json @@ -0,0 +1,29 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/border_radius_border_box_shadow_rescaled.scene.json b/snapshot_tests/view/border_radius_border_box_shadow_rescaled.scene.json new file mode 100644 index 000000000..4849370b2 --- /dev/null +++ b/snapshot_tests/view/border_radius_border_box_shadow_rescaled.scene.json @@ -0,0 +1,34 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "rescaler", + "width": 600, + "height": 300, + "horizontal_align": "center", + "vertical_align": "center", + "child": { + "type": "view", + "background_color_rgba": "#FF0000FF", + "width": 200, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 20, + "offset_y": 20, + "blur_radius": 5, + "color_rgba": "#00FF00FF" + } + ] + } + } + ] + } + } +} diff --git a/snapshot_tests/view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent.scene.json b/snapshot_tests/view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent.scene.json new file mode 100644 index 000000000..45c66220f --- /dev/null +++ b/snapshot_tests/view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent.scene.json @@ -0,0 +1,41 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "width": 460, + "height": 270, + "children": [ + { + "type": "rescaler", + "width": 600, + "height": 300, + "horizontal_align": "center", + "vertical_align": "center", + "child": { + "type": "view", + "background_color_rgba": "#FF0000FF", + "width": 200, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 20, + "offset_y": 20, + "blur_radius": 5, + "color_rgba": "#00FF00FF" + } + ] + } + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/border_radius_box_shadow.scene.json b/snapshot_tests/view/border_radius_box_shadow.scene.json new file mode 100644 index 000000000..7529d7fb7 --- /dev/null +++ b/snapshot_tests/view/border_radius_box_shadow.scene.json @@ -0,0 +1,27 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/border_radius_box_shadow_overflow_fit.scene.json b/snapshot_tests/view/border_radius_box_shadow_overflow_fit.scene.json new file mode 100644 index 000000000..8cc107791 --- /dev/null +++ b/snapshot_tests/view/border_radius_box_shadow_overflow_fit.scene.json @@ -0,0 +1,36 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "overflow": "fit", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ], + "children": [ + { + "type": "input_stream", + "input_id": "input_1" + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/border_radius_box_shadow_overflow_hidden.scene.json b/snapshot_tests/view/border_radius_box_shadow_overflow_hidden.scene.json new file mode 100644 index 000000000..cc401d7a5 --- /dev/null +++ b/snapshot_tests/view/border_radius_box_shadow_overflow_hidden.scene.json @@ -0,0 +1,35 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ], + "children": [ + { + "type": "input_stream", + "input_id": "input_1" + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/border_radius_box_shadow_rescaler_input_stream.scene.json b/snapshot_tests/view/border_radius_box_shadow_rescaler_input_stream.scene.json new file mode 100644 index 000000000..3cb05a51a --- /dev/null +++ b/snapshot_tests/view/border_radius_box_shadow_rescaler_input_stream.scene.json @@ -0,0 +1,40 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ], + "children": [ + { + "type": "rescaler", + "mode": "fill", + "vertical_align": "top", + "child": { + "type": "input_stream", + "input_id": "input_1" + } + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/border_width.scene.json b/snapshot_tests/view/border_width.scene.json new file mode 100644 index 000000000..91410189a --- /dev/null +++ b/snapshot_tests/view/border_width.scene.json @@ -0,0 +1,20 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF" + } + ] + } + } +} diff --git a/snapshot_tests/view/box_shadow.scene.json b/snapshot_tests/view/box_shadow.scene.json new file mode 100644 index 000000000..00df6994b --- /dev/null +++ b/snapshot_tests/view/box_shadow.scene.json @@ -0,0 +1,26 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/box_shadow_sibling.scene.json b/snapshot_tests/view/box_shadow_sibling.scene.json new file mode 100644 index 000000000..16e214f56 --- /dev/null +++ b/snapshot_tests/view/box_shadow_sibling.scene.json @@ -0,0 +1,52 @@ +{ + "video": { + "root": { + "type": "view", + "children": [ + { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "overflow": "visible", + "top": 100, + "left": 100, + "width": 400, + "height": 200, + "children": [ + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "box_shadow": [ + { + "offset_x": 0, + "offset_y": 60, + "blur_radius": 30, + "color_rgba": "#FF0000FF" + }, + { + "offset_x": -60, + "offset_y": -30, + "blur_radius": 30, + "color_rgba": "#0000FFFF" + } + ] + }, + { + "type": "view", + "background_color_rgba": "#FF0000FF", + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#0000FFFF" + } + ] + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/nested_border_width_radius.scene.json b/snapshot_tests/view/nested_border_width_radius.scene.json new file mode 100644 index 000000000..d13427f84 --- /dev/null +++ b/snapshot_tests/view/nested_border_width_radius.scene.json @@ -0,0 +1,42 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FF0000FF", + "children": [ + { + "type": "view", + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#00FF00FF", + "children": [ + { + "type": "view", + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#0000FFFF", + "children": [ + { + "type": "input_stream", + "input_id": "input_1" + } + ] + } + ] + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/nested_border_width_radius_aligned.scene.json b/snapshot_tests/view/nested_border_width_radius_aligned.scene.json new file mode 100644 index 000000000..ddf6b7cc2 --- /dev/null +++ b/snapshot_tests/view/nested_border_width_radius_aligned.scene.json @@ -0,0 +1,42 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 80, + "border_width": 20, + "border_color_rgba": "#FF0000FF", + "children": [ + { + "type": "view", + "border_radius": 60, + "border_width": 20, + "border_color_rgba": "#00FF00FF", + "children": [ + { + "type": "view", + "border_radius": 40, + "border_width": 20, + "border_color_rgba": "#0000FFFF", + "children": [ + { + "type": "input_stream", + "input_id": "input_1" + } + ] + } + ] + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/nested_border_width_radius_multi_child.scene.json b/snapshot_tests/view/nested_border_width_radius_multi_child.scene.json new file mode 100644 index 000000000..c8a740c7f --- /dev/null +++ b/snapshot_tests/view/nested_border_width_radius_multi_child.scene.json @@ -0,0 +1,74 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FFFF00FF", + "children": [ + { + "type": "view", + "top": 50, + "left": 50, + "width": 400, + "height": 200, + "border_radius": 50, + "border_width": 10, + "border_color_rgba": "#FF0000FF", + "children": [ + { + "type": "view", + "border_radius": 40, + "border_width": 10, + "border_color_rgba": "#00FF00FF", + "children": [ + { + "type": "view", + "border_radius": 30, + "border_width": 10, + "border_color_rgba": "#0000FFFF", + "children": [ + { + "type": "input_stream", + "input_id": "input_1" + } + ] + } + ] + }, + { + "type": "view", + "border_radius": 40, + "border_width": 10, + "border_color_rgba": "#00FF00FF", + "children": [ + { + "type": "view", + "border_radius": 30, + "border_width": 10, + "border_color_rgba": "#0000FFFF", + "children": [ + { + "type": "input_stream", + "input_id": "input_1" + } + ] + }, + { + "type": "view", + "border_radius": 30, + "border_width": 10, + "border_color_rgba": "#0000FFFF", + "children": [ + { + "type": "input_stream", + "input_id": "input_1" + } + ] + } + ] + } + ] + } + ] + } + } +} diff --git a/snapshot_tests/view/root_border_radius_border_box_shadow.scene.json b/snapshot_tests/view/root_border_radius_border_box_shadow.scene.json new file mode 100644 index 000000000..3e424d513 --- /dev/null +++ b/snapshot_tests/view/root_border_radius_border_box_shadow.scene.json @@ -0,0 +1,19 @@ +{ + "video": { + "root": { + "type": "view", + "background_color_rgba": "#FF0000FF", + "border_radius": 50, + "border_width": 20, + "border_color_rgba": "#FFFFFFFF", + "box_shadow": [ + { + "offset_x": 60, + "offset_y": 30, + "blur_radius": 30, + "color_rgba": "#00FF00FF" + } + ] + } + } +} diff --git a/src/bin/update_snapshots/main.rs b/src/bin/update_snapshots/main.rs index 5be1e8ae1..7d47bd8d5 100644 --- a/src/bin/update_snapshots/main.rs +++ b/src/bin/update_snapshots/main.rs @@ -19,7 +19,8 @@ use crate::{ fn main() { println!("Updating snapshots:"); - tracing_subscriber::fmt().init(); + let log_filter = tracing_subscriber::EnvFilter::new("info,wgpu_core=warn,wgpu_hal=warn"); + tracing_subscriber::fmt().with_env_filter(log_filter).init(); let tests: Vec<_> = snapshot_tests(); let has_only_flag = tests.iter().any(|t| t.only); diff --git a/src/snapshot_tests.rs b/src/snapshot_tests.rs index 632ca90d3..6f5fb8639 100644 --- a/src/snapshot_tests.rs +++ b/src/snapshot_tests.rs @@ -20,7 +20,7 @@ fn test_snapshots() { check_test_names_uniqueness(&tests); for test in tests.iter() { - eprintln!("Test \"{}\"", test.case.name); + println!("Test \"{}\"", test.case.name); if let Err(err) = test.run() { handle_error(err); } diff --git a/src/snapshot_tests/tests.rs b/src/snapshot_tests/tests.rs index 3c0a6a6b5..714799c60 100644 --- a/src/snapshot_tests/tests.rs +++ b/src/snapshot_tests/tests.rs @@ -497,6 +497,97 @@ fn rescaler_snapshot_tests() -> Vec { inputs: vec![TestInput::new(1)], ..Default::default() }, + TestCase { + name: "rescaler/border_radius", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/border_radius.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "rescaler/border_width", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/border_width.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "rescaler/box_shadow", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/box_shadow.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "rescaler/border_radius_border_box_shadow", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/border_radius_border_box_shadow.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "rescaler/border_radius_box_shadow", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/border_radius_box_shadow.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "rescaler/border_radius_box_shadow_fit_input_stream", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/border_radius_box_shadow_fit_input_stream.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "rescaler/border_radius_box_shadow_fill_input_stream", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/border_radius_box_shadow_fill_input_stream.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "rescaler/nested_border_width_radius", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/nested_border_width_radius.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "rescaler/nested_border_width_radius_aligned", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/nested_border_width_radius_aligned.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + // it is supposed to be cut off because of the rescaler that wraps it + name: "rescaler/border_radius_border_box_shadow_rescaled", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/rescaler/border_radius_border_box_shadow_rescaled.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + } ]) } @@ -1565,7 +1656,144 @@ fn view_snapshot_tests() -> Vec { ), inputs: vec![TestInput::new(1)], ..Default::default() - } + }, + TestCase { + name: "view/border_radius", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_radius.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/border_width", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_width.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/box_shadow", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/box_shadow.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/box_shadow_sibling", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/box_shadow_sibling.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/border_radius_border_box_shadow", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_radius_border_box_shadow.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/border_radius_box_shadow", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_radius_box_shadow.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/border_radius_box_shadow_overflow_hidden", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_radius_box_shadow_overflow_hidden.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/border_radius_box_shadow_overflow_fit", + only: true, + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_radius_box_shadow_overflow_fit.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/border_radius_box_shadow_rescaler_input_stream", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_radius_box_shadow_rescaler_input_stream.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/nested_border_width_radius", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/nested_border_width_radius.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/nested_border_width_radius_aligned", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/nested_border_width_radius_aligned.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/nested_border_width_radius_multi_child", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/nested_border_width_radius_multi_child.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + // it is supposed to be cut off because of the rescaler that wraps it + name: "view/border_radius_border_box_shadow_rescaled", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_radius_border_box_shadow_rescaled.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/root_border_radius_border_box_shadow", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/root_border_radius_border_box_shadow.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, + TestCase { + name: "view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent", + scene_updates: Updates::Scene( + include_str!("../../snapshot_tests/view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent.scene.json"), + DEFAULT_RESOLUTION, + ), + inputs: vec![TestInput::new(1)], + ..Default::default() + }, ]) } From 716d243a804fb0a3abafbd99c92728cee517abaf Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Mon, 4 Nov 2024 19:19:02 +0100 Subject: [PATCH 18/51] [tests] Regenerate snapshot tests (no system fonts) (#848) --- compositor_render/fonts/Inter_18pt-Bold.ttf | Bin 0 -> 344152 bytes .../src/transformations/text_renderer.rs | 5 +++++ snapshot_tests/snapshots | 2 +- snapshot_tests/text/align_center.scene.json | 2 +- snapshot_tests/text/align_right.scene.json | 2 +- snapshot_tests/text/bold_text.scene.json | 2 +- .../text/dimensions_fitted.scene.json | 2 +- ...ons_fitted_column_with_long_text.scene.json | 2 +- ...ns_fitted_column_with_short_text.scene.json | 2 +- .../text/dimensions_fixed.scene.json | 2 +- .../dimensions_fixed_with_overflow.scene.json | 2 +- .../red_text_on_blue_background.scene.json | 2 +- snapshot_tests/text/root_text.scene.json | 2 +- snapshot_tests/text/wrap_glyph.scene.json | 2 +- snapshot_tests/text/wrap_none.scene.json | 2 +- snapshot_tests/text/wrap_word.scene.json | 2 +- src/snapshot_tests/test_case.rs | 2 +- src/snapshot_tests/tests.rs | 3 --- src/snapshot_tests/utils.rs | 2 +- 19 files changed, 21 insertions(+), 19 deletions(-) create mode 100644 compositor_render/fonts/Inter_18pt-Bold.ttf diff --git a/compositor_render/fonts/Inter_18pt-Bold.ttf b/compositor_render/fonts/Inter_18pt-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cd13f60ce1987656c23484e5468d82dcaf6689a6 GIT binary patch literal 344152 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�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 z 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

+kfm`VHw1%7c3;ipS z@l>v3xrk9q_No~V^sh$eA@*a9@KvaeYHm;ZS8Z?C z!UTtY#qu!0ZRv49b9>USqCNC$k*Z&RSB}B9GA|}iSK;%7D%G6WdQUC(U@Ax=-A*YU z=v0MsL;r&XN^zQSFXHW5k_mkG= zWUm{TxOT*dby!W64>15 zehOX6?>BFj+dP>#jff+7Cqau|l15euaKffi8&g=dIx5mlm6>XB}rSX)ZD8%l`S@ zy5$Xs9~azx91lKYE~MfZoYv*2l5mc7Obae~bn+#>;P<3;+1YE8z_9FfNm2>x4NF@8 z4c&j{=OHVCPx{YI{KKK)Q=2yl4((#aSHQ;$tx|+TfE65vfG@=%pa>C~YO^oA&`+Ly zQlk6@^R7z+quIaub$lKM79U^Gon}9+i}9FYvhn@SHBLYFyEp_?GN8fTh5i;XVNvx) zSFP%e&R&-C_x`PmL z0V9^DdHF>7Hc#F-B4^{E7G0w|wohM?8%VnbhMFNx(e2^oho9WBof?g^EhqE*HP z<#) z2j1WrsFS|!Ln6;Bz%Poe3m;KA8IYft@}@l&x2^lL+VtyMpuOHcSrcufCqG7PMBnK@GGM^bG* zyjdFtjptpPHd8eW>M(EqrJZw95rZ5DkByImVUVvG2Hn%UNCA&Jz1Sr^xCYArC8|l6 z4I*move;3f%i<93!IdyfwVDJ`J>VlwnkK`gHu{uTUOL7+wG;=V&r^sMaiVbkwwB|- zwyIW5ZNx*@VN=r$gRV0XSxt*UA}!(OTCFQN<&34uz?!F6TJn%8%B*6|6D=>5M5RP5 zTy;;t(Z4ELwee2AV+@qDjBB65H0%nGT0EUmxE3$~RN#?Gn?B@+0AtXxh~L3c;OPO^ zkj~Rx%qIfz&qkqgbNTTk=H0VX`+zRKZ6Xqa`1R$iZNH0S4!nD=qU0%b^I?PcjAQlq zv7m09+}(U-xlt$Ye~#V`OWa>lw1lmE@`%Lh`Ca#mzLjEuK4RT0nHEPiTaL`l{p7HRxhp2Wv&y^^zum%p&~*EJ3K$)^l4-XpM8z^Lem zks&{_!aC(&@n~E7;?ubcFON&xRnYzEa>FyN^qr@s?+kjK&FV@#Z6G%H0&MP{RX2Ah zIIdj`Ce>?wrj-g0{Ig*G{au9@Rt~60m76XL90N-txaXAq0d!Dp(0tLACS}a#$RWm7 ziv#94-;~+C=>VEhiWq~BXXeTQ+HO!lM{5ak41e^p+v2c@J*7Zs4o_1)p-QH$fU;3?{5SGp-QZM2e0OBb#- zDlLelO}N%5rzOZ#H^bU3F7-b6&wR0TS0u;>DsC?e%!{L?J81yV9Tf=<@lscaSn!`lse&|)N-nkLb`y1ov!F9Db9NOgoPX^c?x(!vuYTS4mN;QI?{-P`2_ z5mdv9Z=)4SriN8ai0EyR*4qlvnN@0d%0l6hjW`SgMIhmy(i3V!t(>3OCM~ta`f@O z{pJk{a_R0?F#avyq^?DOo;Y1m+I?`Bm&-3ccO^$U7`Hqpdv(IV)tT8V;>h^meRWyF zJ`S+y4f<-ZkN>aq%IT`Lj6ymg#@qiF+N+t)kA8plpLHqr`CidAjDq6&U99H+cI zOM9`siT1E3PeV|cP1ni?c(Qf4jaxORuS+M0iK$dB>a$UG2Z)I@VAtP^SO2|!?x&0E z@f&ts`}xL>4e2&^z{vcdN_KPZ4-J;^qo??S;fE%92e$0HG$&_S%#c|9jU8)0odBt% z&OXJfM-7Ek;+!s2idrOB9MmmhSxf(NnWuBhi6edbwQka(aio{CEpPE;f}|ghjd(6i zZ}>)*lg4HnpF|(M`)q?(#>s6*+4cB?^b6sd!mp^;41O?V&ohrU9Z#;9ba*(wo;SQl zRuJ7PhhJ`V*>fY#%{N9#i^fa|8ck~%MiQ`Linh}Vw_U#%E4=c7+J^=uC*5Q^*j7G3 zMAdizi=ZOaWx3cWhr4Zp`rF{() zvwJ5`s_IcG)XuI*M6FuK7{OWx7stoAQe<(uq4${D$C9wFUNraiNmH?^NLy zbOQ9I)-N3f=_puj{Le&56<$=Fe5f^1cNuO^*r{?o_sXBQ;cWI%n0T)mm3@By}$Z;9z-VA zI1ggTH8!*^oFH2(b`0;!{@9`CuY7w7}SIQDB(&?w({xF}I1LfY#hkwzw z)5|L-9UjJf@`m-y3}QE=nYi`6Y1x($=jTc1j5Eee4jcn)j*!j=$`JAvMmU%;spByO z&`>BgFHYhjRaJhkO~+GZla35a53Ap*RlU}+T@#m#>XttY3jm!Clg?m5&(CAyB04dN z-P9?r{Y!`Qi_}>x2(TADChD%D$F5>_1D>T*Es@t=(s>*{_JsbsMK}jJIR=IE#BH0| z$|q4$9@ZJ@zF#YPxwf?kcqy$>$|?~n7kO`$5tJqJ7<`2ax5*Xlk!_;2FRQ#OvP#Ht zY|#L8A#o5{#gzz606)@ywD!yRCarzfD(zQl)r!f{Y=sBP`!(SV(DW75GBgY{4pcom zDS|a8gvKfRgH$|Pu|1F*nam~^ha%>!B$OW`1qDm!Z9Ik}G`*jLrQeyxnAzJ%cvXNK$bx9byS3xI2j8A=lg za|7^ufcuKwP{s0Fr8pc`Vo#Jti``ir;mS%8y{fE0xvcliw4z+rtAs^BttbT)Y96Dk zq30D^&wBLG!9o#AX3Z27p+E474t#3Q4{_=T9(ve=i3{HXuD4zN8$t6>Fzbv}&w{fk zoAswSbd9A?&D28d2yVkF-{r&DUI+qG-;zX`KJ5a-OjK0NJUP2xr@kSOjPXTVWAFBe zz!;v#vMv&ME|GkQIe6Iw7rhf4z6#6@9#GdtUdy*?5>DW%Mbe#rS$9)n>B6cfW*!D(q`japPt=3gWZ^?N7_0kxVIDg z7AGbb_xZrX$IBz86Pw6Cj9!%AgT1INGtrCa`$Ls@2DcSxS^)N{!YSBm7S8H$ljzX& zRU1RiBctVDX5aVdvpVCj+d>1a!A7RXWdeJ#10Yeqekn@){`9Fa1}{XYh{)C51kuITkgRGZgDi^lm{D7q3N35sq?)Z@ zyk+W>c*&?wF*p|@9&6<@VkoY(h^#GI?aCUVwguc4j8oNWRk;4Pje7r^)Uy>HsOMm@ zen{O~!J%$J7c-MxxP1FjpBemMzb&Zbv}^|xWt>u_WU`X zCV5L9RELPS`ULOUYTUO*M0JeJEP4v}&73f)c1$Bwdj!cStW#5=!^+!O8z@N%E|Cb} zfO(sQPH0y%RIF(mXTay7^$S+;g36Kj7Ea4NQJO8xQXE0CM5^2+73<;$tLviq{02o! z%=bYJCF1b`34&rHzXdenZefIr`2Z^N|1{g$S>MEuE&w{nZyA@3Uf(})$CRA16fgc; zht4g0nla|zSsMH~zb?7?1aTmgbze()O0En+dw{4`bl$ZQt5vPOX3e6 zDEZPwQ_-uZ3dfSbh9)eQdwdo)I+G9(Je@3u%0)a(+G>GA_w>Q7Ei!OL#YHS<$^kNS zj&gO`yGM30Z;wt+&28PC`{`C~P>z>R4d^V(-{|Xsaz}g<0Sk=(4`^kGo1>iuy{kgU z6EtgMI~6Ji0P2alj;p{ey_D`dFG>1+cZY3n3Dsr58dW3_y7!)QwIx z0O8<*QvXv)sMvX5)gk(~m24XX@L?W0;+hGLymZ^7>dDs$E5&r$DPqp`oSKhZ96NnW z+jh={n^Q*Z%HY>W#ReyJWh`%0+bDfRcnCKk+>qF}keINv)jxoFfC7&+$jOPbIC&v5z+Cr&CJn;vOhX zASOZ4%D83%CmP*05xz8&f>H1Ek*dLO`nUOQJEvy3iv*XN7H&!z_54ugoeM5?U@qBl zfyv+!HnsXWbHX-m7`d=l`oS5}FUF+d8C}!6OD`B>ld^m>BBf1&Ps2p-GSx>TMeq2G zH0WMnt(2#d0lNZ5o9@qNAVyVD`nQDz%V~|En#wkzq9ApElLt${VWZ7a;XIHg*$R#n zdR6Z5^fo0NiXqkDRuImX>fQwMwmjxPP{~pX=@24A%&`>jPSv(AU0-xUUX{nTFJbOH z?#)mR>_x})o{xglX8 z*Bk|Ul({C^h48>@Dujn}V_>p}#Y;kQ_3P3;lPJ5UoG!ARV`F$*WwhKe7SrkdqQ z7N`||lY;>C&9a8W0==Lf_z||VZok~-u&VKqN3oMmO9DU4edP`o0d^SW3;Yy2fU*JV ztEtfOj4qa$Y6v1i?uQK)ZUH~mzE@^@4@qXME&qVu=#}l|A>(+&yN)`R6gqBNUv>=| z;=@rV64UqO^DYo^isCI7^M~^j>;)|Ztj4$=OK=>!@1F$={@J&e{@qJCd-?tQ7a$o( z*BuaxYX^Jc$)x9d3`iK@+U1YpiOJ`a zYZ-=oai^l!b-es?PGN;N<%2zaNF;DXJVmW{3qer_Wr5#jV`_pUa=FU_Cr5^c2WcV} zI5{#@IAW1-(wLcM!mrnVHtlgJQY}o_5zEH>ny}anm7-NF1UL8UslqXes=Zr!x$~K& zm$oKsh-u?6Vxox>kJX8^z4dPmP`fsTW+-hk+PKPCYz;Ul?Ks{F4wsdN`;G;Rp}z@g z*J^?pH^s_T+=!uD@zMfE3|)g`@mg^Qi&snCp;aN2iI`iYG;3TVI7P8F{BAZcSkY*K zyVnBur~*fHTf^gNf)hRFekr;Q84=NK3tg{^&zlRGvz9GuxV0==!PRl#B&RN>JKAFE z`+r|fj);E4ZEg^81QC`Df&*H5mPPi4N4TGlW3%Scd^tVVE7aH9sby28L>l_+i%$t` z?$W%YYwpD6F3r5Wa;XR-b#Ms;#Z(Oln zR&ZC-blDbDaVc|q3w$KLc2C2B>bLNyMxf;KbidX;loZXiHt^6rvRhnJe>Xe%|Zwf2^t~DolX&+t`3f-L^dt*TEyJzJ0}#YcLC<5 z%t~xp=Z@8l0J7OnnA5>Ug19ut`c4354R7rzr^NiJhiW*gVD{3TuBY@Z-D8Uj_zWXw z9`&3PMMnD6YoKAEbDcZLOApGYY_j07s6Ev=jeS({=;@>g23WFUt2+vxjVvqwA&kE# zvZtCav0Q!%iI_V-$2z@k(wzpyy5Nj>Ia{LLy`8h+x0E@{E09Ky~gDwbQ{qaynT zqA+3&ncKD8M^o)&xq*^F`A_hLIH?g`X9w-dAZ%n8+ty{7P5m7m zV_kdYhbjrLjm%XP{!nk|p4Zp7Mm_Zj3=K5zV-$OL z?GTf%qkn%&|ps^Z_h>ARp_SWHjxJDk~9MGh3 zVCaBqeNcFI#w1e!R#*90k02Y%XfA@pji9s1;Y9IuLx85Oq`CaMZ%Q|p&?fcU`?p^5 z$qZ>@Osc1(luL?~a(azAfzoH{*C%O-W~Nt|QJt%3`lpNA__wduB&1zXs;_iz&FK_; zvs{rpQ)7%{R2?m5Po`p0(9sSx%~%ohuC*eY2&p$pv!lm0l=oB$Q@Eu+dx}y_! zv6?ve4l8Jv55#oFnp^8_SCBDGaY@-4$DK+afg=a-HhMCt3Af(%p*R_l6S;xVR-#Av z6L*T%1w7EIN1P5TABcE|fD3b;+Qa`yaJW!@v!%Z8^I6v4f(vl^H_7z$>hl zuJqoyS_PDRwXUd7@4|{C{g;3I^&Q{O0`s#o$GpY1@%LFcgS1^awCD9t`}XM@Q?Z%- z!^!&#va29;P+j%{rNAu{Le}D~F`3!<{5_WT-CuuvS<3ubAO04cna{;U_v!oT#XX1K zmxc(8%qFJtSH%@72h76h6sh3q)0nteU|sM}Cxi?JfwQw(*G&po^wB&A*37YB@SyDI z=+}1cob*xI!ndY128j@$9rPTovrl=;9mJu~IQtSA>RVT-CAM6#^=zYyMe(B%F-TtbJm z9o%Kb(6qVPK9|^A&qO_I^TMTESN|5c_K zrRpN0rYGD!9-cv(KIkM0RA$agtKslhneJ+L8*8jvKQPVe1^!xQByF$LvlAae4LTP1d0N zc7U%z{>iTHwvF^-^ng-a}u~{amj%80z7w0B4CPvBH)eyhqTB zYNrHtwR%T91Giv%^h!_McS)~%RJ~Ks&Id}bX`QMn%&H4v=O9b>ok z4_SM1{J3p!rFZWbR2n__W7i_D2CO4x?O zrR}@;4aiY=BUO%W-sBIIrh#4bidl-x!bnxE)lzviNDhglw7t5tNFSX$$L3U%66hYJ z6iU~0!=baLlg@<>%@;Zek}pT-2jQG9;E0F5ZqrS)ccB$wYOlYgU5ODZ#o%g!!+!B% z4Mh7u>-K;z5<1io@lk6$zrlV%kQ?-b$^I7nh>w0NGS5Dt!5i>!l1Aq;{wW@_f&l{f zDhP(TBp4X0W*}0jDs0@+biR25tx(6F4cpbaLW{6MPic##mK9nZaaj|r&|Y@+utHm0 zyxJ*|U8~;F6IUq4ij%0cUW|2-#`~^<_ZX9G5WE*~@P4u2eGwwp7%O-{a9E$|w0qox% z&Qo~xzA3e}ib@axRfJoy)*ezytG6lN^e3fRr;`n>GFp*jir_?(vge2wgiXW?;8CM^ zfyN1fQoKMw^>?QUuT15AU2{YRY(>3oQBzd}1;lX_8;6*G3mNj8u`a(&%Ql{VoEmx4 z8JFunj2TgpRufq?NSGK8U@*f_preK9=8xKmpA!jKfFH8W#N{AA95&kr4G#;;2w>h` z9Xiflv%=SRz!2{a83|pxkmJWVBR<#9FE?IVRB_ka^S8CjMvh;T?CP4lW_-n0Vz;@k z8-mWL=7UxV(@KX~2BaJE=#11J$?VLh3U8%X)~`1P)-)0`gUP>7tfc70VJj9};I}o` zqB@?FxN0{3!Q2SH*)k1ri_3 z?KemZtngdtSz%3&h(rhxvArc~%n9t2_Noew?ax-wfoAA$R!~dZ+X7l31k%(W?)ZIA zi%q4P4sYrxADV)N2=XD%+YDc3V<#3{5$@($!ErZlo)-M8+J3psX%$YrTG4%HhPhV} zg;0C_)x>icmR8tdSZ1odR-v5=WF?q*sB10^>~%s0tme83+)6gA;nncavLrl++lz=4 z6b>y*4GM)r)Cfg!4*}2wwVbj^ptXbxEGa}0CU5;|CiC{q=+$eeFY}rCQ=_q0mrGlW z)1ycF`;Uy478^${zdBZMAD9IFBHOQkYA02%$c&F|rCFmRNFSRrqpKj9J8hNjy|MrWkO3mG%&_@6_ogEaW+- z))rj|s1OYms)=+p%+Q;f2vBPhb+xrg)T`o9MIDJUXloiJs<^4k0>Xu9Gt;ak!ea@b zwbdk8gry1`!ZJWi4%%zlx-BNBCT(p!N1C$ce$_<6tf^CKpDImO-$b``c$}zCm02nU z98xLr`Dqwc+FK378mA><@#|}Z-J_#W$9DdbW$*2S!#9ZLr6T)I}V=qdOw8#;i z;ylN-kL{9+3Cd#ZD8DehbAQi#&wib!NjpE5N)Ha)85g&6;6Y>2hsKeY6L<9MwcW*laJMigfR0ZG1eUqO#`Y_~M<4_xO7)+IV@!#bx9Fm%@41nd68hA2ROj z+}`$A*I`3g6K*d}L?qA0_KsWDP+rb{te8t8gJNhq!5x@>NkPs{P|X!gu_`AmPP8)v zy9Xut)v3>iv(Q)Cb!^eMMPR$vu@XJo6y|+SE!c$Z82WP2Z8P<~j%M)1`^LGtv%eu1e_@Do{ zfu%_gjcb;!l13ZrU?ES0nyUvSc2INX+BPmu6Qy>>yK<57k>q?<+G)7|u5rBKKE|Xq z2Q5_O$6yz1^HOC5p{Zm_I?y1j*_*taD0Uv;LKzQE6t!`Zhj))NZZ_d$^NDDD^PWH5DGH5tBmEkV2kT`nC%Bevpx$iw` zyxPXNjSQJ->fnDoqvz7XjvX7`?>I6gW{|71EJ^3e!L&=W5YYQ->B_iNzv#g++=SbQ2H7q7!f|I`nRalc1{b6*d!UgfBP2 zVQFCM%B4!dok2&WZes&T^ul7n*xuIITpVs0qxrB`EW;-M;6mty9} zuj1k96aUVc^X~~ho0Sfk6cjXR2*)LzN1c=l)88*Cy*l-7_so#c5h0j*^1r76txjk@ z2%(Z@9Kx^R%1U`hfF-dGPKkaEw3oUtcU(pCl5}i=q*T~Snf!V^!dxLQ0cqM(iumo> z-*;?c{F~{Y@BrSkyzht(bFp6WxB`ANsLMf3*dZTmuCk;275Vq_OUi=EN@?<=N78Ui zm>9b*A78=1C|dX1GO`LgJTAQjWXpsAhG`c@NV*@`Y_B0n zEe^CCknY9OZdJ;1yi5Po&Xr?1_sdLi=_#XnJ#q82{tbN#Y?mTOX{6~vK|k$9L03=B z3yo;1mJ#HLG02{u@N;L+vZzn4e8Qs6p5^C0xpD;&k({$7SLVKwlk-Xva}R%!`Cq=w z0*)T#S1w=X@4r|+`i+GP-x#g_%V+CH{I?a859!cv!N{A5D)2Z!OAt5mc8dqb$wMV5 zU|^lDkafs9`DpW{&5urIvyOe9U;1^~u0F=)%$3;;%~pGLMnxfq;yn%D2G@oOaMkc&X!bb{NVg&)YX(^m!(2 z*}~-WqZ9VdW0Q?1=dH^;HhsqNtaYUi{oFTxGG{~inGqw-ly8{x$wqg-hiqBf8+#YN zmYaKV!Jg0B@+pvlD2(u1-7ku#(on5?Xlr_d;mM!;Os}otJ9TIWv@QPoJq_1G4Oc4x zH^0tMXP^p~rV69vpz}uo7q2{2V%OL2r&k-4hBog5j#nEh^VC-xxU=4RWS(_@7P)ig z5#n>}5z^;A0<$(!?p$T09<~^%jiK((it1R4!spf_#`hH*SHVGT zPK=BxPLTTXTP2%b=5Joz%q!33N{7y~21)fQ_?s?^&lQ$joj(0)N#VK0E-b8~-avl; z{5AgO%em(umFnAX=~y9car|^(!eG{dInIubYQm5~h2klgZv5j0zHSY?b#5*(9Y$>p zxNxEC+VP(K+j;1`>w9#y=O3~=(#dwNGP`5vkh>g@F@8O_xS{P`CVR9o_UDe8;24CU zd9b6z2?VeQXa^Jt?^0h8xO=Q6a^IQZ-GRqB|a?6t+x>{E2ZG z>#_c;Y16*kz+Y#M<7Uqu$A5>0=cq`rxa{iq2a~cgD4R*_g$5a#x30P)1gW{7{;(}+ zQ&g@?os1tF#m)#WHRegmLAtwGw`ib^jfdT6tTDY^59ABbt8*9iYe88Awk;0G=s z>gp%<82sXb{UU0iM`WN^y{?M=DSo}ea7J3lL)+Br6u~b_Jz5P~a&4V7wY(#Ompus} zf5MlpxqS$j5vZ@z8<=Hm3u4=we-vDGAq&z`xtdZ)_l<-}; zEOrPu;<<)PXk9{xs z4}OiO2R7(8Zkv=7(Adc z|4fpljX6x|fHBLoNDL@jg5T^&n3G^pktHD*?10Q`IZD~c{#PEtx=LBB>*`dtu)cEL zXe{^9eN0b4KD@_z{%w38vQPvAq9qVD6y@k(o>+qM$Q&h`NLs$*kNK?Y($(WmMrFM7 zEig75_02K%0gqm^B%Lv@Aeu5r}<7ECU>-X&ESzm^iHuXg(Dl!tPcc(1hC6 z+&5_-bSJV@s7j8wuHJCxAM^ROrK<~1Mh?C79ls{OG3x8%+?SnQw4`Sj^er_MSJS}| zD3G1N<$(AFMHkH2)GS98oepeL*6;jnF25E$BWvvOs3C8B0TB#V{*<>8-c+_0FM9Xr za-)B5R`}>2ogIbJ#j-UF1#TP_>GWXwgH_A+p}xl+*7ZMkm9NBG!3xZq0dI>#BlJ{R zp^wB*C^wK92UH?cv&ipH zzOiP**VE9a*W3wxM+K3f05PfnphI*4v;1uxZNuszKg;BgDnF?gQp1_me{gt>9mA(mX(SMIj+X8 zpr-EsW%RA7lSDkCxB?FuyOTlPyB*FdE+REgJt4NkNyQ~xHk~2p7$beQ?8kj0>{&ql z?x_Ys-lT!`D#Y?1gk&bM8s&lD4R#os1 z9=r@2?K#tV@Dd9-eVV_0Y4XvmtfP}B9nH=@Dv!Q@x+2=Qc?Jx1SPo83-Z_oYa;8+KKrC#^c@llweVTY$gjZf=dp9R>D-1md= z70ir@7k!t$Gn-~;;^H1^{9WHB>1YE|CB%ZazN%qH^8(9`g0?wh1n$aGaF z$U!?$`gL`ya`I{dPdaT+&i0ai-;nbs;xeC0Usk?%-=ne#SNNa&tpgAEj@M4Hkjt2> z(Vy(x%bY)$5HTU9--Monwv6gBp?Ao<{zLrcmNxN<@r${1Z^2<^vwX?FFKptKSC+@p z2=24A)BM52Z+C9{W^&So_opY#?i05#z2KeA?Ohu;Y5Ql>R`ht7BcAcRfKhl+oj^RB zD+Zwo6$H&v?^vWz;Ji-Uq$loiToq{)itpR}tQp@UvJ=5&Uo-9N^fUCw`*zj5uv?ZySC#!mfa+tzO< zw+&AT8h>_CKP9kdc#!>_BNUq&h9$UN5U7%eskD@Gg$e9hbrs^3-|yez-)~n6Dy9lT zj%Q^bpDGC9?=>hm`1S0!St#h`-05W&PQB-!7QKHn#nk(0zW>27e(Q2R#F8wwcVJ`a zb!20xw#5zIk8qUPMBuOh!wWf_!d&!|dAHNs;@W{Pya<`h_It>RZru(V~JaU7NkFOxC+$owv4u(MZqHBWhu}r2*9w)I@0{O4?Sx z?km4+%xEI*<`;I{n>XqGg}n=tTQ=-;_?HFkcC#)IR?NGmjHc6@5?v~EGw`2UKVS)B(kuUIH=QrpQozp9E zN_gnR0lji#eeI_+#|@Eb4gndPnj*L45NczujGC~x*HPnD$tPmU5dQ&db92`vbQ?A$ zT=FqqKNPuqdOxsF&_b?6#Co6(aPtrIVurh#;l=E5jqurQbB*vhHs99>pKE?Q2RzVQ z@R!*9P-FX2o0lwb!!$EJ^BA^Y6P;G@`3!2+1h*R3Vm3pC;}mV_7iVnNQ;gd@zFIyv zkF%D~&Eu`*bMv@s`P@AIT0S@Pfj&2n*FwLUAGLg5l`n{VX!C8#8}buDfe9cp2|<+e=XmuDqo1xi0>gzGeyjr_?8K3>P>tK)k;Zd%iw8fNvf5u z;Axu!LM#EIXg(!6A~V`_7f~${Cr;Y*zCCnoQPFqn*L^)R@6AO^zMVhggObeoiH_}V z^&Qh~@`%FT;e)&64;?-}C>JSe>vn%PG57Ugr zXY#d9gSw}T7?W;1&@(3pq_qHPYPJ9l3%#oZEE(ArS9n6zoPhy&EXgNY*=UtGFa`y< z4)9c9Bi%I@mVtOCL?ji`Se+=<8@@-{CnyIV8beJ7udcqNQ9J)ywCJy$=^Mv|&0+H8 ztrxN!8I~FEO%9WpQR%`!+Q4(^6OOukrSke zB|kw^Wr!JRB*%i}=5#?x<)(>b?7MVw4sgNg+(I&B$wh30qLLnH_Fwv)pm}Lp_Sn2p zsRe$l#f*Dj62Y@RTQK*XCDHt5z_{eJ5jlfX%>>8y2<;cQqxd}M^Ud@|ulRV`gy-U` z5KQ+S6e3u{eTUza7S_Bq6_O@mDBP|JxlF%mQmwv3O1@}&Nov3Hy=jiDLEX-&k+}uF zLwjwwT)1z1w|UjYL{u}b$x<<9@7wX-^b%Iwv z@OgE-)S;-CUr^uPVV)zG_K9DW8g(O3qSwLIP zv3oOEbN{h}a>o>8r!6JIO25rolsY(PWNPxb0LFibUh>Y|h1UgT^O2n&>r#C z2#bGi!m^K7M4Kp+iDxhk>4H*6n`mtFqyP*W-$dmv0%-NapN);WoPmXrjbCJJkfUdi zS0hgc-*yQV8~;zNWy^Xk9GP}uYtgoTwz^}E&3NXs^4cuMv@@z=T&%q-sEW4*KAUBW z9j!Wij+PKw9X{7)W{vGjw4|)+?MvxhRWm)b1E};YW^~eq6~lj!>EMg~HiBHIBKAUS zJ_yMZK?Zx7Vt-Dmca>r>2-Zp!&Ou#M*L^yn=j@C!-|3UuH+9b$JEj9(uTSD9a%P2u z7RHC}Kg@qP)X}f;u$Sg!Y(H4Avs-pTi+)NSgYMoXK5_Dv8Bx8{yvp`{4gzR9pdv+d z@}}eJN>*JacW%)Ce!JLH(N=+LzkAYJm$2K&59MgI~_n-U>dS`B~sr<5~=-xZ2(sIpriz zgvX=q&j_;`P~pKex|%+-Y0M!`jb>uvwKi7{6`2dJpJthP2)T~_-SGN!gJ?khMXaFFDw(AoZkcqt?Q9Cd{HxrRXsj@Z0*^CLY=@;N1oM zB;cavw2H@Eb9yu23k(6~_KPZmfe$Hhi13B$Zc-VzNepfggBD+F;*6}kAj_>*>~tc{ zv;}*}Fp_|DA1vklCYHhy0Hxi>xCM(2xJ1=%DJMP)w@cO+?R}g-IG1-%5KS@;kCZN>V9C6NaX z@gGih?9|}HlbH*WJ2zsDnNzpXg9eWev8`wS%V&1>!}AleZ;u(Bl}V~!w(+PeSN;)l z?MUIZ>ay)lCO0TjGLLLzZ9O|RX^FC*@f8uM4Hl$)pj*9O`orjtlC1I<`g%I0VflU2 z^C}|gF;lyp=%9L^;2{tV4U{)ad&@B)t7<5-m|Z0ac?>?Ay&@#%vPvK% zM6^fs>bQywOc3^BWhk~nNC-`kwiT1}42J~kH#CJk<|GG3_v>EULy?ga4rlQnw)6>~ z|L@~3XfBV9+c^Fd^;mgFr(gz#DyyXG{{991hL21=r+&foi_O}yPJ{plUW z0cshwsh8FyEcm<0a(?h&#j=}q5?1GAtxrl`mzA?RA+g)|gA>>Owiw;fHM~l62a8^v zY|O59!HMKwx_a;^-!9+fJ8^R`tWmoznf119ltO<0-T1S1|CE?Y3H!)u(o
HleY zYFXkxZ?`~eymUZnPs=p_OMAFd;G_xE;Kd9fe=}|i+~hu}-hPhe_NWe@t385T9bRIC zKyD5AP3{5Fp46E}kI5}i9X_8S%w@)78P{T_8i{JZrmGP2R+iO;50M}V9+IlF&fK@~ z(sscP3wCUU8i!HW($puZIgQ3eHrs`oLm?QwJ>HsvTP(tIxR(@2GkH;ASi-TZdP=Qp z4LL}w1|C|x>8IH{`1Mb>e!#!om~(1&T=zkp`)`}Rb@twY9g{+R{TgB66wW*|dikS0 zXZSy>Rx{m^vU|Im-)@k)D0S?XZb0M!hixMB6jZ2MZ zr4GjHlU7AVt(pXv-=}AdrF^1+J*0?RT;+XzGS-u?W%P!^uDG zTXz4H@4%NonOnBHWcJ^G&n{VAR(k!V0bNc$DBJh*q`X&W7QH$K5+SG&M#Xz1RknZO zRT+{L6;6hN3NNO2scL}FmZsDQpTktCt&V4|RsyLyyo6n-5l<;wX@Lu4L8WINyIUiC zzV>cb^>HnhQq=ZHRZ13WpYXuVCG`>GHjl5C&&}hk<#Y3RYx&$f?pi)KkH41B&3vHG z&3v%XZ{|lWpPTt2@RKQCb^KNML;0ubysP}7d9USrRpo_DZ!tgmyV?;>{hkSKrdRzO zt0A5DQGQZ}!6+vO0=?}-c|oQ+6WCBG?^!GZY1`hnP=u^)Qz?-78UO0mvo-F#hjcam z&U_{BmTm3N@jinf?9RosU-D zj#-+Wy`*pKvdm#i`$6v^P^k2QQfO$?3@?*5$R1z^rvGP$2zi`eH^@6Dc;xiC8W z!czVZs}tF;UnGC{Zr{W~v3S~I^Qyr!8tY@H_8Yc1=BMz$u-?bR0{khl7ahq{&=F3Y z5o#LK6yAm3P!jG}(A5u-G$BvX6@sR^v>CWK_=;vyHgi-PvNrq&(HLg=J)T6^FzYvI zHNhyFSlNrRo$8TO&5fVcwG@Mbp;$w<6RcLZ6t^y|9QCc`{)hQb#+c#kMgE>$y)OK$ z)U9deysgP>a>Xv=Wfn~UY4Vbz4=@BIlj%fAri_eXjn>~Nwl#dz=+m#a-866nf`$VshfXMKGoXrSX4bGfVPqAMyGIRYP zb>bA7I3#LNz*-CyqgJNy8wMW0S$hM!%p_^KaT2b?O_i2nG?cUANB5x>=t>lQS!r`o zj4D(%h*6QyZ2?M579|~+d5AjigK)(l6OU1>;oJE4z{n%mYsPPlALGsh6(uR+?+KrK zV{tVmz(un(4W6PLN|iJ#dls|svrP%Z4ve1@l^qzrJd^to`cRg|>sPW}KgBOPnpN=f zvJM|Kj~fvlJE<2RuJxA4hpS^yZiyMWCuk3oJL9JiQ=KemM=*-0N8&pqKt_>s1Tv{o zebYNEjbCP=eDBBnTFO?02+V`n%`@awV+qi}sMQSu8j*WOIV+TzV`hXSTQ!b|4F@kK z2wwa!SswS}j}>dIkP$~E7+s4&QZ?A10O%w*Ui{7 z^^bN5%SN+`@?&x~zxeip0*urVv*jSx(qHNCX1u2$ZqRTipnP&QGt8)s@q{UAF5|4%Y5r{kx1l0~;xu!1t>8({H+9Xc&T z10!)z>R=TajAxSg4f%ig3r1YHf1mBd^PRX8h;IT1YF42yQDsILP^8nXYnaPc_+)#l zn%tgdyj2SAE5ogO&}6!c7^O;msH}i`q1Tiw^bE-+r6uUi!Xq4o{5nx5XOem&E<^v} zGy|@U$M;l&^K0w~|5t-^&OW|k1xJe1Ui!J0UuQl^(<36LC-Lja^fQ_HJZ5lyJ7n9) zkvlRnc8nakZHRG$Ve-Q=Q0~S_-z3>77# z8XDEWz3qYzP|d6_E@%e6^)B=07q5ABbWGpJ6Lk8!N}Y&aEdqM`UFUlwPpLiM&a#c4 z@dJ^C8SO`{rT3Yk=#&pg2*jO35(21bmAwksgPgoxU=P8g&2X?6`H3n#oWYz@m!T2^ z;8~G=tJ+J!9&`oZWM8qqp+jn;l3azz7~_ahg2t%BxW&NOwQ z|Br^JBMpcybP@QeN)N4GY$;VU$+Tz>lCN36)z`+2yS5tFQoO$(kdZNfpOO9@esI$G zLr_>1+hcq7ir4f>10Yhb<6r?fS4kZ+p>t$qX)JctwZg({tBijU!ePUJke1Z+syNm0 z>%J01V@Ia<)|5c}6xC*w%cAa#f$m|D_9E|#Tyu}|RO3kIIkKi+SHJe!Ypel(!1q?| z+uR4`^!@+nqm<9C-Ur6#fkAbo@hN{{bsBVar7ti(p^yx9z)Lml5hKjPMkDrGL^lxA zpt6B9UQKJ`RMs|O;J^g_5*zTz{rjJkLjaPbo=MF6UiWSxp}(Ksv**0HynNxo1Kx{% z!+iBaowFedJ$T!m3_@h4xK~SxbEl*@_3-J4exe(+Z(W9TwqwaD9!oJw?=2>2DTy0p*K{W_dV>vi18k6}b=1VqvNo_WR>|!XPAYh6C=-GmdGEt7 zQ}QIc1E{rje^=p!l>;hL<)+I5$50XKo|F62yXdSz^F{BoFF$@Ouh5uO#%zvYtgHJj z|72;>Ip37oz5C1@Fh8RducP~TX0D{2b0}&~yo24yKv{HrHs%MCr(D8N?V+KtUHj3^ z8_LQ+$?RQxCJTLFyU%Uc>}6y98}V;2zF#EIS<~)zsh|w?ft7yB9sLe)2`areE`oT% z;Y4m9Y!t%F}f3+iSOhA{EZhn2bI(l`w^!%dt zCQN*PQO4+w1N;J_J2!M`5;J{!1LjmjM$=CLM`e2q5ywt3c{Fy;c`@hv*>p zI;<(J0m`gDYFYzZh79owg`92JOzYBTg-DEe0oQ*06u%s}^B zf@o!9`k_Vw*gzKiA)X|~3K($&4A(+}(;&;4xZ zt8dn`{Yj_v={poV&KT6VJSq4|RvRMN5e_;B=AwtY7xt$+Bu_?ANr%5ucmA<7h557H z{M&OwHU==y(Hjzn8Y89i#z>kyN%v{Rk3aG^_S@FEHR77w`?D{vPx|DGPa!jDI9JgP zQS}gjeN$6YLK`D7#n1$qW0*C$u;N$Qe(=O@-3pWW@BAaF*RhB58C&>hX2of#?LRCa zCo*D8c)6$U&7&g53~Vv6|9cb8@vm^R#r@or%kl@?w(*a4 z?UFA1*~Hg%%vXmFeVN(iki>l}~J`8>L=!{r;y-*x^4fAFB!%E^;gMwEL=@2pwF z?AEM-%psbp@1>D#Plx0PEL}!hGc(XrpN=eu=`KB*DAnN~>U@oMVfO>242c`AODpBw z;pskU_6x?W}IPYqY>%=byMh-O)_3^e}ftRdzfrE z{4kk0utxP+GyG|4&l<6&d_wR$Phurh@MA zDAiO2Hlt@(7R0@0RTyCvZ^~g$RT}KU+O@3Z+O=Q+E}!b&&=`R8i?}XDGe$!<7yIe1 zoA_u2{?3vZTOrx;!}omByY}%-_Wo7cwt6+cyk-r@as^jEEMvXje3PGDYV3kBAHhQN z!$PBF+=hIn5o(6ImRzQ%XgGYdDBX^k#3KdJAL_DGgBTRokpAma}bj-~5 zk*%XU2K3+|*Nl%Y8~tC~7rW3Uv~{XakLc(@%T5de4mOy@ui?Myw z3z)ZaSfhlq2ZN;#!J{L6Rvw#DXYAYCeT@U5>ryL&bldb>Kn8XYZ4;-c6>c7&^D0+3 zz%6I+iSD>apDpV95r6ae85Z)+?5_@vZNT4c5Ik^9&nd^Vvrf#&-_Gl)PQ zAe^Y9hL(C5D#>kB5~*-@^z{;=bliEfeE;dH@7@W&5ykZEY--Vg+D4q(ua#; zo{0`&%ba-z0`BT2LW&#Pz;hO%?x1=DNrd*GNsx7%UNhw_8%JwNS7(@AP`k)Xf5!h~ z2HS=)BZE66&*NV-?3r2+R zemH1f9sZJQlKv=lj3KzD8&auUMSP)9Ji-S1y zv`MxZK}QGeFrb}p1N_y^l6T8SoHtyj5m3J4XahLfYyFGs7Cr%HVT|6i>D6sqBzPixz zmc6$u8pJ0)E%gHeIlZz}za0S(^<7LX66gu@Bc&Fpa5e>l#HVC>EAJRz`%3EFiGQ2f zuk(N|aQeC1wM?1Vr(lJfZOhELv02-P@#`I9JEo@VY#x>BW*bi%W285-2DKj)X^c^Z zE%uJ`8WP(nwqx?ETa4k-o4p3OjRZL>us6Pg5LkUWNhBe(;Diog>Vpz7;qZ9?08?g# zWW4eklGj7xc|8A;9cS+BYTojZmObgTK-8M{X3?Ha=PH~X2#E9aQ|0dC8`JhbWKg0UZM zI<)T_*5k+#{`xoaY2C}< z{oFmY+hlaz&xH=`Fxn96@`K6bB>%d9Kfih4fbliuzH!yZ{D-yAv$n6k%G&PcKd_Xo z7q0j_9;m(hYRl1><4&aBOcSmEp>N`gITlXLu?!?F}EAcH7h7R5kpDDWUkAa6!3B zN%M^drNrG|7xtdfKV{vJ$u|$c9a4W@ap?GXe)nOoQQar!RlH$Hd3X?;bM}$(sq>Q? z)mPHDkDc~v{(rftJu(AtbV?0L8UwrT!` zg*+4gK=__QpKc-3^GEdezl)~daLf5g$_(3@34xXx*adY@c(%G54fm~?tdKLnR|B^yNH0XBTYd;X-kKtg96ff zu^?6~peVK|_FiI&T|r}_Df+}{)FjrZiN>fgnqp#!Mop|qZ0uhC@0oiSP}e+pUf<8} z|4I<1WQIIYW|}x*{IDO{{MKaS&Q~Ib?!FJQk0sljAl)y#YkaLdJ}ttuc`Y z4vCB&>M#8~^Y)rGf6R#3xac9Bc#+)H4;d01(ce3uq|b_QU`_Fjm4KDCfz~?A`0{z{nlE;qf5vSR!4#rDhSu`E__{TwJL>a!SUW zIlV`P=mvy`57!gvM>_xh%C~--wtCXA6@8Y~s;tMIoDrPo;gug8obP?rBP%c<)1y~b z@bsgjM}9hP@|IT`H7{76JN4*jjQJdlK#WYB;bH+v@x~b`v$a_hOSWasq2*tdOU1$z zsk0gyz4bler1Xh#Zew@^lKkPK1&_Xyj$PtgpaAPE^D=8_l)!M+I$GJ`ZnP(>TzQbt z(JSvS5J^`dY(yB2@xsgc#7*ri{ShWCGmdo7c3)FawC&ZH`Hx$V`LZ%F-z#E5V&6%T zfu4>+ml|n-Z+PsCox|R^ITMmcfbZvg?r>pC9~8NN!yON=ounxZBq-B|jpY*D4ilCd zM>%M?1kcTuPSp{%EByLNqv%{Fy2iVr?yS?luMXSrt zRpqCw{$>91EAyI5=Ua`>88|!A!hY1^zO&C(EO`8O+}Mb)vN+%TXy@>;)=BRXn=kf~ zZr_xQIW#Fbuk_r~knEn5e_V(fc@SOEr}y}%Zn6DzaTPJ>a8M4!RC!30Vlsu|O}5ez z#_nQE<1+E2g^{iQn9!K~U-JRst_tD9lrR4}?`Ld+$_yvgi!Ym(tW3Klw=>>FqwHp<(E}WnrPE@u36!dm2IzDHtw(%5p`5m1^5pN(+|+mwVrtaL0O)jSwR80Ug!WB zczx%j`c{3-E2r%~-u5_4MN2T7rfo;c{lPQ>)U~?7j*Bt0Z28r>Er^S$!bdJnn)PkP zf~VEx-=aO%{QRnKK~&f9v2n5EBEm~;OTU1$DQS?aEDU3_B3{L^I(W*seb88++KHJo!INjKwB0S^dhNE<%q7{d6B zlQ)7~Fy!-w|3h4W0`iv*nXqVR<_u(dQ~sG@CihcX{^rAFg#$z&Y#X)t}vjHa*nNI$Q(066gq$D-rIqtPek2(sJ;&TKKwganoahqu8CUp@!I!mSop2MwYSLu5&?{# zc-&zAjaQnS*f-8if2uu8FETvUf5-t5vFjK_^@W@wY(xs9`7Lrd%QSh)b)IL3be$g2 zxPbO5E8Y_LF5%y+VOtU4FTm3=?{PbM3hd;}b&j%wC|sApCXwAb#lS$ICFlce|H#x< zhjF=K6So$RPjMKqhc+$VIx#GF+=@K|98$&`3!c!jRYjvdn6V+XJIGNK~6{Xg@Gzlx%2@R$nUkM7052& zv6Uw*c z_sk5Iz6lD^^$$s2HKq4czrm4xlFrzS{IoP{R$0KOHlF^SJ!9>IU3%sZ3padAm&Gkx zpEqplfP%IC!z+fk{n#Tjz&F)BZr1LS8Rs{8d4%hk+KS_?p*SREey7ZjLLg^m8gC0u z>v22a$&;teu|mC$`HkIb75JV7k?IB6|A4!C?6o2KHgo$77|0O+6p-LJgUNvck}n)5EJ*L#eQ>0Af~#9b=#qm2`+YQN(tE)U zk=c=*CFcf(h8z}axO^*kp;w5L`6vNg1A`~zmf=eo9F>tT4HZ4a0gBwbhnPADdJ~NG zih9i)qP?wT7aQIN^uAk`J}TWK-P;FplTNhqr#VZ0o?JF4Al^xqd*DDi&tbws$Xy)e zmC)TSGi33hf&F$)ocvypV+7z4k;L!#r4Rq5D ziXyggV?w7*l&*h*P>W4wzC{v9;+y5tZt2apuS-EEL1Zh4ECmr*V^Ux{hc(Z7E4hC7 zuykD;aqa2MU(v%%D9r7H@7`gw=7@Buv~?*%rVlS(thuLTAgTh;j8tfP!%BhuY{8*J zD0Bn40M{ z^b6W!#K$vY`b}Q{#ZafrsYXxI^ncM-AhFQBUVwk4t*GHE++Ai@vU5gs|H(#AF3I}I z{iA2>qy^GnOoo4{ub|d4q!jHD^>J0K3hupn7J8Q5c4l@u=FBD!b!Yi`XXRkP#?})R z%WogS#Oa2~K-93VW+O7AC%Xamd|Wos;aBMm!;EQsvTU#TE$hYV0@74T! zE54WV?=}3p0N;`PdmaCtT^o&l#8k8mrgStb``*aEGirNik7%l}%vND~{Q(ALOPJkS z^Ce92q3&npDG;5VmMFjJdw*Z~+c4cpoa1C@^w*WYq^nNiYy?<*>PE)GlVU#mOQ^Vd zRi#l)N2sbL;yrF^U`n^UY>8qkJUg*rR=4K#1#^S5&Q`#WTKO$#rvAJoKYz>5Qzu`1 zr?Bvyi<8G595d$N*z!YT#vG!(=AKx%@WkA2Y9`J-xnRM`x!<%d*m`Z|%wOLvD0uhR znKQ3#Er2h?#K}j?%8pK+cx){FW8tYqHM72+|J9;JU(KgKf4zvg;o8)8rcX6(FoD7? z$BxjaQfJ9PE@|34vCuq5`c0`b6}3BfI<}ltl&)!aJS=I%o;^P$-5>}9jx;u>;IxBn zN>7odth3{1tuan>%NS4p^DG+#`61+?)R~Cn(k0E~C+x|C*-(#r(C;`G7!8FU#%%iC zojXWTksG3_K1Ea+@WoRisGWFCXlcqLUaKh(THd`Y=doyz$3pd(=RuzWHI{-tfM5;4 zTt!+6?Sv&vWr1^=X(aJD$K=P%W$Ee5GP9PZr!OTfO@CzpilVO~t&njUGUC+d`K zIm&EqkzK@aL74pA~N~-rp!B8{P+nwV)7PM}e6o@uQrh*kPrhE3o(Mirf=s9vn98 zpfv8mgDo3riw(t}RaSmJSV)H8dx#r?ESE9CSy$LYql|lmGUFc9`fO}ij zY^$T9qeT^m>`)*Pv>L6s960|0q*BJQka1XBv0SUjJ3>3L8*n}bcQv^#Psu-b+9FYam+Y5H&$cgQw8xt3FkS55Q_&1#XH;g{=j1rcU zU8d6838TD8tBJyL8e%+vOh^F?Dcu6or;^W< zj^8Yu;b}^qXU+xQbz&mMAGklm`#YZJyBByfxU-tWLGwFKo2Uj0L&>80R@oLoob ztp>z0WiWOCr~+5>H%ve<`EZebqLrNbPihUPj&yN!T{=ucEM3k=?ueandd2bqj`71x zMJrUN$Q?CepK$mUIYs#FA5&NfjEWJ7m4H!eAycEaMR9dqWlOpnD@msnB`z2FTx~A;IF0zFSWJ!zCj~AWk1FOu-xExpA39R zUb*#lOUD*(-+Df8Ic&J_&2t1>M{n{G%SfvlH8SQ2PyO!Sr)kn}x882y*z)aL(r?JR zAEupZVL#Zim6n-*@v~p})zDt}74B{|lAXbT#Qm_?REtYE8aiYVJm?rA|H&o$Z%U!k zL^+eSII(6X{ZPqC5i}t|+#x2)42syXHS$qUqj8!@64-W~%)NIHm9`r;qivKe`FwvM zZZkBcXCw(CZi4k_zgVbHU=D#eUlFy2wR?nqhIM;{{+~n&g?kNaKlw!HzZY1$A?r4A zDgKhzQ2DH|ZU70I`oYAwkSEbaMbXg%2SzKu=~wsf8{>*%A_oqPj42YFNKs7mfC14l zMW86R(iAQW>VefYD~}rG;x&yXnrUR!oO|n5ExloE1Nq;CHS45kh4mbV_bJ%YVj#=@ z_|Beicg5Zs&fHkjZH0eGdoyuiUhKG7_wX*hA>;;4T2c@(KFQt3K^IDHCN9j48yDvu zR-ZHhN%lyhv*&)0>Kou>pVD{c_H1vxQ-|0T$z|^QDZT;DT~hnb+>zxI>eN0q3HARP zY;30lKkjQHJ35<{@lCPMl75ks`nvi%d56;*V&dZb*r|Qod>p+Z1hQi8-a_AKC+Fmh zIeQC(!n)ZfnI=xIOKN)@{wwn_`bS5aM+bpW}B;r+*Tm_ zVVkQK(}8mb5Vj=mhi$G}?F7hO1+rar3BBzKAol=a_Ojiu&21Bg0CHc!*#z6%e(@0? z4;095*ygsWy8`m30{IBGx%bs z#9k~AnsZ|oKY|td8_R^b#J=X9WQ}xHZCl|KaM8#6F=h0Wp%?s?na(#$w7`m?=69=^ zKNk<@OrCfU>t4ot!U!^pRMO){oiv&D`Tl$4UxiZvQx41*{p$0u9$A;qupD_S#l)KJ z$Z7lCcjU|Oz5~BdgtT3${s45)hxNFVKro(}HHDn@@{&dn&%cQ0^{<Y*{^H2OqsHIt@JBM?SL6`v-mq4Y*a;7*p@h2JHl5R)G)T;WUh78 zSy5fFyEG4a*+EK1TU6EF)KsZ&!dJyp6%BFa*#Hkw z%8pP_`E9V_)+vXNIADHu>yF;&%n!ZU4xM=$bfmP|$bDl5ZYgPUw&|cyzd}F!A6n4l z+a^Od4IHy?Bzb+EbnDyl@^6XFx^={c{UzO6S8`xkO3JbWB_#)zCnqmIKyQ@p8I`%B zz%RzPz~7Jk%6}t$L=dy89e;|V?BmZrtRIoNPYa*sTRvLbp1#_QPIn4bxrBeHk z+&gB#+e4e2ZI&12pYP|F?;lpwo!o%8g?41f73v3kv=n5ZonDj3jLamAy_K15icr|#Op6%ysAhzIXg$;)tRxi^JTg`;h3u9-`9(!KeT}eV` z7`$d8c+GKP4{al@B1L$wrH%YUZb)s&yCo$UYw^NPajW_~KLqq(cb2em0xED#Sbb>2iBgl6x^lFwYYqii$}L!9bE!*5-Axoc;M(+4lXV(gmmZ} zklt_XvC7F8#?6{F?);=mVP|e)$1ZK#*>=!qn`H+g@J*Uyhqi5Ov4}Lw3XREB%W~Gs zjOi71pk9qSFkKjWg*P2HM6wECg}3$gw6LY?o|}>DAg3x4-NK0WU#W+hVF^|7DTX(;t2G z)s-o~OkcBxlHh)1<_f7ok|w@JW^g{0!}qchkQvgX;YCHmO|>qw!V^37E$RG1OR~Cz zABYVOV=;NKzih0vY~+#5`li)a=FNy*>k&ZwJlCxoHj4xekAAU{8QT&P>Ym>#q=ZcE zm#HuELwjclyTlvnb4p*rO@rrplG?OkQ6?|hZ&-&=c+UzzGH1-LoH?dKJK4hDD@-32 z(aW#VB#W{a#SmuAoi}sH0C)Fz>EG5sn|By5NHx?Fd z?B9PwVc~}UE>YdOMY*^{ckLD>SQh{)r)?}aPP#?9vQ+*rc=*tHLY(?GmJpA69{d=D zcVyW~8YVZ?Hf*Nc>gJ7bG5qv|6r{~cD0nL~G2b;VJSwHx4^~6g4~m;TB_?DA~yDP zck_TuL3EB#1)0p3yM9h(Mj{(>Z^q$a!w$`yd5HZRn%<*FdT2;S_wE^VPRXHZm4`-* zI8-_9@Q6L3qhe!6g#?d^iyOtB$_k@5NDr+)=5OXFh~Cujv?}iV5pGeD?meTU=?$Tc z;f63g!rd)0!o6oW7WO#6R2mC7)nisXL5Eze# zG+c!?l_7mzn`L}TE{De^fO`zIn;>-XrtEY>4|kM0%aZ_6L^o-0de!B!vddNE&aZ!p zH;o|`=Vs43J5heC3i+oY|2R{AY-;M3bV~seEg^TRFO`*Ds!sptPvpKi@$9VG=PKxd z8e3#x2J*A8b=<(U+P-p=J3E@9y5JU^e2}Wsag!cX1&5ML??y>cJ*^dpgw1UP3yB>^Iv;ki4jTK3z< z5YTceY>}t0WG^dsvufY0S=&~TU(J|$YU0FGQ?r(r_h=1JM@!f8*K($uo;2xn1o6uB z4jJ03y;HNMy;`}B4E4_RQnw|Z89w?^E;ikpv~X(Eb9jhPhNtLHJQ7`7b!gF|eM|j_ zimxV4`l`Ysp}u`N z+{V?WhmQxlgt7+iHanpucH#$)Xiug+Y2;|0aJFIrV0rIjN0HpuOHsoxv$|0_BV(Cg zn}G|`L&`#WCN1gzIZ@Af_0HxsH>ZsK@nGL#kDdeK69)Bas>>9c`TC4n)wkU%XPul6 zN~<3E!?Eh!Id@mtym58v?WkANS|?A5PInIv0KgWR5IpWq8Y|_E_J?hNB!X5J;NsvhOMvDOZ4VCXwdx3v!Nwl? z3I9(WA$@PWD8XjM!H@ujpTQVU`wDd9`1wJBW+$mo2-@ zmchL$pFQR<9Xx5Bnp0bhu&oK==tSej@u$~jWvx9ue%v?fva;5FGcILLa`N2d(2|s% z@Z+5C(N`SRr)FFB+SBFbrx?Pi^77Mbvx#N$+|-nL$%MG4jtIdY=p9ig!X#dWY#Jn< zS^@IwtORG6KkTE(>Wcw?KXEyg@#JBT(`1!2=rp}SZ(T7yHs1gKd)k6pTrt{k3qZIq zoL<5nwKMk%;Ax^6&!&+NE!?O`|K<)K`0E=}?q66?^VhfQ33e0&?X zE?we=`=c1~D29E5Vwg@>Y-P0v3$d<2G03ol=?TfxW73OTX|7$huqhToqM|}VBO-;7 z5sOBYEewryC;o=R#qPoHCxo+NME2pu7$#Vu81RpMMzz2=WDf?RC_EfAoBeQ`nCu&~ zDKm3J$&fW!cqXyQ@Nm6rP^Z3nx6o!^b=WKn>%DYPzomWSmlSzUYO4!u=joUoMBv)wzaX8 zmTua_s)SAzoVd7dvcS$ddC_8ON!{{^>5U)dBHn7l3fh^wD7)DgjbnVH;##-vpBO(q zF}X4(ZAfeF)%?u^L!u%>Ln5Q-RF`+A|{3-90iAwNYwZNOuIebPo)4b;WZSwU6jR zp0g=`OA`mzr~vL0?QLb!O0n@6dM$o#cGp)tx{h&=faVerp}t|PNX>KDV%vru3UYM` z;?x9Qo?a-AylX<4Jaz2iFdH?_xYe!ea)OA`*%0ZyYd`FJgY*!!q~&SpW9hsQXgK_^ zN-CDCgd~ClvuvUkNa8ikcEe#IP)-uJpxK4`*q)>9?tQ zz|hn@CYE(9Al*5&_+0zY(sj=@PrNXU_qP`8itRH41l281BJvo)IpyBcs?5x)(lHw| z(yPV`gpy3+=^m zLK=(_!Ty@srZ`ENNd{qPNUM}-gmpLf5P2$z={Z{RZZL~rG*Dj{9$WGDRf=J2%{3)7 z=Fg2<=lEH6YGLW!DkPaTUqwWSMtxYT3GtFXL2D%m!{}Ye$Zou_m6>Z>C^y?s%l7R0 zX;s-!Yskt;Tf3}j;uB@>73$(PZN!jmODdK*E^Okh@7OhXKSmH)-9vc?Ydk^YqB@{_M(y3r@0(nhIrZQhY#o^aSu{D#^@i zonC3`thKX?a~w3C43NS!6~;qWmKwUTQB#sNhEt1`qcpVSnIJ za!j9tdzXe@3)Sf&u79UizcN}V!CXKVOY3`hd37iKj0@LC7lMu(=9XB{fij^do>pw2 zU@5U;M-kGK`y*^SwQy+J(H3gO6IPef)sUIV$umPp2jfCyb`r+I+wul>a;g-;lc~2X zv#!Bkf;|GcJF|eF+Q(<^;cjJ9>*kKFgO2;Rc5L3dac4`PKfnDwp^0_tMox`dTQ^By zJPt;_mXo_8{NTapWjUFv^aqU#k9N$;>)bgnyTeiN^n$>S;K^(OxDq1s!d+&aCoX5& zqY-&D$`Q!6xvwbdQj>cjLNvv`gvWVjqpUaN~ZmG^yuEAD1|N z=Ok&==TiP4kI_1PvBw}*G1w6%f=@f}(V=KQKF-e1R1nwL`v=;z_wH&V3eto7!`s-j z=xS;A%GkToH@0zQ>8=TM{RYxfXwkM=D^_*-8A+*?tm-m7Q+qW7i{U8l_h12oF%H4J zu?kwF16U6yiPGmZSvpBVg|U-Jr1<_k={O>xQ&k!}=+x{(2AFu!>~-fa4OI;C$Nux@ z_wPUd-GQXEw7yAcslw1p$G*ID`S`I*dnc5QtC%>pYy#%ZhO|(|mr>I)4Y47`q`qmX zVF_epiW#y=ooN4dC|Ds1#*_)JC1V=Udh4kDZ`yNb*(6QJPdqdUNd1A-TC;=qygGk> z9SlZ2nzxQk?J6cuw><=uB(0rO%a7AS49vAI3ytrI3Sf=zUFVU@;#{%09X>i*cI|L5 zDRlPf5FZd2`_rMdn-5$2kIWuG<_TjrNgaB0Z|COiRIh zr)ZMsLGn<7N+K_Evi8;>nwHjD-oTMFL$(eiw~~TG5|SbY4GQcX>F=NLb3yf>;x(DW z(@IAVcwZPAT@mlxvzK!>k9obEoqKe5=u;LJQW6!BWua*@uy^d}P=$Xw>Pyk@oMk&M zn~d$fVc$Z(P@Ap|k#i&8?MLCB92gpx6j%0*G?Z?Zwhw=&uvli*)!oOfyWgDY>fM`u zbZF^4CNX(zFnUfdDsCb;)ZJ0EwnunKkY&cgTr#h!@EX-gA8OAFcrd!f1L=3|<~iFF zXpn(jYBpsyT{ZG#z0{O7^C#&;8X#?N^fk|Fe1e=GCK8RY1_c|5B`pbT?c`aiLBZI5 zkX>uk)+@^7ry-m2$rY098YXFHkxXG|kACaQW*r<7Jub$sgJ1s;|L};hy=Paw zulMK`*1@xjSEwR`8wzXFK*41*>9cpL>Xuk?q~M*w0p2$+N#C|@?%&5bV|ILg)ewD3 zYG`mO#%%D^!suym@{-=Nw6_f!lbky<7Ti4a><2X)hXz%F8HQMjGIcC~S<|0>ELC9C zysF-{+c-%X=KXlZxbl0>iq*&b-9$ypkoOc;4VG&1!^jT@`SlCvQk}I*3=J6;=8@)Sp>0|mp)c|eC<=`j)J$vPm+BcdEM%>( ztBbd{i>ogw^l)_Q)zjI5DWz$`V6@!lb^EybQ;cV{2iXk7_NKB;1SSJ=WZ z@m%h)-C>o|mC4Zyw~Q)fV=5e3_bOSLK^Ds^uN-Z-cW}Gd$ZtIQxTL1in@uylm%NM#BvB?xNsaN>4>xltKnjsdZb7{Q=?_S2N|7r}fnOsz8?276=`QA0TNAq9W1| zcu@qvGRIsgU|2-(Mb#MtJOXjK8U78m59wb*l&pI;be^kQPT7>avijqXtE)fWxhXs% zB0MZIqVZ2(ef9G%Uw(OU^Nh(;XU(26r4rN`sYePasGct)##PVNn|AHmRK4rtO<|Fd zVPR1b0pTPdy7AA)zx?IW@#8;N&z$n=tl3ki%na;Ei`rt=L8Fl~Faz+pN!C2cnJ+DN zf52=9bm{DmSP)5ubP!0`^OVY(r#{F z74ER6FpK50+|4PR3v!mEA-q9k56{r{{%*N%OYhKV>1Ni#q^#E)`woq@v+w2A&eLwj zYHjsGWA_&R<-HR|u@_WP$@Ct0aE-GZQ85~7oG~P3Vajguvvg6jck)_l_lxvph}EakLvls>+2SLX)A&0wZjB+WxW1WJ`!_uWrm!$RTQF9e z&+D5SvNUUcA~{0BU3?;=eLDoU`p^X)^J}csmf3#2N9+48ZW3A&)y*x+&p)P3Ygh7a z^})_PA}SJ6D|;*B;R0H)BadbCqQ=?4zEU?rFxG6yn?V%=gL2jkOrP1e(ecIsjxoKp z?MfqJN#d7#BaidR1>2DP3^buZO5n(<(0t4LK z`~w;X4-NB3_qVWUR;&+Y8fHk?pk@{p{^=fJLxYzDy7vqU>ggUxigm88KHlA3e0fFv zMK1`kvWD59TOi0q13Ruyy@rVcMmD@rYm?^1!y zeeH-4)ik0s(!n`sM3jFx4i?g8CJ=}0jguA~8ANv22Xyi7+s9WI#{@xjZWf}I zqk=jO(+bua#hi@OFtAk=%u&e;GdxXAhW_~84Ay4&5u!tQqalRM_>S)WWBSfmy(-Gr zH!4bpR->xXs&Vuqx<}Tpn0F}G(84xK3u*W`8e!abZskfeZV8E`ACMbtw%0>JqaPSQ zCpW69KwupF@;{`bWdbJu)p69{_yzSR-)z_*{jrg`(HGb5ARh|b&FQekj^VB!2Zq1m z>-KR>Z}LX=(OuACuU14Z*j!Tj2w8g|>o_@U#xpu>kDj_V;ej8!hB?K>CXC!NKfHo; zsMPO1nmyssSmZ0Ky^m)-YnjC)qk;LO#xEhk4?ivVzxWHN3DS8o86J-)9=iaL5P54M zAQvTjq~#;9Wu>Zyx$C6x>mOe1#xB~R&Y-f)zF%Bt*Iv5VzQG}xVek*SDN*V zjP>`AOHZBj4ya73ZHm{{@39~u87x+nx3?|K1sHhtlk9rBw_9Z_E%|G-zqd!H`!!?A zp}vOF1@tfVPnZPepd&DEM+SMsA#)W-41Jxz8xT128bA=$3Xu5PxA9yH>Tnj& zvmCOp0pvW-wWtpAI)yI{=q!E#vP6O8(fKUw32>Gw5GLUTPI*}!WIo-@ah59(9pstE zA+OcpEP!E)m2^cNWG?9Z0?6xikk>)yA|P)lkkLX@`jHyZo;7bOkP_iX`hhqFkhc^F zV*Jq$)mlJSDv)9tLq60*1F}ki^Z;ZWhpc80)@|qjGF=$O4Q&k?+00D^vl_R1$?NTo0myw-to86cBL1(_h^1F{~F5NF4a zf!+xkyiao)EjW#3CN5}~zs%BjO&nIo<(yfJ6$%&VbJ|j~WmzGjr$SOD2d*5Nkz<7- zhYoGKm}Bs9#B043mvn{ju_DJ`FDdQo^>Q?_G$Sc`Bf~(=&CztkZ#BZrUe_kVdz`(| z+Y4cRcw!+gBM^*UY63BJ7$#GJSC!t>wC$$2Xuzp{7bgoKCW6$FKcrjJ~UZ(SAz3lG`|DV+8f2nH> zZI{~H+HM$hPEDZx@(HFZA8I<$-!L8N@wHF1$JKX5Ck?Drd|1mv(NC;0%;)KUYo|Pu zF7f=HVkS=yul++i6``7(UQ3h_r_uf|H&@AUQv)PWyTd}cIh@}KWMARWaY5#s9@@r7s$kX6UC%5(NNNHgLI zOT389XQW#3y70TExu|Ij?F0nzt=_C@&aDLYysOozRCWzk-iCjxn}=p)g@$Bh8e&7T zvO+>LGsz?wk|kcx2ntS54-QU${x?Jm6@L}dnP`o%Na4Fm{7cA2V0}D7&c9cv+d$>` z4&T4??*j3H&{ER^_*hJUUxaTP`CG%jCyKw2FErLj$HIy4LE<_(UGpZsp&sG8o*z^y zUerIt_fezlFb-A>{Y#3cv$7M!SAsG!g7ISv#6Lm785x`GNYjbpA8CPsX$^l4vx*0= zn^HaCvBE1sg$J(+v|D;((%Zf6}_~TG#zC;{g8D0z|=LQW1ywf zFsH?K5EqP}s=xc}Go&bOAs>cRYrc-CSNf@2mD>lHRZI@2M zMxj*vt5dg5KCV;ecIw)xSI;SIcubUh$QQN4MJ;QXCmAYYIBPs_G}MlUZ2^vaFpe-C z-rH!%2w865YjH&0-r#ue(&Q94$xTzKEaLE_IE(aZ#~w8)MO0kw(S-Q8I5uGq|2)5> zF$Zt?zz<8_v>KY*M0#kfYA!m{O6ju^8!|H1k0@D}o`&EH@$u2Iz2gz%@}bxm@liE3 zPsvAbzfJ7&HWr5$Z_LlH8iZeY+sVM>@Z`e6z7;=tb6St7-E0V`rGHaqpaaHQ^ml7N*0t1bS)|K z5XKwkc$AfN)!63^Ds;RTOV81B)%Uzc4Ri>!uxxg>Su1To+nD5J2X?a&^c(F|7yeiJ zjDU&0X33LL&(Z(3N~W)E^#c8mT8~r@P+7?G69`U()y8i0{3a>F^41+2vab)lK+ji8 z5qG6XjDRDxAECelpjdIoOjc+@9G%g_bh!K>=QMsry`|I};=P)dH$)3LzwxB;gz>lE z$jskZs7p{mvHlem3yVjOZ)iKeNQJ0sQ2A$-%6Hb`%~j@Ij8kOh1_fVSXE<32#_Icy z1;u$?)U4(WbA<7%X4E|@XL;SPrr*U@-*ZS#j%gdfE5_0y&|%;xuY1)-S5!TyH~L+v z`j=4GS~sNrWRzyfKTvO_m8n-5yL0LvwceyuyfcB&xSMME^(OM^9c#`9d8X;<<7t(qsI_Ew*29Q}AAvvj?LfU;0C{hjd=b3<;qU@?Pc2+t*{Woo#SAvewXIh$A;OuXJK) zF?Qt>Wy6V%b3jF~A@@=ajk7RRjVG$PO;655{8( zAzJ2!hCs&LCzJW8H5atnBgzUhvdAGwE3Ytt?P8LX9PbHj=sBaSY3&#>*27RLEc6&V z!n8KYO$qvE82wlbMvM}$;BI*AI0%!jPBYTzV(eaZ-*Z%vJ?jZ~n^{^YD;V8_wXfmY zBrG(P*0k*3mi=Y&TCestPs?!>@^nZ zfEyO2L)E;>cUjEQsF<79vxA(U$g#64=JCVq7WU7n8P8O8L40{cM0tE({_>l%XWv|I zSl^)HnbKiW3ZQgEl=q1r7jd`p*Tsvk&Ui)v*-^X8Vyq&|GZPE9kFY1{;LHw>4$p?G zu6lj-J;%a9tn92$t(OJJ&+9WjB4T_Wp@8==x9PL7)Y5Ye*Wejf7cc&`@-7a65JVZ> zsBXoCLU=^g8k)!FXcUc##e~5(bcoMbBPrjlpvvsWw}t5&`0N{jJ~@6X;Ir?>{JRG9 z&T@K9Oy8JV8NH^;cPp&W48NJ_8~E(Ix#=7D?7Id3KB5Z4_Y!=!h7pX(7lxtFzO9w- zRtmn2g5L`1EWa)PzMy&+m)9*&97`y+yFuZC>PtWnT0qOpV_yPt7m#=k!DOXC-UWo^ zYRPh;_Z(CeYLjx0%yoY z@P0&0F+y7%6Sf{bW=K0KY%M%0ynW1&Eo?q!$O73BwHvj+VVpu6Pq8B-v=xRh+ywfD zr9ch8u3=~A?Ctas!am_sjoXtmNEuoir8$B}D3F4VtU2;zlO|^mc0a6>pQ?@0c9YXG zEXgTNHeUZRw?VO9CSYb*HWDD#)5XF{!yqo4@eXZ8nK>a4 zobPejd2lPnyMYrKt|Z$B3O@)x7@Pu=lLP&dlReHi`9rhdN!g(kzkrmK0KXKngWNm&wnk&`Xoq>v5@(fm zI5os3j#S-1^tCbL$xTBy;e&R~Nb`1vq_!8-Db3Mh^-{D{ zb;jfmHO%TCdAP9M%Y>IO5+0v2od3V%)?K_?V_E(ZZuFf~lG97MvGd6`7ELtl92A>u zizWsyLs#Jfy<0KwQ6>ffYHDVe-4oRHFS*JF!upwyRtpON9}rcye2 zm%MLqV^H!gu=sC$0~^7>=rdGRvD!MmmBxw8!Og_q;6~>f%Z=l)!+c&2_BJqk0uEBE zbRk7E_47uFUpi>>Qf;lEdi29v~F;IV&QHByaRX{ozwhmNjo z=pWg)|H#NfhQh+E0RODaKW=ABc{HZ`xUnv-?K`*`jXgTH@8L3bEHe$%3uIOt^Q_IX zz?!ZQgB}oz6`ZJc);`d#!Quj=pB`^m+F8M7Z6$Uy{_unG0xj0RG?pG# zOHUxxYMAXDHBq?B#Ik<5W5gQq*qf8@Idd@iq3CJyR z1|7Y#Fnnp(P$#F*Zur|dtSkFl-_;-xIduu3ikGeSGz*-3J?%6^bQLlUV z%1%lT7{-aRvJ<5F%E7zmB___>J$T6O`3aDki=fqE0qp_-{)w{y{rluU@QjsOl6&Hn zf8r<2AUB{sKgYFSy#j5mgs@VcC_oKBk!O60+lcf17CbeA7d5L#X_6MJm`@C4I zNb{4d3U&=O6_6KM7$lsQY%x8(gITZ!RV{}lz&;H@%Vdp~jRTz}Qv?%-~EcE0?FiP@0 z84Fu!w^Ln0uN&JM{$5A7uUltK#IKqk#P&pzXw9#9O%|~NNF<|X%mra%PA#g35|GBR ziZ+3F4n_Ghso-pEF~wz?=H%1%qM=3<<{0BQ(Cx;=4fH?j6usOaQ>)@~ve+o+GZQ@^cZ|9le;{>Sn4D-O1W{ zt=jdsKa8{J*eY_9+%&GgeOvg{5Kh15-TGM)EPkhnK!eQBWQ1Ht!8fLkud2wBu<(lZ z;Hb_d_nu6>bzSXRC7h9L%NeKJw~^%tYA71zkwt}(i?LxUPy;s9opm|m`nz`xh2r8G z<}!E`*<$Lm=`FeH$MV*5qVBBU)ZAoQ1Y~B}YHw(=>jgyEX|*6%i8w~G6;2yBkb5;3 zMf*17!8&ny%?M%J@4qA4PF1aTlX%)BWKkokRHSInD$=m*7TGUG)v{`2dO!5u(FjNV zVm{OdBxFjes3Q-aE)ZkLXSZrug^as%M_SBsqV=$diz9HlUDtXkji{21HQs8lxnbB( zKahIekv!nJ)}B0&nj6(W{2=`zp0DXfXaD#kqf&cD9D#MBjtUCPT{IQZ=}cDO26WuW zgFQd~D9z_Ie){1DEC+3jW146z3grV<2Q(4_&Z|@`;=D@59&3Z3>LoX%Txp|JyKo_v z{(Mr6-Cq^SBV^%1saC3z@{D6xLLS>Tl4>Bx2^*!{8#kmpAk;2|i1mzcdaCbYo|UtQ zgM<9gfrA4g*^3mHnOe0H|GNk`4v~Ju`9gX51w3ZH?$BXro%H?p<>lYwT%+HA7w<pI zETw{=rViofunJRr59QycbSIV$n-Zn#&BFBp22BHcCj3}hVHTcB|1t|N5HL@gp)(h8 zNX@|)Qh1u0!QVjPb7=;CL>y}lP8tg^%f5(DS|I+cIru9=f?2o&xo8&NoxKNRhQ6Lo zH487NaH27TKZQcGH3NUue0`FI^uAgARaAB>d9HoQ7P`eO{xOQ#!wlcA$QZNmGql<) z`~ux(7JiT3F$Y%%&?{!)fdUro7v)h039|p@bLCQpn6DpoDE-hZ9X-W@XNG<_HJF7* z2oYxCkuRYWWxjpY(ey{NbYcXv{aGDL|1^sqM?WwN?=4_5F;lKSFM%%=aY@V!{t6-6 zEPU%r>Sw#KlZVxRzFlt7-8^#c^YGt=re@)H=tb2VScMdPtc6;rr*K?jHwD-#M*i1H z-twv8qB`D~^Iw*mf12yV)Co^_(4Keh)TsX3n)Hv8zL|Qy&&w+`C~rHqF=Cee|Fxu| z!!cp?G2=J?4+R~yS&ZNOc<29hAs?_pnkoFB=Hc2lai&YW0hzvdC$B(Wa^-z)g#%6I(p_Vu`B&X5e~y%`7~Y%9H8ybW)Yc z^m%xJ(8w&Exq_Qn_(CfC20l;c4O(gze*;x~2W3q}V=C7Xakx2rETZxx_#AyKq8rWP zzan7ZzF0rRfqZKg-knZ23)jvgkgKAFeD~&%+~x0JC%=UqUD9CGco^)+`;NU)_7LPY!S<*ft4>;d?_#4l_rvab&>^d=@U5>w>;{z@RbNDL? zJk|tP@Vmc2$BN^>s=(#DM9H9Yi~IVT&!xIkzj<^i56V@nJ>7TES2yI8??;@DQ8 zeOz4t?C~;O^%{pWo=Z4z@?uY8$3I7WZ#5=xsky>UAyKd9l(=8G5C=_ah|Yg z$gq-vxY*o`pq8C2!v`gH7S@zI9?9b^6MU2 ziNR4Dz{f*DcUY)JJ)At5k9J+80r`%q582i|DZgu1pWw*cfeC#}LT9P(ly&M`6k*x9 zWl%xG-Hn*B1VkO+`U8WB26$S>=hI4In*vt>|b zUQAqJ$?(COCp=5)WfexY4W1QR(x8%reCG+92M;ePjEl+33<613IjDZ6=n$*d%d21g zvS!&b1YDBhi%d;nyzp<>mYETSwGR5o9Tqf&wF2)ofC#J~Ide!hS_~~ylMURiQY3uu zmngpX&W#t7KwL-GT3jY)o@CUeuc%93NV-0o4ky@y+DS^f*5Z6MO`hm)#k7jpJh;;`p~@ ze8@A1!`WD8^mQgW>Oq{22|kF^Vf4pqS-A^{qdL|;9O!#5~=rN{AQiS>o8BhE5hrPcgi+uy`rbA|CInB7?W(ZweInk$Td zJzVC4_MXl0`T7HTS55d0*Cht$_!;Pb$5?ywyC!IF5~;NJT{)fIMd9@1{&oqk@vwf* z@2IeTF5gkHc-#=)0RJ+%E8{ah^>YVD-M5Efsd;zcY}2oeCNyc1in_h-WfitcfeV_t1k0=$+fq{TNXRPU+#zZ zR3FvDIUiI1oFv21jt$mv(3{5jBr|v&KH~#8ABS>2Y!cNXPsjF#!z($x2*@Y$_N{}< za-&`nI6iEXtpBRUaQtZu&iXI5>kR%tHCl#)4i3la;J~k^WASYr{4W#!b95d)1840m z(|>H@`yBntAlV+y`9592tp6)*2sa(UtH zq|CF=z%NsSiH=1pPDjQEoXg{adfv+Ez=qB1Z7j!s9)6h|GtpPC<@gsA{1UV9%jBSm zuX-)#E8|}#hdJM(y8e1kDc5w4Uxa>fiQ}8#Q#gM8{KxfB^cQ*li^e@gdA`KlqKIPCyq9 z)zSP~aSGV$Q0D`zEv@hhUe`FR-JuM>5Th$E>*jI5GmYa(m*I-L98VnZOyhWTa1txy z0lXX$vi3qT$}?HGREKXsE1hyqhrLIe@3A&B>Mxet{mTOM*a>!s1Wb#nQe zB$d+z|0Fv({)4>sH=i)<`ye03v_hGD1pm>))oGy0N`t>pdH+&N!^y7J^7aP6!rIXC z3!~A}Ow-60FW(xiIL`V>rt}%j)zLpA(|^k7Y(cne9shzs9opr$*tZ;J->|oQ#M|tO z(6<`imOAudH4EDoe&n?~M;e8AlplxM?ci;f;Wt|z^LioBPw-&epO<$)eF5iEH(TyA zRP$3_3$D*Y>Q3Qfh`v;PDiz?nR=A$NRLRQAJ1x{JRbRgC4vfKhc{Udov6&@WuvTJb z>9rKy%)=a7#PPBBm|1_Z*0Y(lh^;366;{(rXlq$EulPK{`~eNVpJO;Uyp{Gx$_QZT z_9~oX*R*199wYa7F4h=p8L)CJkb7(-(BmCBT&F)OWHaA*@Ryf+OEwc^InUur$S1z% zWIYbJ0s-Ad3|n-|eaS{$iMJ)3%2R^b*$Ve=h5v%PSX$wnx?KJyK^s|lw7Jb57Jbo$ zx0%CR%Y!+qJbOO^TBoPj}#1$MIa$mFGGui<44q<*mHT;Xf+w z%jI8#-xLPw@u;?PJaYM)f{X_mExadKZ`}YM^w!s`UtWc>c`Mr?y3uHgTG)G~mK~-Un5n*`8xzJ9Jhas{nYa(AM_6d@G!n=dyvxMZpH;nOyu> z_gz|>_e@5}?-wb+K{;OCdnR)jJ^mhTlo&NGiP%ckL7%^bww7ge%j9+Ab>NbN(O_^H z_XNg!S)Fw}S;uwR+7$M3i85C%ukhd!rLLt($0eU~xSmU5CbqF20l&hDwXKD5$qddV zS$PK;{*p_!?8oY85#|K%#S4Zt@@S819IGoXWX)$7S;&>m{wLH;rPgxTE$Xm^! zeAUR%m#e0dj}wEkRf9YN=ux>eTQzcN{i*@xHaPUFhC$h?k;^`BU5{-s>v=V5ty?vx zIK@^ttF@Y~8o4I=RWl7U>|b`s|83_9E9OI4)07f*Es`~QXK23ROwLRFWVlY#90Hx{ z41+6!bme<;nFYGKou8i$K8eHmPK}i(l{&b*gG&b8297^c2bXu8j=+=3;Tj!0MlTbU zJvcl-2hY&cRegf{vFxQmfIBEYRd$l!69fJp*#A{?jRMyx<+FVj%421436IsUI?A9d zvlJg+nWu%f{3>4M@P~5gb!;7Brb{&(3ac{1fwUz$Imw`0PTIE%Cj1?jmNAfWIqV&; zCB8VL#}mz=l8ooE4ywGSe1V&=4FPo!4obfG$>!W)K10!7Wft!da3~JXVl8gj*U}{G zP!jwU7+lt&=}A= z3;q=zGC0G<;a|K8$EZCdev(|?!Qh-QLw?V0ZHKuG3Mjdu^ZUf571kp2pg&|uLM$P@ z!^wZx?b+0gxX?=|9E+J^1?#Cb%bgLTccJ!{o!QmaNNAx;;s`4(oCo2Kzp!6+Ncdon z!M;A(8iD>O%(y0&8;HrePTgKW#H0(1{)= z;q=or%gG>m)+r=BMqEn#<(`yET6+dP$$Eyvub?NJROl=8&=t9l#gFl3H2Ufte4#Qp z_a9brH2PeA{z86c?ikA2#lt9S^0v~;O%4si#7sTJALiw?^s6j@N|q9WO>|8<`ED1HAYDH z3iZAzkF9jmutL?9^*H+TCd4sDUH++5;V1f8Jzu)XW`T55_3&Rxq690+O3)}67^lg& zXq1c#KY0lnCHER@0p`n(oVutkE zIbm~zf7I9i`1cpj3CF2US+hokl*&db?Fu$ETTy-kl+Rv4`Lb$=EN44Ytf>aSTe zisMp+vr5r7U%|tw_NNYy8Jc)m-LbWa>}CKR9&x4igJ8Kv9TB$ooel@C6%#MRW~_#_ z7|lb+WvOO}CI))}X_B!jvXmGgwQF0f4*J?5Db)a?-c3}>4^N(~e~kZ7Y!mWaWgsp? z7ih^Y4Eg6eZf)RPo~x>twXjtjJ=8rqz^kjAt4e#4sDN0y*4wFO%U@$ zgl0?jhLFArwP9x>`?l)g4hCPeT!pyeU*IQE;0-wmH3O=!jrPq}m(AbsgPD;9N4gSJAvG^vOxvMaxOV83=r5F;5ouj=|wEtQD=b zHRH84W3>gJng$WTG8Gu(*p+E!$o$osFT+6>m1ko!O}wJbZa&a5e}2n>=H|iU0_RO@ zR$gqT7plHowD8jSzk)^tW=#eaU^7A%PRU-8#;A~AlppZE0!`(+GCT#kSi2EFG1}um z`#a_5GVOepokPx(!Ey}|+(j(s%8Hg>1Vd6LRi|5m)`H#(*aC!d13)RG~ zxv4KXJ}E13L=foz8y&(+No&tu4SwV0s5@;HOBih>I_F!fD{ItS`xV-HnH;`@G&Qdw; zy8hA3p*wzFu#Z06R+>INYWUt!b%*kQAWPd5Bue%)ZoiJUY+LwfZ{ET`(R5Ca9Tpn) zViU!vLGc*U4mTK~9&U0yic~BZj~(}SM%s9NH83mWfnuYBqTA?$eG7ixIb_!3b+n6A zt~DXs){T5CH?E-|eSW&KbmLzO^7cMjxQ&o??TyKo*J(?8TJb~vp}J9fheu6M$0V$y zanePo^W9hmnN%NNTi$X`#=1>Jt7M0~U98h3wZ6>H$B4KgYJ6=}S%3P)f1kTxMD_H%^0Ux&q>Eh^G_|E{nLBPJ~*V#-#=+P zZTh(0>JO{jSqCaA3fLNId8C2|4%X18d<_{1K70)UZm^ZX`T4Gz7)jGPd^T1QvWqY{ zww!9Ch2*UExs1oinZsRWJh&^IsjY=HS9J#sHb-WDPjDg=HmLT9dGxU}=OeE{0I?D| z|9Bsm+p+%VfxUK6ca$b}N*k9=S7)sMb9WZ;BhedYBu%y@&h)aww1_#IqUhP|y?<|* z{_T45h<-~?lWAg^HrY2fVAxTj+*T}!l@J5(G7LS?G2`_myTneny>&KwiUA` z>KlI%k3uqWU-SIAFZO7U5l>5A`bkzB)Z>X@iv4Q5{n z(jv01fi};Qg0StBe7URK8yI=k5lE|{l7#JV(dK2uo6MRub2+EJ}7is^_*JL?u zHmm)4r+A~;diH_^vxOlUp_25>(D34?+O0e8)uQ6V=w{_E+_WPid55*UZ$RLYoTEss zwsyc4QVxIS(cHv*7*i|-x82WYCM_L4oLUi5kW{YmDNlJ$KNDNDPf4U;t{iplTv5>{ zi^uO6)kpIu@g5c&R^Zd*KsSpInr%9O)H=+nKhSUR@n;jgi1n4JhGj)!Y!^>DK4Yh` zcnuaPD9>Sle^(C6eZQgdtsLUu6y-Lgtgm*&aFTbjal+O#;^-LFFDB2|LMvT*(GPdk ztb8(W@F&|Oho!X6(N|9 zt)i2$Nyr&nOEiV=$1T{r)C*JxA08Yp+3?P1LD)#a$-K*ib(Xv7qQ;iDEZ>66K|sJM z%bJCYsx7PM&tKdlu_`DqWcH_{mb55#^w`m|xcv02&;fx};+nEAmaX}=YRr|@%g>Me zep1cYT2fnEJ+Y}vbVO*B@e`7>XUe=?i3z*rPuZJIo)|}kMn-i(UnGHV3_#s`D6Ck` zS#Z9tJ6idk9LmquJ^8#eJ-biOtehcvgkGKe?VQ~YCr)^{H=mf$Go+a$%uZe(GB0mr z;>^<(Z~VP>{p!D#G*JnzYl0#N3wa-(crbnC6Vc01uqIwo2HoI&TQJlXBQS5LU~pS{ zg9IU6DuOtb7qR@0V426tObt?7O}Yvlz`Tf}9v!|x`H>vDtHG+5-Mug;hdu0jFt~kAMX58wlW7F1Lo<8s} zvHO0m`EQ-m8@^szHgr~mcR_gkxWQO416v*`zt=UPD<_RGV^Jh(8$$F-i*Eh$iz684 zNH3UqB;OhQ78XE?i}0wO?}ham$)AItKvvFT=sT#S62Ufw9rRuC?* z*Ku%@Y4wk`jr#HHY^TkqKEsm*;cH2lN?X9y~O;s61PbBX=ZF!*W0 zcFAv2v4IkaZD6YeW~jJ)ycj!ETW2{)QfAggE2o z!n6>Zo&i$+iY@^??SfN60#lvMdo~>C8|4%;sk$zzxIwhtKVWEJ{l~L{X3q?qFzFJp z?$l%0(xUv)Zg$J|cenGZEgdpHx2H+(OOwY3&YT}P^@GWQLojwjX@um88iV79qk`70 ztXHpOSnJ1&bx=-ni9jqTUzob*c2(8w-SaNg(ECDOPEJ&*?6!kA7G$Rncg_zn?qQNv>_+E4 zGp$p%;sF4-I7H|-1 z2SpQe#X%#>R~^%57iL-ebXH(+!1qy4q06cpLCbv>Ma)=Y=8+LPxLheDG%qGZy1Db= z#94otjZWPX?7MN1L*V#)|B8x^rzaDESgoYZZ#t}cwiq_<NVn+mC=Rp@q5kE6L# zn#v2Bk0M+i0CWqeSt`|b{RH$1n`;38I>>3KRTe@6agGji^ym}kc<_w& zSMZUl_eYO@ziP~}O0qs6lVtV}O(%oJ2P>M2(vl7D8>laQBCV@+-QN6I6EKd=6>{ zJ6UD41gg}^6Aek?&gOdye9PkE%l(7LCi=qpnf}&o_W7y1{+K!Q7vXHms6iGh1QKIv z?cr!@Z{lf_Xc5(LaenW{lM|BD>%$`^CeF;A7S=n!#UZ~Tabb&M?=DK0G)FHkwfw-V zZb^`#^6k!DQU4*hhVC>wUrxrpbxO1OgE|$rYLIMl?E|GM@zrUh|Mh0=? zR;1?co)L>VnSr*PLjC%%`f;s6-tJ&6ke3-F*>;C*MjN-%mSy>$ucf2JM{tmjUq5tO zXzc01}T4c zw+H<8ze;b+j;~DgHSO%|iH?BnR>cx~xIs^7RZ5X6lWR^6ZT9O*{kZ9`Vz&`GFFKM= zoPz@eMb^-W=#!f^RbN;%>(g;2^qFyfa!h_m>}OlnRbJbiv3Qy`fOU`o2`d zn55Kk<<_$#bEcBpa5e1cgtQzR(mOjlxkQ3QnDkZs-rH5A>ZhF(NN@U$;FY>4BPU@| zW_nc3!NMhftu>Y*=@tl5`gXhqxsT z9j&b)eVzS1`lnAHCYWpQM-0}u2Nfm{TRFI5=ivT>dIpFgSFWIUStDJQcVSnENAIfJ zl2Uo!HtFrl_FcUYxi0P8A_lxA)BXY8)i7 zn46Q6-IMgp4yNCTUp*m9pRb+2`Z;9p^te&^4dL@+7Uv3rR*TRe(30z*=*f3B%%Ft1 z+bVwbV%{7XhS&jukW*an4l5fQdQ0Y!9gFTCJuum5-`WTCO#HRLiA#oLjc6lO z?YU4zAGZ{1S&|p5U*;%--*~qB5Ht>FYYtw7B}*mS=w-={s_47QUBtHo{puEZS4wI+ zASG#wuagg&4v>$RYj>hi-J#h9;&uj+i$@1LFjmQm46} z&u+4nQaydW+qF~OZr34Ta&hwlUq535)eWPL0aJ>J>&T1MRhP=NpP^ESWl*MK`iN}h zq@rEQf65F?$P9rc)rVR$jr5?m$rpV_hDDDK3am~&KvK0!#oL4yuRS}AkR>f|&HOF~ zX@iEWw{r;?6(2Lw|1v3P_t#f6v%N|E`<06?)h2|2EYua{LJY7S)A);U9Vxn$6JYbH zv)mshcCDrw2r_~aY7;vls&8l);_NVHYxT}sV@BWEGjhjxYkIlMAdkUWRt`hN74-6B z5`E3mf|SsV0fqgS{Jpxz4k9g&sqmvm%!s0UFQh%|F?d0$IOByv+LuqPm!djv!iI1h z)#=VM1B95rw8Z(qpxy}$ho%Vy#+GN(;v&PQk6?m#FFQ-zfAE{3){%Y@!@mFK^tf%s zZlv@K>2v%z>2tQky?E=m)8AYpc@h4RRztp#%AbsRuQGN*#H5ucwqTQgFTL?dUgP7v zL!Ueuy7zHo-jT+1(uJtDoLDhAVnS@?dt)F%_%cTgAxl$b&hlTlDVF3=Vkx+%`)6eJ zBE7S+@`i}ur!^Pm?F2uqzP)4S1>E809%Y~1m~4}bFLidGIVmRl~v4?p$NF$D+m#!aojk6X_U3$f5(@VtVhhxrhR)UFZ z@5I4U|0`EWhvp8UUPkT3A39iPZz-pHq?N}{wKKS_l%gXwO%vZc)lPj|QpOHK?U*m+ z`^xJ)3qAG`SdUzN(QySIf?8YZs%S2&3MTuAgHM2IKNCBbA^o-=B2-(l_T58nNxdvQ zyMzXS2dM{WB=Kguc3YN{K1&w<*8bhYW?aOSgSq(^cMjRNAcZ(crK!1@!!pB? zhtN~x%ML=`gZE5(6EgVCu_NBfcTAm{Y3!#-3=2u>C8R%i0NUMQKv}}sD&l%l|6%cj z;9^9rZ=U{<^cYTJmV8-J@#PZj@5JTD#GykI>AOPI2(poG&)YS2^zJ+{Av^bZw!4IU1aYs-eQ|5>!)Y)w1*)F?kC zrXVcl?B)#Hx<|VAP z*i4r$p<67rv@BiP@~%bQf(3OJljqKxm|PPaGob#X$~Uwdd#tC+Do#!A9~oGaD9+D2 zy>8v5^72b-*PqV2G^MhlzP_?z$`i+&_|y!uTV&|bIctxnkd$LDE2aZ&v6f3ze2fAj*@#bmJ4 zPG}>)z$;a57Oy|YVO59vyRMrBe*ChIyEK9n0aam2j`t0dGoXC zy?NV46=#=~7M`PQ$I6tW2<%u@(rqZF5_?wSj!MjSrYxC&dxK{XY{rNe%x6AKRw%z| zen$+{dY%%#JXO|oU?si$^yyRKgXXkD;_hF5A=TUlZNM_Si@zujVoZ#{5zWCbtiZh? zlR`|r)bQ{ywX_kLw}||kgZQsdlHAy6wYu6U$6&!WVQAL*Hy1=MGp=23wdvo%l0^1x zr$dAoI(QTQ$sjwm@9+n*Wygz0WY;#94VY$c!9O`T9|RAggEx>jx1oE%#DpghGW-gW zeB3S7R+MO1C)|T{_~E!yl9goAw?{(ub#0oo;`k@+)OVH2=qUGN$IzRzTJA~j!91*z zM#EqMj)C4B$a_0nU1EQf1Djls`SEMffL>A-y!-BG)@{7&aPJuy&2p79XX^ZT zkExZfT9ext2VhPv+CF^BPpij&ydbvp1Tok+tnl3>={|+wp?O}OdTa8Ut5s=hF3lKt zh)xM`8b|3>y7Ldhs%GR#RgAx`_WDH6_IHqm!>xv^XW$6kTxC%U%&q9n1i$5@Nh}`+N{gqmBZ=c zji2U#;$fUZZ30D!+kDt86>&EVmvW5JNbD9QDEKnxCpWMhEIUo^IIws{>B5f-%fF(R zPIg)QbgolwQewUvOgDJOT7@QYtNk z2BEuu0h=-rn!1-tP>akXsv9XMjbt2sdwMr_x31xKgZfMf7KXCT8QER(?(q?8=?}AM z`h{D!FnJjptK!N?>q29!iv7XWZSSVi%i>@3vTy+WX%pMrvA>vYjN3iKZ{SK}aqbAy zvkfl8focg=5^eQ@Ujz6Ps}#oE+@y}2-e_Xgql0?~^X^C}DJ9WCzH=JpYJBG`o}(e}qr&@rW-ohV(D08BCD3HDKk3Lv!-C&fKG&Bf zqY_Yf#1>RS4RwdPnBbIx)X)v$Bf3c}KxX9)C^Lq}iKS#d9~fr#(whjlFNV%I%+xJ; zMv%{@y;n#I_SKBrmLa@BqmrXCQfjmOi|uM0-z4)#94PBO{#aST!EuFaO+sSoi+c|p z)6b>ehb0YI(ejw!I98=nF5yN>crlV$N`5Ut2#iZ)))D2g7ZFOv>-K_SRw|Fd&uHv* zm^2K>vUp2u!?yrlC&M99czhc!0%hBA`<7mi235$Dn+3V>(t@QZLfTyq-35*;1uwhE zQM&V^Hu=W}`uSq%^kVvDqj=+nHto8&w2_`~tglyk)xStk9^`+|>z^>C%7jJYFm4_L zKM%1n^}?nAS18JC?B$g^!n8ks_=`@Yjn`I(ga!rQ`f=pCwDgTqAgOA;F4|~U5^onr z&ATbnW8)@818V|F5sm|^F+>=)RI&!7JER5|Ry~^K2X!4V;>VQ*KYm7rshmp`aKB>>mO;Qe9-)+SY24_ zEh)uQN~JHgk*W?9Hg2Ix@=j5fFI({gg&9IS-Y`r;UBi5IC+!-v$Y!9KhgITWPZByd z*39bu_j}O*wNZAeSaqOC`LwOh8rEJWgq#v}W+!YWQl>VCeu?waCYZJ`Q+NUH zRD<=VP^<0{IWl<~{g8bKqZo&`8^|2qF@rvq5$fQocBPHX-wjw0{jnTz0UkOma=b5t zvpfhYslDuvg0ETJu}T+V$D%`)AueBqZ1D`wAe3hw94fMwKf`ka(IAb$3+n;w^NTS9 zndc^=Q1FLr(P|G?VS&(Ma8aOxs_$@yCJxYd?*6l;;mGBmG9?4#R7Mco#ntTXogy##`)DyKI6sq&y# zO@cE=4jj27KYz!_fU=CBPQ<0h*lk~o`IXF4w2pRm#uO#DW@Z=*TSLbQKdhcVd;mE!Vj7dN>uomrgoSb>g zij{w94+sP|9kio+p15RrMtGz--|vWv%N%hX0{$}1N4T(%gr7P^-C!d}^4KakF zRe#8ltI;QHMWZ$FzAAfxfJwX!2*Vm87T~5ce5rP+t6MwB(CyLGa z!k*uMhb%zb4Sv(rhFNUwA*9#|1m_9=RwLHYOy<2>GvU_jRcjtiJO+sS{Qs?j=foNR ztRNqph=&hxQ1EY6Wu9BXl9Rd)g3Lz&SJ+g&(-6PoOtu1;dRfV~by=5$jfQWAy|{TB z{c2;XcSZjWUe!+~PkOL@2PjB6WD=C_F4TMB6bqr;GA!qwN|Q^F#U8Xgi|?EZPn-OUIYN1euMEEq!86tl6E0 zHei1mYXUO8=!S8{LffiBxgmiB8Qi>|t0@9omvy}PTo z<7HtNPR0g{BYzeXnnEi|G@6o%(5B{(zi)0N{{1r&-QAKh`qMKYpMh#;BYnOt8@M89 z<*lst6@Oi*=o&9$Q3+jAcz67@-NW~jz8}UYEs3UnOR##CDx}I7psHE z?j({x9B1deO%z+dC*E5^r@l8Xs@P}v`?Ka8&-cm?FFY_iZnjXaU54@fSK$CS`ctgI zNwd9lhxN1Sp5ib4_=+_wo>YcI$}VK^mM5%y8+d+8RZFOhN2+1*z|tc=UW*kU%6K4G zW&9kjy06&Z3SZ0V0wb61arg<{8dmvPP;2eDM}^*u2TKKb)Jx$hOG^i6+Cta*V@1R% zBLT{j?cjt&oSPOMtDk%zU!A4O+izC-LA~&yHafGUBvUxr`ZKuxgVLf8rcZyr81tbH z-U9LP7GRns28W49&Jg?XF_MoZ+WJ)E-~vb2(!S<}W%P=8Yv=DXWZ|+8ATf(_r$q!mMM*$T_}uShIwX9lMCoIO2n;nl!h>C~R=@MG-nEHv_^ljk6+V{WFKBnJ9`Cf8|{vZ)pp?B0_7dt!qNVeYAz- z&F>13aga=EI&djcLr%JfhPt05zEPL3shFYd3ndHVteVXUuo#}6OdpYnpkKKR_*Y`e z+~>I<_V*ved9mQN**hY1oR#&skZ^D9aPsEWf@d;GzPZXgaf0q>LtGR2l6Wa*Kije~ zX{?u#KHj#l&Pr$%-y1?iqJ>`nkVK_Kd5^^1B}#h7ZRj9+IC!YnBhsBd!mVH7#I0vQ zSLDeFqKQ-?njE}y?%bV&hhnpx?6Q&$krqnG0^w8by8IF$R~sORAAgJyMn9O9yig2{-DhuA19x?`C zv|O=+mu5~)Lm6C7QUgIK3l<16w%>(%KbnSh9JdRHbO+1Ak`3SxVOL{gM5R-#Pdymk^KT4LBb0A#W_?s#k!Y} zK$=f*3EzqFZV3(}9b(*S$)lx9shP0pqA-0|%BHxuO)0yybr-ZnXOlO^#B5AH3$k%I zLd)h{x+erEmL&{}OoslGKZ|O5Yub)yoGV|Qs;0LMd@}-~M-2!V6?0j8S#W;zZ+w{T z)X*^Ii*LxSI^5~g+GLt|Q=2U8*Cu02O3PkoKR~;u(RdbvhJu|~I?oUjC=k%-9oVKx z#NmMhyZnz7xD6={A)`o*c0pH|20UTm+4}SQ)c>R~oWzp83G?PAAa1}(-At7iX(^qx zTzi?uuOK~z&3BqvT1&0~A$*1lLfDe5d%>p0EfTQTKuKvEIdggbPuq)(iBJ3f85P0f z4&>(_s12?h?B9-_Ga0q(`>AJ0|D*5F)8=W*KO7ZU5N2C-edGG;<7@^M1Wq|UKk6O2 z^S58=u6Hnp^qXFt5~}>3oEMS+*VP4U?{mxnq!=Z$I2_EBClgT_!u=ZMu=1r}*;*8r zqZ|(2@&33pm?_DyGo=WtXbpwjgMl4gg;?k`%B>pzjmA*ZRbc+Z|ankxB?C+C4qB1LfhvYu4`;z9kJ=PJJUiyQi-lUbr%?o5vs*$IL~AK8q>c zy^FRiW)lxI!H-~2g#iH^7)L{}ZGzW|trHMR7dz zdxo~Ys1KZjM<%*PYU~V1mkz1ZcaxnlKCGxu3=M%t=&s#FSnN}{DAUnpkVm()m4(As zrg!&@?CX@(P~wY9={w?IDut=?zq-YhQSpt5arl4e9v{r>ito_egc!xE~a3Ea6xiNYPxt$fLFVG9Qvc%z4WbcP;= zPfgPu;vA{mOT6IOA<~5DSXf8aYIkz6`Sv|>RGW{^SPzr;5gf4gWta1Yw4P#vJ@|BD z<_!I@cB_9bvv|TFkCWF{69`{e!fy*cub6my(}7BvE0zql8~#a09aRK$+1z%;H!g};SC1}=*%`z?>IfJYOXR?HyJ4TIRBa7P8b z#a_*iZUP1Ae7oq}Fq@i-z*A&t3 zg{hgrf37awdS zHj^jOTdPlEk2?F=))QA}H6*Vr9lY-&RILi$RBLh6z+5^Uz@{-T9K=@pH9ul9A?)zQ zM58mSLT_#sp4`)ZQ9aZcpC33 z376D{e)&_QwU6l^1B&Xy1dH#r?PD~8c*#%=vg@d=bOaT!fD03B79lohGyJ(Q(=5$Z zU<18G0v!zyjb1cy$8R1n(AGQMLP~z@k`r5VeEOiDRo2P%nIl)^y3oe5{YwU#xLT8m z4|eRhUpMN)S82mth*LpkdZDxHaB6GUw^zsR6Tcv~AN$$(&--j%QfD*&)M|1jW>uB7 zQ}0e@2Z+(~xxa4gz4-3T$FUP5dne6JNt~0`JEATYt0cDNH*q=!m>&ceVRKxB^#IVRYTmX;JVSgp#i|Y0US!w!3mBwju z!DjTk0FM}~(6!W({Ma&|^Cqx-7GZ4x>C2ojNY1cfKbZG1v@q!&OD&7Cj_k1NLC745 zX}-G8R4T*UKqD$Lgo$Fc>PznW!EE!bUCs|Vi!b5FwX$QRao*vExpNy1FPTd$*x}0S zMjbqh_n47}8F{ez`BWc#iT>@`3U`pMrg56|j(93L~f<9p>LeK|uUPX!$YXLJDP^)TY^fuCm?P_ZCX;L+RzLO(y-VfH zN{bg!KbEMeMu)ACmq%|KAV`(H2b{e>%6=Lxl(x&ysw;AN)oFcsqdos;d3?{xGkgXx zCb2dfVEpAas}}vE_BV93N9?pz!fSuy1uKm{Rz+}XH)L#5ql`_O%CX_SLGeG{v)bc5 zqpmuDpP;VV$jjGZwAd8^D&a@|tkdl99K)Yu5&AV1vqdGO%ZblGpCz?a@uZeSu?W&9 z0lvJ}%vde^CF;+$W#@Jl-ierMCeIs*YrDo-^@{^S->6$Kt3Cau)5501r%Bh9%jko% z`*HI#xifp_=&u^4FZps*!;B?A&)rQ=Uzv7=e!6SMZ7}P%=qhCi7LDwoC+i3hGQP4p zV`(j)@OHo4&Z>{E`_BUyXLo-qgHWECJg>_o=?cS*wKfDjmSKh$%t? zK?4pw@b1VKd`Dc@7K$h7x8g_I;v40HpIEDXk6sW~iQQgkm16TP?MUJ-M1qfIlMB)( zVlJDAAvWyD2^$xjl`}~#ee$1?Z&S{H<1ja zq`6Bzrh%l}4jPDWVrUm}l2F4t0wd_a-PXlP+O_9};r(gzO5!J|n@uXjr%i8?wMS_u zbhD?lPPG)aCKC|p2dxwvcn4ow?gwnCaxQ-OqJG-nH-?T+B?{uZ?GOoh9wDvsiL$qg z@-9l97#21$6>E06U`d{c6$oWQRw==mLEszkgbY%t7zEGO%HPFbRNqNzl~Q4?`c9!z zyrl?Io>BJVRW-#}xiAHkU0%jL?e*I&XvMhdUEX@(cd^ayZQ+9AZP9k$zUJ@W7Ok6R z4~dP<$&QO1f=e^9@oP?OY&Isa{W*ZnJ+`@jab#ExReDOAMT!y2#PKC0^RMS*#E8bL^sLTrLMGP6vGuf+VB*+r$y z)yLKp9O)GzndeC8oxsu(y6W#g>CTezi9Zsr^PkgmHxu-POG^Xq&<|9mB&IH|&^I@` ze_?W6_;c~KdbH3bl0Or$D#JpsTGXbbS&0UYBj=Q>#ko*6vBP0I8a|(7w<8{6r?jmZ zaHwp^#-$B0aTEMX!`~Z~vbu48Smb!I*D=5Rfk^|roKN*n8;~@>n|GH5@2*Zb6M$1X z^VDu_8v2Wb-3=;@xIlm1_Ka>X9UuP#@vUaHwheR57+91zF$xRkl)^}QB-ys|1s+Pu z=NHa}Ma(tnQPUO4=~r#%9l~R}`{CXl!jrei<_FqS!sD%46VbcrE<#D2w+K(SqWkYt zE3rX+5H_-XOu{Jl!N-Qp?fK-M=q_BARLZxxrS6qy3{rbKOgxG&7{<&fWFfNnrdQh6kI0WBIlXg3iYD9 zM4KiTr;Jb&C$HWo=JgA4>1=LoWzjux(3~TEG%hBg8BQ34IgrkuDFd0`QHY2DQ_;rM zPNU?1z3?oiUnVXw^z!jTcj)?Z#r89r?9jdh{cFwWHD<$8V5Zl}w`W5lmbGMpQ-`!2mzd;_{h@Y3;BX(iV zlO=zy?y>r>MsoV=uYtKp2oj5x0Xi0I3J)O0WlhQ6ur1%vJD<^8->x4d1d&j3Oe+b^ zG=iSMN4tb*@m;0A{81`A^_4i*S1Naj#?+sjY5t8wk~8A`HN^azb#y8*TN}3W^^ZdA z?BFKrV`pbBzDwVu{-QCyIzuAG`9bTxp%1CurIlf8|4}`DIK<9^gr!@;HjwVkEu`nV zLF-Y!<0ORF?<5V!SIZP@gnA)Fo^H%k%Y@!C@{sO0MHU@C{5yGzW}(;w?RUcRmUne+ zN7^$>8x70H7IJoFrCVIT$`z-z-@$M1(YbR-BWH~9azph{l!e7PyvatqX^3%j-HDoBYx_V0ha{i)2M*bCy-bi&zDZk10f`;Fqw zKTGcu%d=>{pr}EAt#0{9KkNuCR@(VkDr*E=%JuIZh0Tv94b2BHtKx3*clJ3 z3A#Nawv2^QHR0hkQS!h2LW14gfg@P9$9NKQ8AH*h-pYiEbESZ!e}sst?^gbLJNF96s~?mpYGdt zj?N(y*k2j7=%c3}g6YM+5Ph`2YCfbt?caZ!jv{XW;hS*8Jb?o)9qMpa5Vk8Y8I5>C zTYU5eow!7>yg|>dbUc3i0-c#aFOq&yz%MW10J(j&s5Wyf*(pE1fxLKce3>MZ{NFvbDt#FoMJyq!QxVO;oJyOJk!}cZhA5Z&Vd7EB-~Zm znJ_L<=jIsLdl2i&-Hn*iX#tO36EB!^qWz=e!lDvJGi1&w;z7gyjQiDSo7Uz>nKmP!iW>d6<=C-(xwzAJO+(< zbdPd6+%x1AfPwNdnfFxe{*>+^KWeqq3a9_WT3VDlvFN(;FkU;HdSiOGu}0~4l(1qV z>JlhS*>(><`5|OXx?dM+&$p|bD-ydEXOo!dSFWNT!E_I;w_wSQw_wQp=N5HBA>k?O0ZT`vL^g0gf zb;jx&s z^7gW~atpLJ%}7cuo;h9Vd(Y0HXHODaQdDr$EvS2!=tr5JR$Y2~n8(`1=ftJvDoAsk zw1v)4{m7%JF|D}el@SInf@N4|0c18t(ABQUst*eqpE7Y44Z!_s9-jR@qJmw*E#tdY zNLxsBU3BNvX)(*|LQ2}Zcn=Bd91`EFSEfy{LeRQP2er4=N6^V^Qvy~bH&1Sg_S(kw zo{ml!Ja=bD57kxX*0|8dwQnDreyn>&qk;{nUJI!nysJMzHZ~DiS27Q)n^8`56R9BX&-`Iv(2-RjCj22DkP>E zs}{Jl2zOyDP#^rxEvwqgTjr^KN#&@)r5jxBLp+tfWUKaDq7bTAmDQ4Dy5G}10i8G% zb*x1lVJgBFm31Np&k|O6wp-;EY}SJ~de+X%tnEK@*67J(Mc;l-eLI=BI$_7Wg3LoL zW2Pn;*KDcFwb8gn*c&@WxH$F6tWt>0wbC{^U3~_%H07hj>WQs}o{G7#fPT=0urXTN zAGa*nR5q?=WO0eHp-*;qZ-2G2zmKn%htfq@*Zi;p**M;4%G#B+ed5MP)DIfq7aEa0 z$Vk^82kCfFLhz?NOs2Zq4>4lAEn1rm^PI;FPanC(pv)trZL@`1kGHvc(`*CZ%JRWwo17d%yh*BtlvfTO zA#8MX40TrxMhuiAeNnxtd^~-J#CW^K2Ue{aHJ%#XW*E|5ud zPwFO3CredFj~=P%svpOVn@zqI;^ z3A0PVU#AlnJ4ZX^$btgjEFUXZTSwh54jA_zpeK8PjdjE^cqH(@#>gCAvM_xJF;)rr zKUt0w=W(;khtF&fvc0?=tXxBtR^~&JQi^6wB}G|N2L+E$n>d{gfY##fIiO!upkqYW zgl=P%Unbh?Szl~Fnd|jRa86)ckG@Hw>S9`Xm9tN7NaxVF?$()hfeNYVJlf%>YlpW2 zr#B%wKIp)M=#WnK-&?{~qF|;>A+w%^wkts^95#^I<%KgB3)$XYXhv|m9%e&0 zn0){g1s|* zNmsAff!+~iDK@#&zz>>V(qt0#|Bb4h(!uV3QzqVYw-d?uKP%vWB;Y96_Gs~YIve{L z6DV11BwmK@BbJw)r{g$Q$HNg4114_ql8Ix=lxrs2M|X>G2@Wz_6jNUiS=N7AS!`xM zBO}kOUV)xQ2ATkWe`x97yE+f=ZWHK3me*?^C6xJoMPlj`+fCXKS)bY|esauI65;P3 z8j(4uT}UPv&oB(e0=0p{3iWA~q)fq(<&-WMn(b8}swPd^h=i`=Yv&lPH+1)O@wOoS zLp;3Nk0G79O_z3%Ib~Bu&dM)v?A^z&&ls=Bc82lgzxMV=!Bd z)eahsse{H;>#<27e@xemSln%EC%sNa{gdjw=kZ|;V2U!a@{(YnSc zDYIl76ef_K+A+(geP8wcG`o$0=|*J{+04Fr`4@B!;`?o?+gyg}B$!%W{XoGNlQwP3 zTmxTHQ8Bo5BXM;I_LRj+i$bVbSyoH;lVmTq1k@x8m=@`3%-B7P4Fe8qR`21pbVcnZ z!F#jx&|m28ude~O)xMYq&WGRib z%ibk#IP`V1%ii2nF()NX30LfPO0}OmQj&-U>TQM+aZ^s2;@G>V19cJ73ep18&4iA| zL`1UH_`VSiNIYv}pl%o1!Op=B6?qpG$$^H%y?;XxF)5R07I@ue-xLvs=2|hLcR|GpbIx3?~ zZ91C7#YPqv$M?4F+0~+#u^D1>bNvSQb?(y>6RRIulcxTbE1@hLjVWo+q?nScJ-@Lg z*TT_UZD85a#!WgX}qJ( zFS(n)k5cju@bhqcYq6=R0qM}m&MYd9U@@*5Z&?3k;fLI=vH)Rl*giihM;So9puViL5#ko%(6Rmz?P< z??nAOE#c)R5|;;nh`cESqKixSHWbY*2pr*QzgMIsI_t)Utan+=+M&o+48s*u?Zhk)fc8%p9 zSNHYv?JGS?9x)=>VcKGU(J$t1L zEBv37^70gipkQ>{Gg?4KC|N9-A=sKJ3eYK zR3WvKn!vJW&eo|~8{2-$@MyBONFedyXX(05B#o{)H@x%O=D(sAwXfF}M3H{Q0@c!8 zq%eI|*ylx3u`x-Zn|>%XUK63sj96$iQENn83+S=uWSBACM~p&0FEl2bCKe1@h_Q|e zrI&|cW%q#!rB>4aueC3Mi>hk>=iGZ|1_2dC7-WZmVUcYHMnD(_7(kRw_EkmPcLh|0 zR8%xf&6La~_oX*mTuLi@-_pu9tt?Hm*SE5=ve$OAUSj6l-}l@*;JE$X-~aRZ>t~p` z_nv#sbN1&v&-ZyAwn&=;-8BhtPt|4p=mo;*xuc4J#lOrznlOc@m;l8PQ^7I^K5Q_$ zYb2(zA10k8OkKRHxiNL_@-?Z^QIlIYRu5L}(8L5!nWc3d8XFuPjOjdD;Z19mvm{f^ zP(z$bO&y+nl=5o`tG#mpXv2qWHN{tN1 z?{?aC23DU7K9$V;&X64o`xh=AsjErVghvk#>1V7lgiLJuWy}~v?erCXrynahh);j$ zZjr>(VX&{>Bz%NB--&;~GaPXkC7dP8lo}?DD(Riu67UskKuh2L@$s>`xQMonRl?a4 ze}5mJ)zwAC75{(U1M9JQn_SRM_WXkE;c^Czi_sqxTt!ykB`4Ub2&`)$r0v`88m)QR`%$>wfqST?s&v(KO9a~m;IJ`QM`XH^T(iI9}tO^%yQ zpD8Vrk_?;;weMW|8RB)Zap7$p9W5~(*>VOZ!%!JgTJM=*~dWX{@L)rdCvNIrx!^550o$QqIB;Whp6T_McNM&{R*> z@LGFSQhkmU-skfWXo?lZc1OGH?TcbKPB0921fJrKrd3s?nX0O&g8fLVtR(UGi$e8& zd1`98{fErEBO(=nOyV*r1Lgs$ET+RJWm2H5%M#%q;+YlTKtK_txxQEUov+61S1Oq` z28W7$%U@UalPYrGYVajCI;jAvO(0nK7Of}I)$@(n-zt1T-hv+)#=6=y2noy@H!d@~ zu1@%(I-SYW(yNg;O}NUJgJ@{L(iw9E$Eu;kBog&^u+Cj0Tvd{A`ib(XJ5u)Q%1k!P zp6``zJyttNI##&EyDIxjJewr0kPnKGUMR_n~(P9+_Pl=0M0hq=Wb1 zFX1eL-2rq<%(H>_h%1fn42j||y`9u}6cZjE zQytPMjGoj4(0sFRK!DF@k>z}8K}|7UPY2v-AjAqxHYkmS1Ov8#i2o2m zopqL|u63}g(pgt`b%J3&OI36MAWrgu6S*>dpY?^;n7)sy$Oby=3RC5EUl1M!9m$d+ z1Fd7zMKZ2NT80fwMX3sfOz?&-J2^ExSbvBZr)7i>PdA5XhCYMemzxjG7k=~(^47=n z!8r5^^oosk$!W={Gm<%}kn8+QSV6C<{y+gClEH_a&XYN^v6T~Ihd$!%epACif}@#K zc2GPxHRIF_C_^)~!EsO+R_Er`*5-|@A*3pAsP}{ic)|+LalEImua{1lx@LO+ax>eI3=rLr9%aOpZhfLQ0lbI^s@Y+ zn)qjoQ_VxGD&jTqH0+=^r*a=`C;cbU)!Q#k zq5p1cqd%QDY^B!t^Tg3`_G~-`*jDSObc}eUcYxsljsSCNwR=c{^~B1R^zzq9Ptxxa zfkbGhmi2Fsp0@taaTrl?h})N;0{`U{*8LE-1eL!R)ekMV&DKV|i zQ_0+^)9L!@WTy4TG%|TAeT+<>PB)+?ooIj;#n(`icnj1UxYL0<&q#L+7OVxL*nQgi zse>2pggP0zWw3pmbp`e!;*cO92C1|RW66<)7zUgEEP<`5(yA-$lvdbP@@k7UqE&bw zyAF>XZjHlFI4f+hUZHj3F-eq@5SpM4jZ-D4RcckJ%JSCS{eJuUPI21qw|{z3-5Bb- zA-X=}rB~AHqaRM*`Y6P?Kf^JcyLcE&q$ku7I#gOd|49d5o9}g5RIR?>gYI8Q`?&fQ z?c?j0H+$)V^hTpzXZ(gNuOGj>y}o|=0&jhwJ{9^VBmJ_hrKPNR{`_L^SU*!lR9ae8 zSxalF{SDM+tFVJkR4$e}AWjAOY=XwxZ)-}|f~}@5<>LMH&An*k7ilcFN!*NO@`!k` z>uJ39rLcl~P4Oc;FqwgygC!%gGJ}mD4D+K8iw;L-2cGvSUv#v!^@SxRgU<&x9HGLB zw5dzdywZ(fVaANX>1|U?SWwFpL!jtnKJgriFh6j8?r(oXCzjD>bY=ibd=3jUv|8QI z3upKb72R0!F;dtXbiX%r?8PEQF7OGzJ`v1CeW>f|=e&gX$ZZR?%$l0*!wHm0^N}^ntfPd?P%k^o^jKR~hmL;W-)R zd82}GmsDl88G{yM+&YKYhHoJtq~gS@ueOtc^d~t><;{C!iL6+bECn?vZ-Nt&3T1IT zS)nYBCrg2EzB^J_CQg=6C^F*$Y@JG$ib>-&#O}9s{Cj`UtH1U@MY&&UM&?ylV;NUE zAVQ|$hOxLLWmr+s_S8{D#^ge#nae}w9mw3-#uZ7K$%_a)JCG2&@lO+L3uH`cK`kwN z2e7!WtRIpZI9#jA&971PO(`i!Nh&Vx!-6L5Hx`XbO)i87GRrCJ$JBs{ifNW5Z9gnl z44jQgUy`gXL5mR^&9g6g)~PI~q8fBr#RvB)>#?f4wqgclWM7yEg5@cz;DWLw`j3C@|h(IvnV3 zIYWOV31ws-3p={*2~;p$I3woUk{AM^x3i>k8K-ZwD=MF)XVxMCK>}h+AUUwLkaxKR zx?ma0;z^|FK7bTskpc+WbUsj>z;aPp7JNXQM%R)0wI3~LVoA4er)RcrNAe3u{*W!X z8%xdyhN`+RtS0rN>q#HL85cF%r~m5*;jDvF(Z%@Xl0Zq-V$<*$0+rTG;IKO=3OKxnMu zZHa@F&TT3%EVf|)fwEP*aD84j{eDzoh}KQ(st=x_c>5Ly8RF!)&(#x?ek}&sbn#)S zOTqJH0r9E8N5wd^j`IEGq@(JIinocPf&QC#?4j3)XH!!XN}o#|#pU7~Y&Xq{Q%S>< z2|W?dNb-5c4t1f{K2MJsl0G;r-5BUS)TLb&RhphSespYjaqN8Kk6!%)0t3Utht(%* zwcdVcG)t~9kM336ltkFl?iR{+H+f1ypv^XHh_U5(I84|Kkitzbe@$d`buuim3-gQB zeS_V+{lol>3Hf2;4p-z295AeYJY2#m!kPZDMO+=hZ7Rf_b zg>DOl$g~HAa4)PwUX#KvZro_W%ReZz@P4?5X9ES)e}24QN&TRK;U2C+2mR_``f$2;|#JYnX%c^i_VVw2(%6^dcPbG*BC!ot2J zt2sYt;l`~?oSJtosWLfbR_CN84ujWD%Y2|Y76VQYh!$p2yg>IJqt{zw6;002IZ%@| zEL=|Bpq~N_lN_A|G|b>UpIK$qOU!A_z;tX}m@&mUBEB|bP->yCe}y&`fJ3*UWh2qD zOqZ1hWrPg2z`o)J)e`GUwM`{K1L?Dty<`E@5(9WA_kJN!40>Qa$BnC-cuO^L2-#$z zT^M?Zi7miwGl@PMdNRm{jd84r_qfY5<=USG#+cy5IA6EH#YVkv(lGCV-sH|(1AI>J z+NJz#aP)8w_dvC0)JP9?P=`7?N9_^p?jAG3-6N3fgno{9qR68_ZEXWn13j;w22_Avf1ypG;v)Wa)5G;ztHf4tla-D%mrq&&mL zRBO|7TlT}w=dkk2Tf+g2Ig}WzOHln#XyRc+&Bg&!YoOb#!|g#aHD0}-7-bD?hTLy~ zV)7RZZ!;V1Krv77$EALfEf_RzQeArbNX0a{tU#Lr#d>--Aq&P1(z%yP;JI z9mG4S`-Ma@t&*+lLIUHhyT(ma3C*0KWf~?gwA?I7!{jKj`)E0)sstcO%AWy}WC!sU zucz9cC5An#ltX9DDx12CghfQ@2ie+-6xiTN^BL$-0+rUI${V(7)%SOF+NNntoP#qaWbm8GT_6Z0L z)rM|gF@3@cN0*&WE^eeIUZ?esHUX8u03l0NlWe##O;A*%CO9g}`nw$hE;J*+GxOKV zct217SdShAoM4%T>E2-@KSVNqw_}9tIWC?JWw~ndP{zQPCK@VYd5q}7B4T19fMauu z57Wl$!@}aD+a7tOZRuLFW@)OP=u%VT;%*VBiIfSf>mA~^qtgU{%ATZ6HoANuwt@MK zywbA)C)1^pKs#=C3>0b5BW$KFEG$k3NF8z4X@|i6UN=Om3){2GF=6Jc@~Jz>5N$f> zu{BgMYdERF?gF?Wl$GT@;R*VJayU+b8J0xB8H?nn)XcpsK7CIH{^bjdfp2}_=;9LZ z3z~-Ktj|7UIWmu$aS{m)XAFGXlvLxCHY|eutiOpK;z^qX!A@#mu#+0__qlI*`I(fd z=7dTnH#lUn$r7M*ymgZa7|J1F(9_TQB#uo9Lc2L9jZF#)3Z=g~Cg6r9Ow%W647-6! zRtnq2NvgG|WN7z6;0T0nC+jB;4*~Dqqi_S51SS{?hLSfhyu2HXG1Ti#eG4TzzX>h4q_P5H&ur-=;dhvEIJp9yl5;ex1FU1YkL^aQ4v zvOChMt-1X^uDkN(xbuBax}2-~;!53l7vaM1EBDNqvuEYa8!PwCp1F7V@9Z$4@Z>Hj zVAKP*JPaZKq;Q!lkr4COq~PEOaa|={e;>re!t((6jo{bFobW`p-vEWcM^MrvyFA}+ zX~I*^VKLGL^`w(A7DyLF-J0NbJ@x0GNr9A*$>!hZud7O>X)g;|ZIfe=GSE&|45JnP zZfUa#hbQ4~Nq930Vvow$q=e`SSxU%>qVN`%q3SOkUT%{`Gv5Hc^5}nAUlHDdIJ&AT zBdwYnv1bpeE7Qr|lza@xvP+3&x{XePeD0=`yoMa_qLa(8%lW^z0MLMU=WKlA&lSS^ zJ+k(mZz8n-sLq5ISF6IY&30G=bqEG`&lYBfQPQ1SS($2r(!<&ILvixNiRtAj#I71iiATVvcyn?cwKcXe!TN}MNDMf>@=wYm|>daodVeh=SBpJQEj*+1NW z=#V9={KNcpv5QxeX{_UV8@pI)Y=$zr56O~)Ol&~+XmP(KORjXi_n&(-`iiYvmGlqd z#9SJP%0m9S}*kap$|+?p(wjXn0tfo6n{uG!wPwGLAJ zTT-S>Qo3@>Ab0&g=n)EAva(tV3m0Z*FD%rjrRnwQ=}OnM*_l~0)6-{WWz9-!H^s)L zrpCrX3gci?;-JMGO56hZ4+DuyD^v@KlsT2!h%WlOr2Sz+It{`v<3lE&n@gOZzj%m1 zyTB4k%AiLv%T4mEXEm}sP9LJ#;_DD@U$dyXU`Et^i9ROw6CXhhz>#Ie$=+L-`h>BG zA#uH@Jn6do(p-`mpP12LoR(#tVkGqqro?!2Q|dHx_S9i>n3OBKAtR$9yZ0BWG6QO# zFl7Kcai%k__?Dz{C^uHB&wC|y^TQC5~wwXPIBID>lgVPXZ^9xlkb z5gm_w6ioVc-RHZia3`LIfcBlZW9oicyb3B?>>3?gU$4O5=VS=k z?st-ENh@7(?!bX_>>Ha*f1K+tD*prVA(LcbMA}uF?dd&o5NpGp*Un`W=9@pR*fqVh zxF#>Jl8_4F%->eTjVg>Uhhr=?DKi)g3X@X`K^#ww;$U$Gh+EtJhD7c~{t6wU^b}Oi zk(Np(|Fno;>+%tWnyG%klQP+vyF2XS^ks2O^>gj*tj_kR!n7@Q@31i~D?4S4B)f*H z!h^ImC)EFv`DRRyMuq>(7z-O2?`RqG%nC zBe$T8KpX2UpG%GKB<}3M9j3iWL#s3G4HIRG)=cPiIPtiY_Fr8HRSF5*1KcHX7^Vl7 zjV|QZy;B(}&QcA;9Yyy})j&*`&5AF?bk!zlh&h09~YS#;1SEZgx z47XvJ6t`Vj|6JMG*!bv!W~0$eTUKspYV2HTHl}3KO^qubY)Hkwh6kl@6cY=Bt8ckO zsKXE4Yb?*=j*jNjYhsOb=V3NBySLHh;&gGERL^bVG?22%`n8xYJ}cLAcyB$+`KK)9 zCC87`U;qAhOrE{MzhNJ8N>0_QFz7#nEP%pb^=vX%_+cuUHG_7N+0*GGSiHi7GuWsb z@d6V;Vcp{GP6KhLNfy0I%gx!vC0UteOmc;&>wYN(1u4k|1$et&_$R+WWrjG3nPl|n zhV6GgQrF`FlB_aSR+{ipbnV`)fS&;`MQTA}VgdW0JL;9S`~t^QN|iGtK5(|nOG@E= zs;BUa+4F<hU%`yuQR(^Li6#x*ir;a(d#YIkpr zp+nl-{Q|jt{G8FTBa-6=%bU9kI0zFk6tu7H2ixfV3_})o_+g`uS@aMYH!3MG-S zZKDOou`n#?Wik5yZ!Cu7(dm9HMzZzQI~fcv9vl}2mvS=qxaw2XpY1kaQ|!-YB&_qw z8CscdOv}wpOU+YGh673mt1dGuR-cuHm&Xbxc~`JhvTl%dy!}Ri%x(h|yt?ehN#W!z zPyuO^SRBM!M>a0^&4vMsj@EChIZ~ICGwx8$HpQ`%H}1>^wA2Z2@m{KQ&=QJ@+(FBI z@HEHjw^Tn#)6QK4cu8br!y*)$CcMX= z1MSS&E;tJtNJGLO^#V0Eu!_HD18bbNRhqpx_3jtJ+1^5UTsv`N**#w@mtKV8s<*_D zTi6LeCwhw}(c986UstakS4l!{Wi{8?X;sGfSR4K2Xf_$b-b?>IF*&!gT^(b`%Epcy z7ALc^O}!;t^66L=19{CtGG?!*FpM()7YniU$dACvv4@BZm85CXN%{FSI}C&m^PkAG!rBwlFauamPfb5YXE zT(pt6a(!oTEPwsf@XlpXg{F-Y-vk|x!j?1x!8n+ur32z^$?{8Vw-Oex$MQf00J7%M z=QlL(Dk8^@78sJV{0NCIPK)RJe*LxL#){2j4>iAZ@PniJiiG2J3)8}>nl8UH^K=`2 z8$uBe3G>&BgCtCzm2r_bq?SbcXD93Ojy{*Oqiy|BYP@o{pqN<^p#0CdOBNLm>T2QiW99c}UUL#s@Ju5FuE^juA#pR&t zW@ZLgB%z%O^NEFw7%V}&1Kk6eY!$8$0Dy{fQ)w6;g#@b5{cJgw+&OEQ?1)KeyB{RS z>F}95cXHo8`+3O#N)K)xRNQ|j{STQHO25?ZSlRkic%J5W7yyE&iGC`8PZ8wl; zdRG4?@ugpLVGVR-?Se^ADJ-h3O^OLOp-&?Cu{;ZtCxtzO_W)>_n9dk56cuBbBW_y7 zPpX1q21N{v2rLUFkMU!%C?iNuOSnvjb4=P&a!XQcKsG9+@(pcvh>LodXR3KJ zS*{RXrzHyI7rc;@n{e)r*Wbq5Kax%S_uO$w&IKJ6n>W2ma7p?{GAo9+WDczv={uw- zyxP1lFQIa{Usx&GlvP_Btcl1lj<42en7f!fFoF*YFbQyQV6Ay3^u_ncfmJc7>u24Qt z6e%Xmfjsd?M^NdIMX=d4(@VBgPe?bo+#`ED78=wp~&e*n=SZRU+Q<=V3= z`_*KSdUyW#@%i`&eY*b?w$zQx9XmF6WF6>O3N39mMmO3E(e0%FitO%WqUXjDz2aPV zlyDve+}iM&0sS4DEN~Y+@I7on_E19iZ6>ACMcRadZ{NCmHX`2PQ{g|`T%%d!^bBo`>t)il4ZVx&<#$}SOV_c&1u|OM7tcE!|3b6fjd;K|&xA~8A+lm( zrR4;O2lT>v;X5uFhfOx{csRwGdWm>$zyUOdesud&CgNDXfp~t}`!HGp6ArvDn9#gn zM{WukT9hw=3H8B^v~P0vKX*fNFq zwvzmUg@ZBaY}$pWB(W0{e~`qnGb4%HkU`p^>QGm`W(=*&nV+@4H8I&)wV%~c9Lp#o z$L>$jG*C2i`LdZA?U^%MXJ*|-(YWlC^s<(UrpG6k6VrPs;w-HS4(28@IuN258$`5~ zGbEi6Y0^wPfP%O{UKW4m*x^+=`49N(Tdwi=aWwlPZXI97o7n^Av1k!@iCcH{ zD9*>*tlhL)JctKai_)y()(!(dIBl*rs$w`{Fih)Zl`;hK&`*dsrx9mH4kbKjd3n!Ee3fmtv9qAF^etzyJUM literal 0 HcmV?d00001 diff --git a/compositor_render/src/transformations/text_renderer.rs b/compositor_render/src/transformations/text_renderer.rs index a3ae0810b..4d5efd959 100644 --- a/compositor_render/src/transformations/text_renderer.rs +++ b/compositor_render/src/transformations/text_renderer.rs @@ -264,6 +264,11 @@ impl TextRendererCtx { .load_font_source(Source::Binary(Arc::new(include_bytes!( "../../fonts/Inter_18pt-Italic.ttf" )))); + font_system + .db_mut() + .load_font_source(Source::Binary(Arc::new(include_bytes!( + "../../fonts/Inter_18pt-Bold.ttf" + )))); Self { font_system: Mutex::new(font_system), swash_cache: Mutex::new(SwashCache::new()), diff --git a/snapshot_tests/snapshots b/snapshot_tests/snapshots index fd3ef30ac..d8becda39 160000 --- a/snapshot_tests/snapshots +++ b/snapshot_tests/snapshots @@ -1 +1 @@ -Subproject commit fd3ef30acb19aded98515cad20a16b0c5c89d7a9 +Subproject commit d8becda39b0c167a7f4ddee67878d97f75ffad8e diff --git a/snapshot_tests/text/align_center.scene.json b/snapshot_tests/text/align_center.scene.json index 5223887dd..afbaea49b 100644 --- a/snapshot_tests/text/align_center.scene.json +++ b/snapshot_tests/text/align_center.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example text", "font_size": 100, - "font_family": "Verdana", + "font_family": "Inter", "align": "center", "width": 1000, "height": 200 diff --git a/snapshot_tests/text/align_right.scene.json b/snapshot_tests/text/align_right.scene.json index 6fa3e7372..d72b686f5 100644 --- a/snapshot_tests/text/align_right.scene.json +++ b/snapshot_tests/text/align_right.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example text", "font_size": 100, - "font_family": "Verdana", + "font_family": "Inter", "align": "right", "width": 1000, "height": 200 diff --git a/snapshot_tests/text/bold_text.scene.json b/snapshot_tests/text/bold_text.scene.json index d699a6c35..8c98f7933 100644 --- a/snapshot_tests/text/bold_text.scene.json +++ b/snapshot_tests/text/bold_text.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example text", "font_size": 100, - "font_family": "Verdana", + "font_family": "Inter", "align": "right", "weight": "bold", "width": 1000, diff --git a/snapshot_tests/text/dimensions_fitted.scene.json b/snapshot_tests/text/dimensions_fitted.scene.json index eabb98a38..7dfdb090b 100644 --- a/snapshot_tests/text/dimensions_fitted.scene.json +++ b/snapshot_tests/text/dimensions_fitted.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example text", "font_size": 100, - "font_family": "Verdana", + "font_family": "Inter", "background_color_rgba": "#FF0000FF" } ] diff --git a/snapshot_tests/text/dimensions_fitted_column_with_long_text.scene.json b/snapshot_tests/text/dimensions_fitted_column_with_long_text.scene.json index 3f953ffde..ad911d54e 100644 --- a/snapshot_tests/text/dimensions_fitted_column_with_long_text.scene.json +++ b/snapshot_tests/text/dimensions_fitted_column_with_long_text.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example long text that should be longer that underlaying texture.", "font_size": 30, - "font_family": "Verdana", + "font_family": "Inter", "width": 300 } ] diff --git a/snapshot_tests/text/dimensions_fitted_column_with_short_text.scene.json b/snapshot_tests/text/dimensions_fitted_column_with_short_text.scene.json index 84dda9749..dd4eca462 100644 --- a/snapshot_tests/text/dimensions_fitted_column_with_short_text.scene.json +++ b/snapshot_tests/text/dimensions_fitted_column_with_short_text.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example text", "font_size": 30, - "font_family": "Verdana", + "font_family": "Inter", "width": 300 } ] diff --git a/snapshot_tests/text/dimensions_fixed.scene.json b/snapshot_tests/text/dimensions_fixed.scene.json index e448d8427..a9c5daa60 100644 --- a/snapshot_tests/text/dimensions_fixed.scene.json +++ b/snapshot_tests/text/dimensions_fixed.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example text", "font_size": 100, - "font_family": "Verdana", + "font_family": "Inter", "width": 1000, "height": 200 } diff --git a/snapshot_tests/text/dimensions_fixed_with_overflow.scene.json b/snapshot_tests/text/dimensions_fixed_with_overflow.scene.json index 5efaf64cd..00895a433 100644 --- a/snapshot_tests/text/dimensions_fixed_with_overflow.scene.json +++ b/snapshot_tests/text/dimensions_fixed_with_overflow.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example text", "font_size": 120, - "font_family": "Verdana", + "font_family": "Inter", "width": 640, "height": 80 } diff --git a/snapshot_tests/text/red_text_on_blue_background.scene.json b/snapshot_tests/text/red_text_on_blue_background.scene.json index 5f020d705..3ce59d824 100644 --- a/snapshot_tests/text/red_text_on_blue_background.scene.json +++ b/snapshot_tests/text/red_text_on_blue_background.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Example text", "font_size": 50, - "font_family": "Verdana", + "font_family": "Inter", "align": "left", "wrap": "word", "color_rgba": "#FF0000FF", diff --git a/snapshot_tests/text/root_text.scene.json b/snapshot_tests/text/root_text.scene.json index 39f04ee19..ff243b846 100644 --- a/snapshot_tests/text/root_text.scene.json +++ b/snapshot_tests/text/root_text.scene.json @@ -4,7 +4,7 @@ "type": "text", "text": "Example text", "font_size": 100, - "font_family": "Verdana", + "font_family": "Inter", "width": 1000, "height": 200 } diff --git a/snapshot_tests/text/wrap_glyph.scene.json b/snapshot_tests/text/wrap_glyph.scene.json index b38861b65..bbe71ba5b 100644 --- a/snapshot_tests/text/wrap_glyph.scene.json +++ b/snapshot_tests/text/wrap_glyph.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum id eros non eros dictum scelerisque. Sed vehicula magna et metus fringilla, nec placerat felis elementum. Nullam tincidunt dui id purus egestas, et pulvinar est facilisis.", "font_size": 50, - "font_family": "Verdana", + "font_family": "Inter", "align": "left", "wrap": "glyph", "width": 1000, diff --git a/snapshot_tests/text/wrap_none.scene.json b/snapshot_tests/text/wrap_none.scene.json index 5455b67f8..56af073cc 100644 --- a/snapshot_tests/text/wrap_none.scene.json +++ b/snapshot_tests/text/wrap_none.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum id eros non eros dictum scelerisque. Sed vehicula magna et metus fringilla, nec placerat felis elementum. Nullam tincidunt dui id purus egestas, et pulvinar est facilisis.", "font_size": 50, - "font_family": "Verdana", + "font_family": "Inter", "align": "left", "wrap": "none", "width": 1000, diff --git a/snapshot_tests/text/wrap_word.scene.json b/snapshot_tests/text/wrap_word.scene.json index 4aef48b6c..8b60251c4 100644 --- a/snapshot_tests/text/wrap_word.scene.json +++ b/snapshot_tests/text/wrap_word.scene.json @@ -8,7 +8,7 @@ "type": "text", "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum id eros non eros dictum scelerisque. Sed vehicula magna et metus fringilla, nec placerat felis elementum. Nullam tincidunt dui id purus egestas, et pulvinar est facilisis.", "font_size": 50, - "font_family": "Verdana", + "font_family": "Inter", "align": "left", "wrap": "word", "width": 1000, diff --git a/src/snapshot_tests/test_case.rs b/src/snapshot_tests/test_case.rs index 479b81b04..3cd2ce00b 100644 --- a/src/snapshot_tests/test_case.rs +++ b/src/snapshot_tests/test_case.rs @@ -37,7 +37,7 @@ impl Default for TestCase { timestamps: vec![Duration::from_secs(0)], scene_updates: Updates::Scenes(vec![]), only: false, - allowed_error: 20.0, + allowed_error: 1.0, } } } diff --git a/src/snapshot_tests/tests.rs b/src/snapshot_tests/tests.rs index 714799c60..e14460595 100644 --- a/src/snapshot_tests/tests.rs +++ b/src/snapshot_tests/tests.rs @@ -1188,7 +1188,6 @@ fn text_snapshot_tests() -> Vec { include_str!("../../snapshot_tests/text/wrap_glyph.scene.json"), DEFAULT_RESOLUTION, ), - allowed_error: 325.7, ..Default::default() }, TestCase { @@ -1205,7 +1204,6 @@ fn text_snapshot_tests() -> Vec { include_str!("../../snapshot_tests/text/wrap_word.scene.json"), DEFAULT_RESOLUTION, ), - allowed_error: 321.8, ..Default::default() }, TestCase { @@ -1722,7 +1720,6 @@ fn view_snapshot_tests() -> Vec { }, TestCase { name: "view/border_radius_box_shadow_overflow_fit", - only: true, scene_updates: Updates::Scene( include_str!("../../snapshot_tests/view/border_radius_box_shadow_overflow_fit.scene.json"), DEFAULT_RESOLUTION, diff --git a/src/snapshot_tests/utils.rs b/src/snapshot_tests/utils.rs index d79b8cb67..893133f82 100644 --- a/src/snapshot_tests/utils.rs +++ b/src/snapshot_tests/utils.rs @@ -85,7 +85,7 @@ pub(super) fn create_renderer() -> Renderer { stream_fallback_timeout: Duration::from_secs(3), wgpu_features: WgpuFeatures::default(), wgpu_ctx: Some(global_wgpu_ctx(false, Default::default())), - load_system_fonts: true, + load_system_fonts: false, }) .unwrap(); renderer From c7534b6370c3e06cf67bc9ef2f76355f66046f3a Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Tue, 5 Nov 2024 12:07:08 +0100 Subject: [PATCH 19/51] Remove LFS file from h264-reader fork (#847) --- Cargo.lock | 2 +- vk-video/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 920bce870..50d40658d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1359,7 +1359,7 @@ dependencies = [ [[package]] name = "h264-reader" version = "0.7.1-dev" -source = "git+https://github.com/membraneframework-labs/h264-reader.git?branch=@jerzywilczek/scaling-lists#7c982f1089558640021ff8a70a2fa253e3e881c7" +source = "git+https://github.com/membraneframework-labs/h264-reader.git?branch=live-compositor#9292ad0ab24b75e07815f546f41cef24b30b09c9" dependencies = [ "bitstream-io", "hex-slice", diff --git a/vk-video/Cargo.toml b/vk-video/Cargo.toml index 7256069af..d5e84402e 100644 --- a/vk-video/Cargo.toml +++ b/vk-video/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/software-mansion/live-compositor" ash = "0.38.0" bytes = "1" derivative = "2.2.0" -h264-reader = { git = "https://github.com/membraneframework-labs/h264-reader.git", branch = "@jerzywilczek/scaling-lists" } +h264-reader = { git = "https://github.com/membraneframework-labs/h264-reader.git", branch = "live-compositor" } thiserror = "1.0.59" tracing = "0.1.40" vk-mem = "0.4.0" From e286d6de0d66be4306da4e2fa36e85e4556c9e80 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Thu, 31 Oct 2024 19:54:16 +0100 Subject: [PATCH 20/51] enhanced error handling --- compositor_pipeline/src/error.rs | 11 +- compositor_pipeline/src/pipeline.rs | 16 ++- .../src/pipeline/output/whip.rs | 41 ++++++- .../src/pipeline/pipeline_output.rs | 110 +++++++++--------- .../examples/encoded_channel_output.rs | 9 +- .../examples/raw_channel_input.rs | 6 +- .../examples/raw_channel_output.rs | 7 +- integration_tests/examples/vulkan.rs | 6 +- integration_tests/examples/whip_client.rs | 5 +- src/routes/register_request.rs | 6 +- 10 files changed, 121 insertions(+), 96 deletions(-) diff --git a/compositor_pipeline/src/error.rs b/compositor_pipeline/src/error.rs index 1596f0832..3a5c8d992 100644 --- a/compositor_pipeline/src/error.rs +++ b/compositor_pipeline/src/error.rs @@ -6,7 +6,7 @@ use compositor_render::{ InputId, OutputId, }; -use crate::pipeline::{decoder::AacDecoderError, VideoCodec}; +use crate::pipeline::{decoder::AacDecoderError, output::whip, VideoCodec}; use fdk_aac_sys as fdk; #[derive(Debug, thiserror::Error)] @@ -93,6 +93,15 @@ pub enum OutputInitError { #[error("Failed to register output. FFmpeg error: {0}.")] FfmpegMp4Error(ffmpeg_next::Error), + + #[error("Unkown Whip output error, channel unexpectedly closed")] + UnknownWhipError, + + #[error("Whip init timeout exceeded")] + WhipInitTimeout, + + #[error("Failed to init whip output: {0}")] + WhipInitError(Box), } #[derive(Debug, thiserror::Error)] diff --git a/compositor_pipeline/src/pipeline.rs b/compositor_pipeline/src/pipeline.rs index aa20f184f..d4edc5c98 100644 --- a/compositor_pipeline/src/pipeline.rs +++ b/compositor_pipeline/src/pipeline.rs @@ -25,6 +25,7 @@ use input::RawDataInputOptions; use output::EncodedDataOutputOptions; use output::OutputOptions; use output::RawDataOutputOptions; +use pipeline_output::register_pipeline_output; use tokio::runtime::Runtime; use tracing::{error, info, trace, warn}; use types::RawDataSender; @@ -254,11 +255,12 @@ impl Pipeline { } pub fn register_output( - &mut self, + pipeline: &Arc>, output_id: OutputId, register_options: RegisterOutputOptions, ) -> Result, RegisterOutputError> { - self.register_pipeline_output( + register_pipeline_output( + pipeline, output_id, ®ister_options.output_options, register_options.video, @@ -267,11 +269,12 @@ impl Pipeline { } pub fn register_encoded_data_output( - &mut self, + pipeline: &Arc>, output_id: OutputId, register_options: RegisterOutputOptions, ) -> Result, RegisterOutputError> { - self.register_pipeline_output( + register_pipeline_output( + pipeline, output_id, ®ister_options.output_options, register_options.video, @@ -280,11 +283,12 @@ impl Pipeline { } pub fn register_raw_data_output( - &mut self, + pipeline: &Arc>, output_id: OutputId, register_options: RegisterOutputOptions, ) -> Result { - self.register_pipeline_output( + register_pipeline_output( + pipeline, output_id, ®ister_options.output_options, register_options.video, diff --git a/compositor_pipeline/src/pipeline/output/whip.rs b/compositor_pipeline/src/pipeline/output/whip.rs index 08b0c4b8a..8e9f3e9f9 100644 --- a/compositor_pipeline/src/pipeline/output/whip.rs +++ b/compositor_pipeline/src/pipeline/output/whip.rs @@ -5,7 +5,12 @@ use init_peer_connection::init_pc; use packet_stream::PacketStream; use payloader::{Payload, Payloader, PayloadingError}; use reqwest::{Method, StatusCode, Url}; -use std::sync::{atomic::AtomicBool, Arc}; +use std::{ + sync::{atomic::AtomicBool, Arc}, + thread, + time::{Duration, SystemTime}, +}; +use tokio::sync::oneshot; use tracing::{debug, error, span, Instrument, Level}; use url::ParseError; use webrtc::{ @@ -88,6 +93,8 @@ pub enum WhipError { PayloadingError(#[from] PayloadingError), } +const WHIP_INIT_TIMEOUT: Duration = Duration::from_secs(60); + impl WhipSender { pub fn new( output_id: &OutputId, @@ -111,6 +118,9 @@ impl WhipSender { let tokio_rt_clone = tokio_rt.clone(); let output_id_clone = output_id.clone(); + let (init_confirmation_sender, mut init_confirmation_receiver) = + oneshot::channel::>(); + tokio_rt.spawn( async move { run_whip_sender_thread( @@ -120,6 +130,7 @@ impl WhipSender { packet_stream, request_keyframe_sender, tokio_rt_clone, + init_confirmation_sender, ) .await; event_emitter.emit(Event::OutputDone(output_id_clone)); @@ -132,6 +143,27 @@ impl WhipSender { )), ); + let start_time = SystemTime::now(); + loop { + thread::sleep(Duration::from_secs(5)); + let elapsed_time = SystemTime::now().duration_since(start_time).unwrap(); + if elapsed_time > WHIP_INIT_TIMEOUT { + return Err(OutputInitError::WhipInitTimeout); + } + match init_confirmation_receiver.try_recv() { + Ok(result) => match result { + Ok(_) => break, + Err(err) => return Err(OutputInitError::WhipInitError(err.into())), + }, + Err(err) => match err { + oneshot::error::TryRecvError::Closed => { + return Err(OutputInitError::UnknownWhipError) + } + oneshot::error::TryRecvError::Empty => {} + }, + }; + } + Ok(Self { connection_options: options, should_close, @@ -153,6 +185,7 @@ async fn run_whip_sender_thread( packet_stream: PacketStream, request_keyframe_sender: Option>, tokio_rt: Arc, + init_confirmation_sender: oneshot::Sender>, ) { let client = reqwest::Client::new(); let peer_connection: Arc; @@ -165,7 +198,7 @@ async fn run_whip_sender_thread( audio_track = audio; } Err(err) => { - error!("Error occured while initializing peer connection: {err}"); + init_confirmation_sender.send(Err(err)).unwrap(); return; } } @@ -182,10 +215,11 @@ async fn run_whip_sender_thread( { Ok(val) => val, Err(err) => { - error!("{err}"); + init_confirmation_sender.send(Err(err)).unwrap(); return; } }; + init_confirmation_sender.send(Ok(())).unwrap(); for chunk in packet_stream { if should_close.load(std::sync::atomic::Ordering::Relaxed) { @@ -223,5 +257,4 @@ async fn run_whip_sender_thread( } } let _ = client.delete(whip_session_url).send().await; - // }); } diff --git a/compositor_pipeline/src/pipeline/pipeline_output.rs b/compositor_pipeline/src/pipeline/pipeline_output.rs index eb9b79aaa..f62eeb8d8 100644 --- a/compositor_pipeline/src/pipeline/pipeline_output.rs +++ b/compositor_pipeline/src/pipeline/pipeline_output.rs @@ -34,73 +34,69 @@ pub(super) enum OutputSender { FinishedSender, } -impl Pipeline { - pub(super) fn register_pipeline_output( - &mut self, - output_id: OutputId, - output_options: &dyn OutputOptionsExt, - video: Option, - audio: Option, - ) -> Result { - let (has_video, has_audio) = (video.is_some(), audio.is_some()); - if !has_video && !has_audio { - return Err(RegisterOutputError::NoVideoAndAudio(output_id)); - } +pub(super) fn register_pipeline_output( + pipeline: &Arc>, + output_id: OutputId, + output_options: &dyn OutputOptionsExt, + video: Option, + audio: Option, +) -> Result { + let (has_video, has_audio) = (video.is_some(), audio.is_some()); + if !has_video && !has_audio { + return Err(RegisterOutputError::NoVideoAndAudio(output_id)); + } - if self.outputs.contains_key(&output_id) { - return Err(RegisterOutputError::AlreadyRegistered(output_id)); - } + if pipeline.lock().unwrap().outputs.contains_key(&output_id) { + return Err(RegisterOutputError::AlreadyRegistered(output_id)); + } - let (output, output_result) = output_options.new_output(&output_id, &self.ctx)?; + let pipeline_ctx = pipeline.lock().unwrap().ctx.clone(); - let output = PipelineOutput { - output, - audio_end_condition: audio.as_ref().map(|audio| { - PipelineOutputEndConditionState::new_audio( - audio.end_condition.clone(), - &self.inputs, - ) - }), - video_end_condition: video.as_ref().map(|video| { - PipelineOutputEndConditionState::new_video( - video.end_condition.clone(), - &self.inputs, - ) - }), - }; + let (output, output_result) = output_options.new_output(&output_id, &pipeline_ctx)?; - if let (Some(video_opts), Some(resolution), Some(format)) = ( - video.clone(), - output.output.resolution(), - output.output.output_frame_format(), - ) { - let result = self.renderer.update_scene( - output_id.clone(), - resolution, - format, - video_opts.initial, - ); + let mut guard = pipeline.lock().unwrap(); - if let Err(err) = result { - self.renderer.unregister_output(&output_id); - return Err(RegisterOutputError::SceneError(output_id.clone(), err)); - } - }; + let output = PipelineOutput { + output, + audio_end_condition: audio.as_ref().map(|audio| { + PipelineOutputEndConditionState::new_audio(audio.end_condition.clone(), &guard.inputs) + }), + video_end_condition: video.as_ref().map(|video| { + PipelineOutputEndConditionState::new_video(video.end_condition.clone(), &guard.inputs) + }), + }; - if let Some(audio_opts) = audio.clone() { - self.audio_mixer.register_output( - output_id.clone(), - audio_opts.initial, - audio_opts.mixing_strategy, - audio_opts.channels, - ); - } + if let (Some(video_opts), Some(resolution), Some(format)) = ( + video.clone(), + output.output.resolution(), + output.output.output_frame_format(), + ) { + let result = + guard + .renderer + .update_scene(output_id.clone(), resolution, format, video_opts.initial); - self.outputs.insert(output_id.clone(), output); + if let Err(err) = result { + guard.renderer.unregister_output(&output_id); + return Err(RegisterOutputError::SceneError(output_id.clone(), err)); + } + }; - Ok(output_result) + if let Some(audio_opts) = audio.clone() { + guard.audio_mixer.register_output( + output_id.clone(), + audio_opts.initial, + audio_opts.mixing_strategy, + audio_opts.channels, + ); } + guard.outputs.insert(output_id.clone(), output); + + Ok(output_result) +} + +impl Pipeline { pub(super) fn all_output_video_senders_iter( pipeline: &Arc>, ) -> impl Iterator>>)> { diff --git a/integration_tests/examples/encoded_channel_output.rs b/integration_tests/examples/encoded_channel_output.rs index 00397e0a7..f9312eb6b 100644 --- a/integration_tests/examples/encoded_channel_output.rs +++ b/integration_tests/examples/encoded_channel_output.rs @@ -109,12 +109,9 @@ fn main() { Pipeline::register_input(&state.pipeline, input_id.clone(), input_options).unwrap(); - let output_receiver = state - .pipeline - .lock() - .unwrap() - .register_encoded_data_output(output_id.clone(), output_options) - .unwrap(); + let output_receiver = + Pipeline::register_encoded_data_output(&state.pipeline, output_id.clone(), output_options) + .unwrap(); Pipeline::start(&state.pipeline); diff --git a/integration_tests/examples/raw_channel_input.rs b/integration_tests/examples/raw_channel_input.rs index 9a4272098..b458f8c51 100644 --- a/integration_tests/examples/raw_channel_input.rs +++ b/integration_tests/examples/raw_channel_input.rs @@ -112,11 +112,7 @@ fn main() { ) .unwrap(); - pipeline - .lock() - .unwrap() - .register_output(output_id.clone(), output_options) - .unwrap(); + Pipeline::register_output(&pipeline, output_id.clone(), output_options).unwrap(); let frames = generate_frames(&wgpu_device, &wgpu_queue); diff --git a/integration_tests/examples/raw_channel_output.rs b/integration_tests/examples/raw_channel_output.rs index 8d18ca3b3..43bfc6037 100644 --- a/integration_tests/examples/raw_channel_output.rs +++ b/integration_tests/examples/raw_channel_output.rs @@ -127,11 +127,8 @@ fn main() { Pipeline::register_input(&pipeline, input_id.clone(), input_options).unwrap(); - let RawDataReceiver { video, audio } = pipeline - .lock() - .unwrap() - .register_raw_data_output(output_id.clone(), output_options) - .unwrap(); + let RawDataReceiver { video, audio } = + Pipeline::register_raw_data_output(&pipeline, output_id.clone(), output_options).unwrap(); Pipeline::start(&pipeline); diff --git a/integration_tests/examples/vulkan.rs b/integration_tests/examples/vulkan.rs index 099515b41..90150fb9f 100644 --- a/integration_tests/examples/vulkan.rs +++ b/integration_tests/examples/vulkan.rs @@ -171,11 +171,7 @@ fn client_code() -> Result<()> { audio: None, }; - pipeline - .lock() - .unwrap() - .register_output(OutputId("output_1".into()), output_options) - .unwrap(); + Pipeline::register_output(&pipeline, OutputId("output_1".into()), output_options).unwrap(); Pipeline::start(&pipeline); diff --git a/integration_tests/examples/whip_client.rs b/integration_tests/examples/whip_client.rs index 64b200051..c1a082d69 100644 --- a/integration_tests/examples/whip_client.rs +++ b/integration_tests/examples/whip_client.rs @@ -1,7 +1,7 @@ use anyhow::Result; use compositor_api::types::Resolution; use serde_json::json; -use std::{thread::sleep, time::Duration}; +use std::time::Duration; use integration_tests::examples::{self, run_example}; @@ -69,8 +69,5 @@ fn client_code() -> Result<()> { examples::post("start", &json!({}))?; - sleep(Duration::from_secs(300)); - examples::post("output/output_1/unregister", &json!({}))?; - Ok(()) } diff --git a/src/routes/register_request.rs b/src/routes/register_request.rs index c6ecbcee2..cbc98fdc1 100644 --- a/src/routes/register_request.rs +++ b/src/routes/register_request.rs @@ -71,13 +71,13 @@ pub(super) async fn handle_output( tokio::task::spawn_blocking(move || { let response = match request { RegisterOutput::RtpStream(rtp) => { - Pipeline::register_output(&mut api.pipeline(), output_id.into(), rtp.try_into()?)? + Pipeline::register_output(&api.pipeline, output_id.into(), rtp.try_into()?)? } RegisterOutput::Mp4(mp4) => { - Pipeline::register_output(&mut api.pipeline(), output_id.into(), mp4.try_into()?)? + Pipeline::register_output(&api.pipeline, output_id.into(), mp4.try_into()?)? } RegisterOutput::Whip(whip) => { - Pipeline::register_output(&mut api.pipeline(), output_id.into(), whip.try_into()?)? + Pipeline::register_output(&api.pipeline, output_id.into(), whip.try_into()?)? } }; match response { From 4bb1d74f6de350d15113101503708cb9d4bac8e0 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Thu, 7 Nov 2024 14:18:28 +0100 Subject: [PATCH 21/51] changed trickle ice logging --- .../pipeline/output/whip/establish_peer_connection.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs index b7c35ce3f..8edc4fb54 100644 --- a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -3,7 +3,7 @@ use crossbeam_channel::Sender; use super::WhipError; use reqwest::{header::HeaderMap, Client, Method, StatusCode, Url}; use std::sync::{atomic::AtomicBool, Arc}; -use tracing::{debug, error, info}; +use tracing::{debug, error, info, warn}; use webrtc::{ ice_transport::{ice_candidate::RTCIceCandidate, ice_connection_state::RTCIceConnectionState}, peer_connection::{sdp::session_description::RTCSessionDescription, RTCPeerConnection}, @@ -194,7 +194,12 @@ async fn handle_candidate( .text() .await .map_err(|e| WhipError::BodyParsingError("Trickle ICE patch".to_string(), e))?; - return Err(WhipError::BadStatus(status, body_str)); - }; + if status == StatusCode::UNPROCESSABLE_ENTITY || status == StatusCode::METHOD_NOT_ALLOWED { + warn!("Error while sending Ice Candidate do WHIP Server (Trickle ICE is probably not supported):\nStaus code: {status}\nBody: {body_str}") + } else { + return Err(WhipError::BadStatus(status, body_str)); + } + } + Ok(()) } From c816a68119b10a2cc0b10ae520d362fe2cfa548e Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Fri, 8 Nov 2024 12:33:50 +0100 Subject: [PATCH 22/51] [test] Split snapshots into separate files + unify update behavior (#850) --- Cargo.toml | 1 + build_tools/nix/package.nix | 1 - .../simple_input_pass_through.scene.json | 0 snapshot_tests/snapshots | 2 +- src/bin/update_snapshots/main.rs | 85 - src/lib.rs | 3 + src/main.rs | 3 - src/snapshot_tests.rs | 173 +- src/snapshot_tests/image_tests.rs | 76 + src/snapshot_tests/input.rs | 111 + src/snapshot_tests/rescaler_tests.rs | 250 +++ src/snapshot_tests/shader_tests.rs | 262 +++ src/snapshot_tests/simple_tests.rs | 17 + src/snapshot_tests/snapshot.rs | 90 + src/snapshot_tests/test_case.rs | 325 +-- src/snapshot_tests/tests.rs | 1807 ----------------- src/snapshot_tests/text_tests.rs | 118 ++ src/snapshot_tests/tiles_tests.rs | 318 +++ src/snapshot_tests/tiles_transitions_tests.rs | 174 ++ src/snapshot_tests/transition_tests.rs | 95 + src/snapshot_tests/utils.rs | 67 +- src/snapshot_tests/view_tests.rs | 219 ++ 22 files changed, 1920 insertions(+), 2277 deletions(-) rename snapshot_tests/{ => simple}/simple_input_pass_through.scene.json (100%) delete mode 100644 src/bin/update_snapshots/main.rs create mode 100644 src/snapshot_tests/image_tests.rs create mode 100644 src/snapshot_tests/input.rs create mode 100644 src/snapshot_tests/rescaler_tests.rs create mode 100644 src/snapshot_tests/shader_tests.rs create mode 100644 src/snapshot_tests/simple_tests.rs create mode 100644 src/snapshot_tests/snapshot.rs delete mode 100644 src/snapshot_tests/tests.rs create mode 100644 src/snapshot_tests/text_tests.rs create mode 100644 src/snapshot_tests/tiles_tests.rs create mode 100644 src/snapshot_tests/tiles_transitions_tests.rs create mode 100644 src/snapshot_tests/transition_tests.rs create mode 100644 src/snapshot_tests/view_tests.rs diff --git a/Cargo.toml b/Cargo.toml index 5ff8a49ab..c0261eb4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ resolver = "2" [features] default = ["web_renderer"] +update_snapshots = [] decklink = ["compositor_api/decklink"] web_renderer = ["dep:compositor_chromium", "compositor_api/web_renderer"] diff --git a/build_tools/nix/package.nix b/build_tools/nix/package.nix index 2c1d9e512..f28ce969f 100644 --- a/build_tools/nix/package.nix +++ b/build_tools/nix/package.nix @@ -51,7 +51,6 @@ rustPlatform.buildRustPackage { '' rm -f $out/bin/live_compositor rm -f $out/bin/package_for_release - rm -f $out/bin/update_snapshots mv $out/bin/main_process $out/bin/live_compositor '' + ( diff --git a/snapshot_tests/simple_input_pass_through.scene.json b/snapshot_tests/simple/simple_input_pass_through.scene.json similarity index 100% rename from snapshot_tests/simple_input_pass_through.scene.json rename to snapshot_tests/simple/simple_input_pass_through.scene.json diff --git a/snapshot_tests/snapshots b/snapshot_tests/snapshots index d8becda39..0d8cc569b 160000 --- a/snapshot_tests/snapshots +++ b/snapshot_tests/snapshots @@ -1 +1 @@ -Subproject commit d8becda39b0c167a7f4ddee67878d97f75ffad8e +Subproject commit 0d8cc569b9f616de79c62dbe1e10d3aa3db0cd39 diff --git a/src/bin/update_snapshots/main.rs b/src/bin/update_snapshots/main.rs deleted file mode 100644 index 7d47bd8d5..000000000 --- a/src/bin/update_snapshots/main.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::{collections::HashSet, fs, io}; - -#[path = "../../snapshot_tests/tests.rs"] -mod tests; - -#[allow(dead_code)] -#[path = "../../snapshot_tests/utils.rs"] -mod utils; - -#[path = "../../snapshot_tests/test_case.rs"] -mod test_case; - -use tests::snapshot_tests; - -use crate::{ - test_case::TestCaseInstance, - utils::{find_unused_snapshots, snapshots_path}, -}; - -fn main() { - println!("Updating snapshots:"); - let log_filter = tracing_subscriber::EnvFilter::new("info,wgpu_core=warn,wgpu_hal=warn"); - tracing_subscriber::fmt().with_env_filter(log_filter).init(); - - let tests: Vec<_> = snapshot_tests(); - let has_only_flag = tests.iter().any(|t| t.only); - let tests: Vec<_> = if has_only_flag { - tests - .into_iter() - .filter(|t| t.only) - .map(TestCaseInstance::new) - .collect() - } else { - tests.into_iter().map(TestCaseInstance::new).collect() - }; - for test in tests.iter() { - for pts in &test.case.timestamps { - let (snapshot, Err(_)) = test.test_snapshots_for_pts(*pts) else { - println!("PASS: \"{}\" (pts: {}ms)", test.case.name, pts.as_millis()); - continue; - }; - - println!( - "UPDATE: \"{}\" (pts: {}ms)", - test.case.name, - pts.as_millis() - ); - - let snapshot_path = snapshot.save_path(); - - if let Err(err) = fs::remove_file(&snapshot_path) { - if err.kind() != io::ErrorKind::NotFound { - panic!("Failed to remove old snapshots: {err}"); - } - } - let parent_folder = snapshot_path.parent().unwrap(); - if !parent_folder.exists() { - fs::create_dir_all(parent_folder).unwrap(); - } - - let width = snapshot.resolution.width - (snapshot.resolution.width % 2); - let height = snapshot.resolution.height - (snapshot.resolution.height % 2); - image::save_buffer( - snapshot_path, - &snapshot.data, - width as u32, - height as u32, - image::ColorType::Rgba8, - ) - .unwrap(); - } - } - if !has_only_flag { - // Check for unused snapshots - let snapshot_paths = tests - .iter() - .flat_map(TestCaseInstance::snapshot_paths) - .collect::>(); - for path in find_unused_snapshots(&snapshot_paths, snapshots_path()) { - println!("Removed unused snapshot {path:?}"); - fs::remove_file(path).unwrap(); - } - } - println!("Update finished"); -} diff --git a/src/lib.rs b/src/lib.rs index f24d5211f..d0a1c5f43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,3 +4,6 @@ pub mod middleware; pub mod routes; pub mod server; pub mod state; + +#[cfg(test)] +mod snapshot_tests; diff --git a/src/main.rs b/src/main.rs index c463d9312..dbe1771a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,6 @@ mod routes; mod server; mod state; -#[cfg(test)] -mod snapshot_tests; - fn main() { #[cfg(feature = "web_renderer")] { diff --git a/src/snapshot_tests.rs b/src/snapshot_tests.rs index 6f5fb8639..54122e53e 100644 --- a/src/snapshot_tests.rs +++ b/src/snapshot_tests.rs @@ -1,89 +1,134 @@ -use std::{collections::HashSet, env, fs, path::PathBuf}; - -use self::{ - test_case::{TestCaseError, TestCaseInstance}, - tests::snapshot_tests, - utils::{find_unused_snapshots, snapshots_path}, +use std::{ + collections::HashSet, + fs, + path::{Path, PathBuf}, + time::Duration, }; +use compositor_api::types::UpdateOutputRequest; +use compositor_render::{scene::Component, Resolution}; +use test_case::{TestCase, TestResult, OUTPUT_ID}; +use utils::SNAPSHOTS_DIR_NAME; + +mod input; +mod snapshot; mod test_case; -mod tests; mod utils; -#[test] -fn test_snapshots() { - let tests: Vec = snapshot_tests() - .into_iter() - .map(TestCaseInstance::new) - .collect(); +mod image_tests; +mod rescaler_tests; +mod shader_tests; +mod simple_tests; +mod text_tests; +mod tiles_tests; +mod tiles_transitions_tests; +mod transition_tests; +mod view_tests; - check_test_names_uniqueness(&tests); +const DEFAULT_RESOLUTION: Resolution = Resolution { + width: 640, + height: 360, +}; - for test in tests.iter() { - println!("Test \"{}\"", test.case.name); - if let Err(err) = test.run() { - handle_error(err); +struct TestRunner { + cases: Vec, + snapshot_dir: PathBuf, +} + +impl TestRunner { + fn new(snapshot_dir: PathBuf) -> Self { + Self { + cases: Vec::new(), + snapshot_dir, } } - // Check for unused snapshots - let snapshot_paths = tests - .iter() - .flat_map(TestCaseInstance::snapshot_paths) - .collect::>(); - let unused_snapshots = find_unused_snapshots(&snapshot_paths, snapshots_path()); - if !unused_snapshots.is_empty() { - panic!("Some snapshots were not used: {unused_snapshots:#?}") + fn add(&mut self, case: TestCase) { + self.cases.push(case) } -} -fn handle_error(err: TestCaseError) { - let TestCaseError::Mismatch { - ref snapshot_from_disk, - ref produced_snapshot, - .. - } = err - else { - panic!("{err}"); - }; - - let failed_snapshot_path = failed_snapshot_path(); - if !failed_snapshot_path.exists() { - fs::create_dir_all(&failed_snapshot_path).unwrap(); + fn run(self) { + check_test_names_uniqueness(&self.cases); + check_unused_snapshots(&self.cases, &self.snapshot_dir); + let has_only = self.cases.iter().any(|test| test.only); + + let mut failed = false; + for test in self.cases.iter() { + if has_only && !test.only { + continue; + } + println!("Test \"{}\"", test.name); + if let TestResult::Failure = test.run() { + failed = true; + } + } + if failed { + panic!("Test failed") + } } - let snapshot_save_path = produced_snapshot.save_path(); - let snapshot_name = snapshot_save_path.file_name().unwrap().to_string_lossy(); - - let width = produced_snapshot.resolution.width - (produced_snapshot.resolution.width % 2); - let height = produced_snapshot.resolution.height - (produced_snapshot.resolution.height % 2); - image::save_buffer( - failed_snapshot_path.join(format!("mismatched_{snapshot_name}")), - &produced_snapshot.data, - width as u32, - height as u32, - image::ColorType::Rgba8, - ) - .unwrap(); - - snapshot_from_disk - .save(failed_snapshot_path.join(format!("original_{snapshot_name}"))) - .unwrap(); - - panic!("{err}"); } -fn failed_snapshot_path() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("failed_snapshot_tests") +fn scene_from_json(scene: &'static str) -> Vec { + let scene: UpdateOutputRequest = serde_json::from_str(scene).unwrap(); + vec![scene.video.unwrap().try_into().unwrap()] +} + +fn scenes_from_json(scenes: &[&'static str]) -> Vec { + scenes + .iter() + .map(|scene| { + let scene: UpdateOutputRequest = serde_json::from_str(scene).unwrap(); + scene.video.unwrap().try_into().unwrap() + }) + .collect() } -fn check_test_names_uniqueness(tests: &[TestCaseInstance]) { +fn check_test_names_uniqueness(tests: &[TestCase]) { let mut test_names = HashSet::new(); for test in tests.iter() { - if !test_names.insert(test.case.name) { + if !test_names.insert(test.name) { panic!( "Multiple snapshots tests with the same name: \"{}\".", - test.case.name + test.name ); } } } + +fn snapshots_path() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(SNAPSHOTS_DIR_NAME) +} + +fn snapshot_save_path(test_name: &str, pts: &Duration) -> PathBuf { + let out_file_name = format!("{}_{}_{}.png", test_name, pts.as_millis(), OUTPUT_ID); + snapshots_path().join(out_file_name) +} + +fn check_unused_snapshots(tests: &[TestCase], snapshot_dir: &Path) { + let existing_snapshots = tests + .iter() + .flat_map(TestCase::snapshot_paths) + .collect::>(); + let mut unused_snapshots = Vec::new(); + for entry in fs::read_dir(snapshot_dir).unwrap() { + let entry = entry.unwrap(); + if !entry.file_name().to_string_lossy().ends_with(".png") { + continue; + } + + if !existing_snapshots.contains(&entry.path()) { + unused_snapshots.push(entry.path()) + } + } + + if !unused_snapshots.is_empty() { + if cfg!(feature = "update_snapshots") { + for snapshot_path in unused_snapshots { + println!("DELETE: Unused snapshot {snapshot_path:?}"); + fs::remove_file(snapshot_path).unwrap(); + } + } else { + panic!("Some snapshots were not used: {unused_snapshots:#?}") + } + } +} diff --git a/src/snapshot_tests/image_tests.rs b/src/snapshot_tests/image_tests.rs new file mode 100644 index 000000000..60360413e --- /dev/null +++ b/src/snapshot_tests/image_tests.rs @@ -0,0 +1,76 @@ +use compositor_render::{ + image::{ImageSource, ImageSpec, ImageType}, + RendererId, RendererSpec, +}; + +use super::{ + input::TestInput, scene_from_json, scenes_from_json, snapshots_path, test_case::TestCase, + TestRunner, +}; + +#[test] +fn image_tests() { + let mut runner = TestRunner::new(snapshots_path().join("image")); + + let image_renderer = ( + RendererId("image_jpeg".into()), + RendererSpec::Image(ImageSpec { + src: ImageSource::Url { + url: "https://www.rust-lang.org/static/images/rust-social.jpg".to_string(), + }, + image_type: ImageType::Jpeg, + }), + ); + + runner.add(TestCase { + name: "image/jpeg_as_root", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/image/jpeg_as_root.scene.json" + )), + renderers: vec![image_renderer.clone()], + inputs: vec![TestInput::new(1)], + ..Default::default() + }); + runner.add(TestCase { + name: "image/jpeg_in_view", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/image/jpeg_in_view.scene.json" + )), + renderers: vec![image_renderer.clone()], + inputs: vec![TestInput::new(1)], + ..Default::default() + }); + runner.add(TestCase { + name: "image/jpeg_in_view_overflow_fit", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/image/jpeg_in_view_overflow_fit.scene.json" + )), + renderers: vec![image_renderer.clone()], + inputs: vec![TestInput::new(1)], + ..Default::default() + }); + runner.add(TestCase { + // Test if removing image from scene works + name: "image/remove_jpeg_as_root", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/image/jpeg_as_root.scene.json"), + include_str!("../../snapshot_tests/view/empty_view.scene.json"), + ]), + renderers: vec![image_renderer.clone()], + inputs: vec![TestInput::new(1)], + ..Default::default() + }); + runner.add(TestCase { + // Test if removing image from scene works + name: "image/remove_jpeg_in_view", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/image/jpeg_in_view.scene.json"), + include_str!("../../snapshot_tests/view/empty_view.scene.json"), + ]), + renderers: vec![image_renderer.clone()], + inputs: vec![TestInput::new(1)], + ..Default::default() + }); + + runner.run() +} diff --git a/src/snapshot_tests/input.rs b/src/snapshot_tests/input.rs new file mode 100644 index 000000000..b01567772 --- /dev/null +++ b/src/snapshot_tests/input.rs @@ -0,0 +1,111 @@ +use compositor_render::{scene::RGBColor, FrameData, Resolution, YuvPlanes}; + +#[derive(Debug, Clone)] +pub(super) struct TestInput { + pub name: String, + pub resolution: Resolution, + pub data: FrameData, +} + +impl TestInput { + const COLOR_VARIANTS: [RGBColor; 17] = [ + // RED, input_0 + RGBColor(255, 0, 0), + // GREEN, input_1 + RGBColor(0, 255, 0), + // YELLOW, input_2 + RGBColor(255, 255, 0), + // MAGENTA, input_3 + RGBColor(255, 0, 255), + // BLUE, input_4 + RGBColor(0, 0, 255), + // CYAN, input_5 + RGBColor(0, 255, 255), + // ORANGE, input_6 + RGBColor(255, 165, 0), + // WHITE, input_7 + RGBColor(255, 255, 255), + // GRAY, input_8 + RGBColor(128, 128, 128), + // LIGHT_RED, input_9 + RGBColor(255, 128, 128), + // LIGHT_BLUE, input_10 + RGBColor(128, 128, 255), + // LIGHT_GREEN, input_11 + RGBColor(128, 255, 128), + // PINK, input_12 + RGBColor(255, 192, 203), + // PURPLE, input_13 + RGBColor(128, 0, 128), + // BROWN, input_14 + RGBColor(165, 42, 42), + // YELLOW_GREEN, input_15 + RGBColor(154, 205, 50), + // LIGHT_YELLOW, input_16 + RGBColor(255, 255, 224), + ]; + + pub fn new(index: usize) -> Self { + Self::new_with_resolution( + index, + Resolution { + width: 640, + height: 360, + }, + ) + } + + pub fn new_with_resolution(index: usize, resolution: Resolution) -> Self { + let color = Self::COLOR_VARIANTS[index].to_yuv(); + let mut y_plane = vec![0; resolution.width * resolution.height]; + let mut u_plane = vec![0; (resolution.width * resolution.height) / 4]; + let mut v_plane = vec![0; (resolution.width * resolution.height) / 4]; + + let yuv_color = |x: usize, y: usize| { + const BORDER_SIZE: usize = 18; + const GRID_SIZE: usize = 72; + + let is_border_in_x = + x <= BORDER_SIZE || (x <= resolution.width && x >= resolution.width - BORDER_SIZE); + let is_border_in_y: bool = y <= BORDER_SIZE + || (y <= resolution.height && y >= resolution.height - BORDER_SIZE); + let is_on_grid = (x / GRID_SIZE + y / GRID_SIZE) % 2 == 0; + + let mut y = color.0; + if is_border_in_x || is_border_in_y || is_on_grid { + y -= 0.2; + } + + (y.clamp(0.0, 1.0), color.1, color.2) + }; + + for x_coord in 0..resolution.width { + for y_coord in 0..resolution.height { + let (y, u, v) = yuv_color(x_coord, y_coord); + if x_coord % 2 == 0 && y_coord % 2 == 0 { + let (_, u2, v2) = yuv_color(x_coord + 1, y_coord); + let (_, u3, v3) = yuv_color(x_coord, y_coord + 1); + let (_, u4, v4) = yuv_color(x_coord + 1, y_coord + 1); + + let coord = (y_coord / 2) * (resolution.width / 2) + (x_coord / 2); + u_plane[coord] = ((u + u2 + u3 + u4) * 64.0) as u8; + v_plane[coord] = ((v + v2 + v3 + v4) * 64.0) as u8; + } + + y_plane[y_coord * resolution.width + x_coord] = (y * 255.0) as u8; + } + } + + let data = FrameData::PlanarYuv420(YuvPlanes { + y_plane: y_plane.into(), + u_plane: u_plane.into(), + v_plane: v_plane.into(), + }); + + Self { + name: format!("input_{index}"), + resolution, + data, + } + } +} diff --git a/src/snapshot_tests/rescaler_tests.rs b/src/snapshot_tests/rescaler_tests.rs new file mode 100644 index 000000000..a14b7d348 --- /dev/null +++ b/src/snapshot_tests/rescaler_tests.rs @@ -0,0 +1,250 @@ +use compositor_render::Resolution; + +use super::{ + input::TestInput, scene_from_json, snapshots_path, test_case::TestCase, TestRunner, + DEFAULT_RESOLUTION, +}; + +#[test] +fn rescaler_tests() { + let mut runner = TestRunner::new(snapshots_path().join("rescaler")); + let default = TestCase { + inputs: vec![TestInput::new(1)], + ..Default::default() + }; + + let higher_than_default_resolution = Resolution { + width: DEFAULT_RESOLUTION.width, + height: DEFAULT_RESOLUTION.height + 100, + }; + let lower_than_default_resolution = Resolution { + width: DEFAULT_RESOLUTION.width, + height: DEFAULT_RESOLUTION.height - 100, + }; + let portrait_resolution = Resolution { + width: 360, + height: 640, + }; + let higher_than_default = TestInput::new_with_resolution(1, higher_than_default_resolution); + let lower_than_default = TestInput::new_with_resolution(1, lower_than_default_resolution); + let portrait = TestInput::new_with_resolution(1, portrait_resolution); + + runner.add(TestCase { + name: "rescaler/fit_view_with_known_height", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_view_with_known_height.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_view_with_known_width", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_view_with_known_width.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_view_with_unknown_width_and_height", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_view_with_unknown_width_and_height.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fill_input_stream_inverted_aspect_ratio_align_top_left", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fill_input_stream_align_top_left.scene.json" + )), + inputs: vec![portrait.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fill_input_stream_inverted_aspect_ratio_align_bottom_right", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fill_input_stream_align_bottom_right.scene.json" + )), + inputs: vec![portrait.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fill_input_stream_lower_aspect_ratio_align_bottom_right", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fill_input_stream_align_bottom_right.scene.json" + )), + inputs: vec![lower_than_default.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fill_input_stream_lower_aspect_ratio", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fill_input_stream.scene.json" + )), + inputs: vec![lower_than_default.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fill_input_stream_higher_aspect_ratio", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fill_input_stream.scene.json" + )), + inputs: vec![higher_than_default.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fill_input_stream_inverted_aspect_ratio", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fill_input_stream.scene.json" + )), + inputs: vec![portrait.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fill_input_stream_matching_aspect_ratio", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fill_input_stream.scene.json" + )), + inputs: vec![TestInput::new(1)], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_input_stream_lower_aspect_ratio", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_input_stream.scene.json" + )), + inputs: vec![lower_than_default.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_input_stream_higher_aspect_ratio", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_input_stream.scene.json" + )), + inputs: vec![higher_than_default.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_input_stream_higher_aspect_ratio_small_resolution", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_input_stream.scene.json" + )), + inputs: vec![TestInput::new_with_resolution( + 1, + Resolution { + width: higher_than_default_resolution.width / 10, + height: higher_than_default_resolution.height / 10, + }, + )], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_input_stream_inverted_aspect_ratio_align_top_left", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_input_stream_align_top_left.scene.json" + )), + inputs: vec![portrait.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_input_stream_inverted_aspect_ratio_align_bottom_right", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_input_stream_align_bottom_right.scene.json" + )), + inputs: vec![portrait.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_input_stream_lower_aspect_ratio_align_bottom_right", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_input_stream_align_bottom_right.scene.json" + )), + inputs: vec![lower_than_default.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_input_stream_inverted_aspect_ratio", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_input_stream.scene.json" + )), + inputs: vec![portrait.clone()], + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/fit_input_stream_matching_aspect_ratio", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/fit_input_stream.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/border_radius", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/border_radius.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/border_width", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/border_width.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/box_shadow", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/box_shadow.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/border_radius_border_box_shadow", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/border_radius_border_box_shadow.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/border_radius_box_shadow", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/border_radius_box_shadow.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/border_radius_box_shadow_fit_input_stream", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/border_radius_box_shadow_fit_input_stream.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/border_radius_box_shadow_fill_input_stream", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/border_radius_box_shadow_fill_input_stream.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/nested_border_width_radius", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/nested_border_width_radius.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "rescaler/nested_border_width_radius_aligned", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/nested_border_width_radius_aligned.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + // it is supposed to be cut off because of the rescaler that wraps it + name: "rescaler/border_radius_border_box_shadow_rescaled", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/rescaler/border_radius_border_box_shadow_rescaled.scene.json" + )), + ..default.clone() + }); + runner.run() +} diff --git a/src/snapshot_tests/shader_tests.rs b/src/snapshot_tests/shader_tests.rs new file mode 100644 index 000000000..126bce552 --- /dev/null +++ b/src/snapshot_tests/shader_tests.rs @@ -0,0 +1,262 @@ +use std::time::Duration; + +use compositor_render::{ + scene::{ + Component, InputStreamComponent, ShaderComponent, ShaderParam, ShaderParamStructField, + }, + shader::ShaderSpec, + InputId, RendererId, RendererSpec, +}; + +use super::DEFAULT_RESOLUTION; + +use super::{input::TestInput, scene_from_json, snapshots_path, test_case::TestCase, TestRunner}; + +#[test] +fn shader_tests() { + let mut runner = TestRunner::new(snapshots_path().join("shader")); + + let input1 = TestInput::new(1); + let input2 = TestInput::new(2); + let input3 = TestInput::new(3); + let input4 = TestInput::new(4); + let input5 = TestInput::new(5); + + let plane_id_shader = ( + RendererId("base_params_plane_id".into()), + RendererSpec::Shader(ShaderSpec { + source: include_str!("../../snapshot_tests/shader/layout_planes.wgsl").into(), + }), + ); + + let time_shader = ( + RendererId("base_params_time".into()), + RendererSpec::Shader(ShaderSpec { + source: include_str!("../../snapshot_tests/shader/fade_to_ball.wgsl").into(), + }), + ); + + let texture_count_shader = ( + RendererId("base_params_texture_count".into()), + RendererSpec::Shader(ShaderSpec { + source: include_str!( + "../../snapshot_tests/shader/color_output_with_texture_count.wgsl" + ) + .into(), + }), + ); + + let output_resolution_shader = ( + RendererId("base_params_output_resolution".into()), + RendererSpec::Shader(ShaderSpec { + source: include_str!("../../snapshot_tests/shader/red_border.wgsl").into(), + }), + ); + + runner.add(TestCase { + name: "shader/base_params_plane_id_no_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/shader/base_params_plane_id_no_inputs.scene.json" + )), + renderers: vec![plane_id_shader.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "shader/base_params_plane_id_5_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/shader/base_params_plane_id_5_inputs.scene.json" + )), + renderers: vec![plane_id_shader.clone()], + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + input4.clone(), + input5.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "shader/base_params_time", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/shader/base_params_time.scene.json" + )), + renderers: vec![time_shader.clone()], + inputs: vec![input1.clone()], + timestamps: vec![ + Duration::from_secs(0), + Duration::from_secs(1), + Duration::from_secs(2), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "shader/base_params_output_resolution", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/shader/base_params_output_resolution.scene.json" + )), + renderers: vec![output_resolution_shader.clone()], + inputs: vec![input1.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "shader/base_params_texture_count_no_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/shader/base_params_texture_count_no_inputs.scene.json" + )), + renderers: vec![texture_count_shader.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "shader/base_params_texture_count_1_input", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/shader/base_params_texture_count_1_input.scene.json" + )), + renderers: vec![texture_count_shader.clone()], + inputs: vec![input1.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "shader/base_params_texture_count_2_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/shader/base_params_texture_count_2_inputs.scene.json" + )), + renderers: vec![texture_count_shader.clone()], + inputs: vec![input1.clone(), input2.clone()], + ..Default::default() + }); + + user_params_snapshot_tests(&mut runner); + + runner.run() +} + +fn user_params_snapshot_tests(runner: &mut TestRunner) { + struct CircleLayout { + pub left_px: u32, + pub top_px: u32, + pub width_px: u32, + pub height_px: u32, + /// RGBA 0.0 - 1.0 range + pub background_color: [f32; 4], + } + + impl CircleLayout { + pub fn shader_param(&self) -> ShaderParam { + ShaderParam::Struct(vec![ + ShaderParamStructField { + field_name: "left_px".to_string(), + value: ShaderParam::U32(self.left_px), + }, + ShaderParamStructField { + field_name: "top_px".to_string(), + value: ShaderParam::U32(self.top_px), + }, + ShaderParamStructField { + field_name: "width_px".to_string(), + value: ShaderParam::U32(self.width_px), + }, + ShaderParamStructField { + field_name: "height_px".to_string(), + value: ShaderParam::U32(self.height_px), + }, + ShaderParamStructField { + field_name: "background_color".to_string(), + value: ShaderParam::List(vec![ + ShaderParam::F32(self.background_color[0]), + ShaderParam::F32(self.background_color[1]), + ShaderParam::F32(self.background_color[2]), + ShaderParam::F32(self.background_color[3]), + ]), + }, + ]) + } + } + + let input1 = TestInput::new(1); + let input2 = TestInput::new(2); + let input3 = TestInput::new(3); + let input4 = TestInput::new(4); + + const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; + const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0]; + const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0]; + const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; + + let shader_id = RendererId("user_params_circle_layout".into()); + + let layout1 = CircleLayout { + left_px: 0, + top_px: 0, + width_px: (DEFAULT_RESOLUTION.width / 2) as u32, + height_px: (DEFAULT_RESOLUTION.height / 2) as u32, + background_color: RED, + }; + + let layout2 = CircleLayout { + left_px: (DEFAULT_RESOLUTION.width / 2) as u32, + top_px: 0, + width_px: (DEFAULT_RESOLUTION.width / 2) as u32, + height_px: (DEFAULT_RESOLUTION.height / 2) as u32, + background_color: GREEN, + }; + + let layout3 = CircleLayout { + left_px: 0, + top_px: (DEFAULT_RESOLUTION.height / 2) as u32, + width_px: (DEFAULT_RESOLUTION.width / 2) as u32, + height_px: (DEFAULT_RESOLUTION.height / 2) as u32, + background_color: BLUE, + }; + + let layout4 = CircleLayout { + left_px: (DEFAULT_RESOLUTION.width / 2) as u32, + top_px: (DEFAULT_RESOLUTION.height / 2) as u32, + width_px: (DEFAULT_RESOLUTION.width / 2) as u32, + height_px: (DEFAULT_RESOLUTION.height / 2) as u32, + background_color: WHITE, + }; + + let circle_layout_scene = Component::Shader(ShaderComponent { + id: None, + shader_id: shader_id.clone(), + shader_param: Some(ShaderParam::List(vec![ + layout1.shader_param(), + layout2.shader_param(), + layout3.shader_param(), + layout4.shader_param(), + ])), + size: DEFAULT_RESOLUTION.into(), + children: vec![ + Component::InputStream(InputStreamComponent { + id: None, + input_id: InputId(input1.name.clone().into()), + }), + Component::InputStream(InputStreamComponent { + id: None, + input_id: InputId(input2.name.clone().into()), + }), + Component::InputStream(InputStreamComponent { + id: None, + input_id: InputId(input3.name.clone().into()), + }), + Component::InputStream(InputStreamComponent { + id: None, + input_id: InputId(input4.name.clone().into()), + }), + ], + }); + + runner.add(TestCase { + name: "shader/user_params_circle_layout", + scene_updates: vec![circle_layout_scene], + renderers: vec![( + shader_id.clone(), + RendererSpec::Shader(ShaderSpec { + source: include_str!("../../snapshot_tests/shader/circle_layout.wgsl").into(), + }), + )], + inputs: vec![input1, input2, input3, input4], + ..Default::default() + }); +} diff --git a/src/snapshot_tests/simple_tests.rs b/src/snapshot_tests/simple_tests.rs new file mode 100644 index 000000000..9cbd63103 --- /dev/null +++ b/src/snapshot_tests/simple_tests.rs @@ -0,0 +1,17 @@ +use super::{input::TestInput, scene_from_json, snapshots_path, test_case::TestCase, TestRunner}; + +#[test] +fn simple_tests() { + let mut runner = TestRunner::new(snapshots_path().join("simple")); + + runner.add(TestCase { + name: "simple/simple_input_pass_through", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/simple/simple_input_pass_through.scene.json" + )), + inputs: vec![TestInput::new(1)], + ..Default::default() + }); + + runner.run() +} diff --git a/src/snapshot_tests/snapshot.rs b/src/snapshot_tests/snapshot.rs new file mode 100644 index 000000000..395e63617 --- /dev/null +++ b/src/snapshot_tests/snapshot.rs @@ -0,0 +1,90 @@ +use std::{ + fs::{self, create_dir_all}, + path::PathBuf, + time::Duration, +}; + +use compositor_render::Resolution; + +use super::snapshot_save_path; + +#[derive(Debug, Clone)] +pub(super) struct Snapshot { + pub test_name: String, + pub pts: Duration, + pub resolution: Resolution, + pub data: Vec, +} + +impl Snapshot { + pub(super) fn save_path(&self) -> PathBuf { + snapshot_save_path(&self.test_name, &self.pts) + } + + pub(super) fn diff_with_saved(&self) -> f32 { + let save_path = self.save_path(); + if !save_path.exists() { + return 1000.0; + } + let old_snapshot = image::open(save_path).unwrap().to_rgba8(); + snapshots_diff(&old_snapshot, &self.data) + } + + pub(super) fn update_on_disk(&self) { + let width = self.resolution.width - (self.resolution.width % 2); + let height = self.resolution.height - (self.resolution.height % 2); + let save_path = self.save_path(); + create_dir_all(save_path.parent().unwrap()).unwrap(); + image::save_buffer( + save_path, + &self.data, + width as u32, + height as u32, + image::ColorType::Rgba8, + ) + .unwrap(); + } + + pub(super) fn write_as_failed_snapshot(&self) { + let failed_snapshot_path = + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("failed_snapshot_tests"); + create_dir_all(&failed_snapshot_path).unwrap(); + + let snapshot_name = self + .save_path() + .file_name() + .unwrap() + .to_string_lossy() + .to_string(); + + let width = self.resolution.width - (self.resolution.width % 2); + let height = self.resolution.height - (self.resolution.height % 2); + image::save_buffer( + failed_snapshot_path.join(format!("actual_{snapshot_name}")), + &self.data, + width as u32, + height as u32, + image::ColorType::Rgba8, + ) + .unwrap(); + + fs::copy( + self.save_path(), + failed_snapshot_path.join(format!("expected_{snapshot_name}")), + ) + .unwrap(); + } +} + +fn snapshots_diff(old_snapshot: &[u8], new_snapshot: &[u8]) -> f32 { + if old_snapshot.len() != new_snapshot.len() { + return 10000.0; + } + let square_error: f32 = old_snapshot + .iter() + .zip(new_snapshot) + .map(|(a, b)| (*a as i32 - *b as i32).pow(2) as f32) + .sum(); + + square_error / old_snapshot.len() as f32 +} diff --git a/src/snapshot_tests/test_case.rs b/src/snapshot_tests/test_case.rs index 3cd2ce00b..48d46dd58 100644 --- a/src/snapshot_tests/test_case.rs +++ b/src/snapshot_tests/test_case.rs @@ -1,31 +1,30 @@ -use std::{fmt::Display, path::PathBuf, sync::Arc, time::Duration}; +use std::{path::PathBuf, sync::Arc, time::Duration}; -use super::utils::{create_renderer, frame_to_rgba, snaphot_save_path, snapshots_diff}; +use super::{ + input::TestInput, + snapshot::Snapshot, + snapshot_save_path, + utils::{create_renderer, frame_to_rgba}, +}; use anyhow::Result; -use compositor_api::types::{self}; use compositor_render::{ - scene::RGBColor, Frame, FrameData, FrameSet, InputId, OutputFrameFormat, OutputId, Renderer, - RendererId, RendererSpec, Resolution, YuvPlanes, + scene::Component, Frame, FrameSet, InputId, OutputFrameFormat, OutputId, Renderer, RendererId, + RendererSpec, Resolution, }; -use image::ImageBuffer; pub(super) const OUTPUT_ID: &str = "output_1"; -pub struct TestCase { +#[derive(Debug, Clone)] +pub(super) struct TestCase { pub name: &'static str, pub inputs: Vec, pub renderers: Vec<(RendererId, RendererSpec)>, pub timestamps: Vec, - pub scene_updates: Updates, - #[allow(dead_code)] + pub scene_updates: Vec, pub only: bool, pub allowed_error: f32, -} - -pub enum Updates { - Scene(&'static str, Resolution), - Scenes(Vec<(&'static str, Resolution)>), + pub resolution: Resolution, } impl Default for TestCase { @@ -35,116 +34,97 @@ impl Default for TestCase { inputs: Vec::new(), renderers: Vec::new(), timestamps: vec![Duration::from_secs(0)], - scene_updates: Updates::Scenes(vec![]), + scene_updates: vec![], only: false, allowed_error: 1.0, + resolution: Resolution { + width: 640, + height: 360, + }, } } } -pub struct TestCaseInstance { - pub case: TestCase, - pub renderer: Renderer, +pub(super) enum TestResult { + Success, + Failure, } -impl TestCaseInstance { - pub fn new(test_case: TestCase) -> TestCaseInstance { - if test_case.name.is_empty() { - panic!("Snapshot test name has to be provided"); - } - - let mut renderer = create_renderer(); - for (id, spec) in test_case.renderers.iter() { +impl TestCase { + fn renderer(&self) -> Renderer { + let renderer = create_renderer(); + for (id, spec) in self.renderers.iter() { renderer .register_renderer(id.clone(), spec.clone()) .unwrap(); } - for (index, _) in test_case.inputs.iter().enumerate() { + for (index, _) in self.inputs.iter().enumerate() { renderer.register_input(InputId(format!("input_{}", index + 1).into())) } - let outputs = match test_case.scene_updates { - Updates::Scene(scene, resolution) => vec![(scene, resolution)], - Updates::Scenes(ref scenes) => scenes.clone(), - }; + renderer + } - for (update_str, resolution) in outputs { - let scene: types::UpdateOutputRequest = serde_json::from_str(update_str).unwrap(); - if let Some(root) = scene.video { - renderer - .update_scene( - OutputId(OUTPUT_ID.into()), - resolution, - OutputFrameFormat::PlanarYuv420Bytes, - root.try_into().unwrap(), - ) - .unwrap(); - } + pub(super) fn run(&self) -> TestResult { + if self.name.is_empty() { + panic!("Snapshot test name has to be provided"); } + let mut renderer = self.renderer(); + let mut result = TestResult::Success; - TestCaseInstance { - case: test_case, - renderer, + for update in &self.scene_updates { + renderer + .update_scene( + OutputId(OUTPUT_ID.into()), + self.resolution, + OutputFrameFormat::PlanarYuv420Bytes, + update.clone(), + ) + .unwrap(); } - } - #[allow(dead_code)] - pub fn run(&self) -> Result<(), TestCaseError> { - for pts in self.case.timestamps.iter() { - let (_, test_result) = self.test_snapshots_for_pts(*pts); - test_result?; + for pts in self.timestamps.iter().copied() { + if let TestResult::Failure = self.test_snapshots_for_pts(&mut renderer, pts) { + result = TestResult::Failure; + } } - Ok(()) + result } - pub fn test_snapshots_for_pts(&self, pts: Duration) -> (Snapshot, Result<(), TestCaseError>) { - let snapshot = self.snapshot_for_pts(pts).unwrap(); - - let save_path = snapshot.save_path(); - if !save_path.exists() { - return ( - snapshot.clone(), - Err(TestCaseError::SnapshotNotFound(snapshot.clone())), - ); - } - - let snapshot_from_disk = image::open(&save_path).unwrap().to_rgba8(); - let snapshots_diff = snapshots_diff(&snapshot_from_disk, &snapshot.data); - if snapshots_diff > self.case.allowed_error { - return ( - snapshot.clone(), - Err(TestCaseError::Mismatch { - snapshot_from_disk: snapshot_from_disk.into(), - produced_snapshot: snapshot.clone(), - diff: snapshots_diff, - }), - ); - } + fn test_snapshots_for_pts(&self, renderer: &mut Renderer, pts: Duration) -> TestResult { + let snapshot = self.snapshot_for_pts(renderer, pts).unwrap(); + let snapshots_diff = snapshot.diff_with_saved(); if snapshots_diff > 0.0 { println!( "Snapshot error in range (allowed: {}, current: {})", - self.case.allowed_error, snapshots_diff + self.allowed_error, snapshots_diff ); } - - (snapshot, Ok(())) - } - - #[allow(dead_code)] - pub fn snapshot_paths(&self) -> Vec { - let mut paths = Vec::new(); - for pts in self.case.timestamps.iter() { - paths.push(snaphot_save_path(self.case.name, pts)); + if snapshots_diff > self.allowed_error { + if cfg!(feature = "update_snapshots") { + println!("UPDATE: \"{}\" (pts: {}ms)", self.name, pts.as_millis(),); + snapshot.update_on_disk(); + } else { + println!("FAILED: \"{}\" (pts: {}ms)", self.name, pts.as_millis(),); + snapshot.write_as_failed_snapshot(); + return TestResult::Failure; + } } + TestResult::Success + } - paths + pub(super) fn snapshot_paths(&self) -> Vec { + self.timestamps + .iter() + .map(|pts| snapshot_save_path(self.name, pts)) + .collect() } - pub fn snapshot_for_pts(&self, pts: Duration) -> Result { + fn snapshot_for_pts(&self, renderer: &mut Renderer, pts: Duration) -> Result { let mut frame_set = FrameSet::new(pts); - for input in self.case.inputs.iter() { + for input in self.inputs.iter() { let input_id = InputId::from(Arc::from(input.name.clone())); let frame = Frame { data: input.data.clone(), @@ -154,178 +134,15 @@ impl TestCaseInstance { frame_set.frames.insert(input_id, frame); } - let outputs = self.renderer.render(frame_set)?; + let outputs = renderer.render(frame_set)?; let output_frame = outputs.frames.get(&OutputId(OUTPUT_ID.into())).unwrap(); let new_snapshot = frame_to_rgba(output_frame); Ok(Snapshot { - test_name: self.case.name.to_owned(), + test_name: self.name.to_owned(), pts, resolution: output_frame.resolution, data: new_snapshot, }) } } - -#[derive(Debug, Clone)] -pub struct TestInput { - pub name: String, - pub resolution: Resolution, - pub data: FrameData, -} - -impl TestInput { - const COLOR_VARIANTS: [RGBColor; 17] = [ - // RED, input_0 - RGBColor(255, 0, 0), - // GREEN, input_1 - RGBColor(0, 255, 0), - // YELLOW, input_2 - RGBColor(255, 255, 0), - // MAGENTA, input_3 - RGBColor(255, 0, 255), - // BLUE, input_4 - RGBColor(0, 0, 255), - // CYAN, input_5 - RGBColor(0, 255, 255), - // ORANGE, input_6 - RGBColor(255, 165, 0), - // WHITE, input_7 - RGBColor(255, 255, 255), - // GRAY, input_8 - RGBColor(128, 128, 128), - // LIGHT_RED, input_9 - RGBColor(255, 128, 128), - // LIGHT_BLUE, input_10 - RGBColor(128, 128, 255), - // LIGHT_GREEN, input_11 - RGBColor(128, 255, 128), - // PINK, input_12 - RGBColor(255, 192, 203), - // PURPLE, input_13 - RGBColor(128, 0, 128), - // BROWN, input_14 - RGBColor(165, 42, 42), - // YELLOW_GREEN, input_15 - RGBColor(154, 205, 50), - // LIGHT_YELLOW, input_16 - RGBColor(255, 255, 224), - ]; - - pub fn new(index: usize) -> Self { - Self::new_with_resolution( - index, - Resolution { - width: 640, - height: 360, - }, - ) - } - - pub fn new_with_resolution(index: usize, resolution: Resolution) -> Self { - let color = Self::COLOR_VARIANTS[index].to_yuv(); - let mut y_plane = vec![0; resolution.width * resolution.height]; - let mut u_plane = vec![0; (resolution.width * resolution.height) / 4]; - let mut v_plane = vec![0; (resolution.width * resolution.height) / 4]; - - let yuv_color = |x: usize, y: usize| { - const BORDER_SIZE: usize = 18; - const GRID_SIZE: usize = 72; - - let is_border_in_x = - x <= BORDER_SIZE || (x <= resolution.width && x >= resolution.width - BORDER_SIZE); - let is_border_in_y: bool = y <= BORDER_SIZE - || (y <= resolution.height && y >= resolution.height - BORDER_SIZE); - let is_on_grid = (x / GRID_SIZE + y / GRID_SIZE) % 2 == 0; - - let mut y = color.0; - if is_border_in_x || is_border_in_y || is_on_grid { - y -= 0.2; - } - - (y.clamp(0.0, 1.0), color.1, color.2) - }; - - for x_coord in 0..resolution.width { - for y_coord in 0..resolution.height { - let (y, u, v) = yuv_color(x_coord, y_coord); - if x_coord % 2 == 0 && y_coord % 2 == 0 { - let (_, u2, v2) = yuv_color(x_coord + 1, y_coord); - let (_, u3, v3) = yuv_color(x_coord, y_coord + 1); - let (_, u4, v4) = yuv_color(x_coord + 1, y_coord + 1); - - let coord = (y_coord / 2) * (resolution.width / 2) + (x_coord / 2); - u_plane[coord] = ((u + u2 + u3 + u4) * 64.0) as u8; - v_plane[coord] = ((v + v2 + v3 + v4) * 64.0) as u8; - } - - y_plane[y_coord * resolution.width + x_coord] = (y * 255.0) as u8; - } - } - - let data = FrameData::PlanarYuv420(YuvPlanes { - y_plane: y_plane.into(), - u_plane: u_plane.into(), - v_plane: v_plane.into(), - }); - - Self { - name: format!("input_{index}"), - resolution, - data, - } - } -} - -#[derive(Debug, Clone)] -pub struct Snapshot { - pub test_name: String, - pub pts: Duration, - pub resolution: Resolution, - pub data: Vec, -} - -impl Snapshot { - pub fn save_path(&self) -> PathBuf { - snaphot_save_path(&self.test_name, &self.pts) - } -} - -#[derive(Debug)] -pub enum TestCaseError { - SnapshotNotFound(Snapshot), - Mismatch { - #[allow(dead_code)] - snapshot_from_disk: Box, Vec>>, - produced_snapshot: Snapshot, - diff: f32, - }, -} - -impl std::error::Error for TestCaseError {} - -impl Display for TestCaseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let err_msg = match self { - TestCaseError::SnapshotNotFound(Snapshot { test_name, pts, .. }) => format!( - "FAILED: \"{}\", PTS({}). Snapshot file not found. Generate snapshots first", - test_name, - pts.as_secs() - ), - TestCaseError::Mismatch { - produced_snapshot: Snapshot { test_name, pts, .. }, - diff, - .. - } => { - format!( - "FAILED: \"{}\", PTS({}). Snapshots are different error={}", - test_name, - pts.as_secs_f32(), - diff, - ) - } - }; - - f.write_str(&err_msg) - } -} diff --git a/src/snapshot_tests/tests.rs b/src/snapshot_tests/tests.rs deleted file mode 100644 index e14460595..000000000 --- a/src/snapshot_tests/tests.rs +++ /dev/null @@ -1,1807 +0,0 @@ -use std::time::Duration; - -use compositor_render::{ - image::{ImageSource, ImageSpec, ImageType}, - shader::ShaderSpec, - RendererId, RendererSpec, Resolution, -}; -use serde_json::{json, Value}; - -use super::test_case::{TestCase, TestInput, Updates}; - -const DEFAULT_RESOLUTION: Resolution = Resolution { - width: 640, - height: 360, -}; - -pub fn snapshot_tests() -> Vec { - let mut tests = Vec::new(); - tests.append(&mut base_snapshot_tests()); - tests.append(&mut view_snapshot_tests()); - tests.append(&mut transition_snapshot_tests()); - tests.append(&mut image_snapshot_tests()); - tests.append(&mut text_snapshot_tests()); - tests.append(&mut tiles_snapshot_tests()); - tests.append(&mut rescaler_snapshot_tests()); - tests.append(&mut shader_snapshot_tests()); - tests -} - -fn shader_snapshot_tests() -> Vec { - let mut base_params_snapshot_tests = shader_base_params_snapshot_tests(); - let mut user_params_snapshot_tests = shader_user_params_snapshot_tests(); - - base_params_snapshot_tests.append(&mut user_params_snapshot_tests); - base_params_snapshot_tests -} - -fn shader_user_params_snapshot_tests() -> Vec { - struct CircleLayout { - pub left_px: u32, - pub top_px: u32, - pub width_px: u32, - pub height_px: u32, - /// RGBA 0.0 - 1.0 range - pub background_color: [f32; 4], - } - - impl CircleLayout { - pub fn shader_param(&self) -> Value { - let background_color_params: Vec = self - .background_color - .iter() - .map(|val| { - { - json!({ - "type": "f32", - "value": val - }) - } - }) - .collect(); - - json!({ - "type": "struct", - "value": [ - { - "field_name": "left_px", - "type": "u32", - "value": self.left_px - }, - { - "field_name": "top_px", - "type": "u32", - "value": self.top_px - }, - { - "field_name": "width_px", - "type": "u32", - "value": self.width_px - }, - { - "field_name": "height_px", - "type": "u32", - "value": self.height_px - }, - { - "field_name": "background_color", - "type": "list", - "value": background_color_params - }, - ] - }) - } - } - - let input1 = TestInput::new(1); - let input2 = TestInput::new(2); - let input3 = TestInput::new(3); - let input4 = TestInput::new(4); - - const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; - const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0]; - const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0]; - const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; - - let circle_layout_shader = ( - RendererId("user_params_circle_layout".into()), - RendererSpec::Shader(ShaderSpec { - source: include_str!("../../snapshot_tests/shader/circle_layout.wgsl").into(), - }), - ); - - let layout1 = CircleLayout { - left_px: 0, - top_px: 0, - width_px: (DEFAULT_RESOLUTION.width / 2) as u32, - height_px: (DEFAULT_RESOLUTION.height / 2) as u32, - background_color: RED, - }; - - let layout2 = CircleLayout { - left_px: (DEFAULT_RESOLUTION.width / 2) as u32, - top_px: 0, - width_px: (DEFAULT_RESOLUTION.width / 2) as u32, - height_px: (DEFAULT_RESOLUTION.height / 2) as u32, - background_color: GREEN, - }; - - let layout3 = CircleLayout { - left_px: 0, - top_px: (DEFAULT_RESOLUTION.height / 2) as u32, - width_px: (DEFAULT_RESOLUTION.width / 2) as u32, - height_px: (DEFAULT_RESOLUTION.height / 2) as u32, - background_color: BLUE, - }; - - let layout4 = CircleLayout { - left_px: (DEFAULT_RESOLUTION.width / 2) as u32, - top_px: (DEFAULT_RESOLUTION.height / 2) as u32, - width_px: (DEFAULT_RESOLUTION.width / 2) as u32, - height_px: (DEFAULT_RESOLUTION.height / 2) as u32, - background_color: WHITE, - }; - - let shader_param = json!({ - "type": "list", - "value": [ - layout1.shader_param(), - layout2.shader_param(), - layout3.shader_param(), - layout4.shader_param(), - ] - }); - - let inputs = Vec::from([input1, input2, input3, input4]); - - let children: Vec = inputs - .iter() - .map(|input| { - json!({ - "type": "input_stream", - "input_id": input.name - }) - }) - .collect(); - - let circle_layout_scene = Box::new( - json!({ - "video": { - "root": { - "type": "shader", - "shader_id": "user_params_circle_layout", - "resolution": { - "width": DEFAULT_RESOLUTION.width, - "height": DEFAULT_RESOLUTION.height - }, - "shader_param": shader_param, - "children": children, - } - } - }) - .to_string(), - ); - - Vec::from([TestCase { - name: "shader/user_params_circle_layout", - scene_updates: Updates::Scene(circle_layout_scene.leak(), DEFAULT_RESOLUTION), - renderers: vec![circle_layout_shader], - inputs, - ..Default::default() - }]) -} - -fn shader_base_params_snapshot_tests() -> Vec { - let input1 = TestInput::new(1); - let input2 = TestInput::new(2); - let input3 = TestInput::new(3); - let input4 = TestInput::new(4); - let input5 = TestInput::new(5); - - let plane_id_shader = ( - RendererId("base_params_plane_id".into()), - RendererSpec::Shader(ShaderSpec { - source: include_str!("../../snapshot_tests/shader/layout_planes.wgsl").into(), - }), - ); - - let time_shader = ( - RendererId("base_params_time".into()), - RendererSpec::Shader(ShaderSpec { - source: include_str!("../../snapshot_tests/shader/fade_to_ball.wgsl").into(), - }), - ); - - let texture_count_shader = ( - RendererId("base_params_texture_count".into()), - RendererSpec::Shader(ShaderSpec { - source: include_str!( - "../../snapshot_tests/shader/color_output_with_texture_count.wgsl" - ) - .into(), - }), - ); - - let output_resolution_shader = ( - RendererId("base_params_output_resolution".into()), - RendererSpec::Shader(ShaderSpec { - source: include_str!("../../snapshot_tests/shader/red_border.wgsl").into(), - }), - ); - - Vec::from([ - TestCase { - name: "shader/base_params_plane_id_no_inputs", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/shader/base_params_plane_id_no_inputs.scene.json" - ), - DEFAULT_RESOLUTION, - ), - renderers: vec![plane_id_shader.clone()], - ..Default::default() - }, - TestCase { - name: "shader/base_params_plane_id_5_inputs", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/shader/base_params_plane_id_5_inputs.scene.json" - ), - DEFAULT_RESOLUTION, - ), - renderers: vec![plane_id_shader.clone()], - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - input4.clone(), - input5.clone(), - ], - ..Default::default() - }, - TestCase { - name: "shader/base_params_time", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/shader/base_params_time.scene.json"), - DEFAULT_RESOLUTION, - ), - renderers: vec![time_shader.clone()], - inputs: vec![input1.clone()], - timestamps: vec![ - Duration::from_secs(0), - Duration::from_secs(1), - Duration::from_secs(2), - ], - ..Default::default() - }, - TestCase { - name: "shader/base_params_output_resolution", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/shader/base_params_output_resolution.scene.json" - ), - DEFAULT_RESOLUTION, - ), - renderers: vec![output_resolution_shader.clone()], - inputs: vec![input1.clone()], - ..Default::default() - }, - TestCase { - name: "shader/base_params_texture_count_no_inputs", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/shader/base_params_texture_count_no_inputs.scene.json" - ), - DEFAULT_RESOLUTION, - ), - renderers: vec![texture_count_shader.clone()], - ..Default::default() - }, - TestCase { - name: "shader/base_params_texture_count_1_input", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/shader/base_params_texture_count_1_input.scene.json" - ), - DEFAULT_RESOLUTION, - ), - renderers: vec![texture_count_shader.clone()], - inputs: vec![input1.clone()], - ..Default::default() - }, - TestCase { - name: "shader/base_params_texture_count_2_inputs", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/shader/base_params_texture_count_2_inputs.scene.json" - ), - DEFAULT_RESOLUTION, - ), - renderers: vec![texture_count_shader.clone()], - inputs: vec![input1.clone(), input2.clone()], - ..Default::default() - }, - ]) -} - -fn rescaler_snapshot_tests() -> Vec { - let higher_than_default = Resolution { - width: DEFAULT_RESOLUTION.width, - height: DEFAULT_RESOLUTION.height + 100, - }; - let lower_than_default = Resolution { - width: DEFAULT_RESOLUTION.width, - height: DEFAULT_RESOLUTION.height - 100, - }; - let portrait_resolution = Resolution { - width: 360, - height: 640, - }; - Vec::from([ - TestCase { - name: "rescaler/fit_view_with_known_height", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_view_with_known_height.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "rescaler/fit_view_with_known_width", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_view_with_known_width.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "rescaler/fit_view_with_unknown_width_and_height", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_view_with_unknown_width_and_height.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "rescaler/fill_input_stream_inverted_aspect_ratio_align_top_left", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fill_input_stream_align_top_left.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, portrait_resolution)], - ..Default::default() - }, - TestCase { - name: "rescaler/fill_input_stream_inverted_aspect_ratio_align_bottom_right", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fill_input_stream_align_bottom_right.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, portrait_resolution)], - ..Default::default() - }, - TestCase { - name: "rescaler/fill_input_stream_lower_aspect_ratio_align_bottom_right", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fill_input_stream_align_bottom_right.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, lower_than_default)], - ..Default::default() - }, - TestCase { - name: "rescaler/fill_input_stream_lower_aspect_ratio", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fill_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, lower_than_default)], - ..Default::default() - }, - TestCase { - name: "rescaler/fill_input_stream_higher_aspect_ratio", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fill_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, higher_than_default)], - ..Default::default() - }, - TestCase { - name: "rescaler/fill_input_stream_inverted_aspect_ratio", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fill_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, portrait_resolution)], - ..Default::default() - }, - TestCase { - name: "rescaler/fill_input_stream_matching_aspect_ratio", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fill_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/fit_input_stream_lower_aspect_ratio", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, lower_than_default)], - ..Default::default() - }, - TestCase { - name: "rescaler/fit_input_stream_higher_aspect_ratio", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, higher_than_default)], - ..Default::default() - }, - TestCase { - name: "rescaler/fit_input_stream_higher_aspect_ratio_small_resolution", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, Resolution { width: higher_than_default.width / 10, height: higher_than_default.height / 10 })], - ..Default::default() - }, - TestCase { - name: "rescaler/fit_input_stream_inverted_aspect_ratio_align_top_left", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_input_stream_align_top_left.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, portrait_resolution)], - ..Default::default() - }, - TestCase { - name: "rescaler/fit_input_stream_inverted_aspect_ratio_align_bottom_right", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_input_stream_align_bottom_right.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, portrait_resolution)], - ..Default::default() - }, - TestCase { - name: "rescaler/fit_input_stream_lower_aspect_ratio_align_bottom_right", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_input_stream_align_bottom_right.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, lower_than_default)], - ..Default::default() - }, - TestCase { - name: "rescaler/fit_input_stream_inverted_aspect_ratio", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, portrait_resolution)], - ..Default::default() - }, - TestCase { - name: "rescaler/fit_input_stream_matching_aspect_ratio", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/fit_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/border_radius", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/border_radius.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/border_width", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/border_width.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/box_shadow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/box_shadow.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/border_radius_border_box_shadow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/border_radius_border_box_shadow.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/border_radius_box_shadow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/border_radius_box_shadow.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/border_radius_box_shadow_fit_input_stream", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/border_radius_box_shadow_fit_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/border_radius_box_shadow_fill_input_stream", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/border_radius_box_shadow_fill_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/nested_border_width_radius", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/nested_border_width_radius.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "rescaler/nested_border_width_radius_aligned", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/nested_border_width_radius_aligned.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - // it is supposed to be cut off because of the rescaler that wraps it - name: "rescaler/border_radius_border_box_shadow_rescaled", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/rescaler/border_radius_border_box_shadow_rescaled.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - } - ]) -} - -fn tiles_snapshot_tests() -> Vec { - let input1 = TestInput::new(1); - let input2 = TestInput::new(2); - let input3 = TestInput::new(3); - let input4 = TestInput::new(4); - let input5 = TestInput::new(5); - let input6 = TestInput::new(6); - let input7 = TestInput::new(7); - let input8 = TestInput::new(8); - let input9 = TestInput::new(9); - let input10 = TestInput::new(10); - let input11 = TestInput::new(11); - let input12 = TestInput::new(12); - let input13 = TestInput::new(13); - let input14 = TestInput::new(14); - let input15 = TestInput::new(15); - let portrait_resolution = Resolution { - width: 360, - height: 640, - }; - let portrait_input1 = TestInput::new_with_resolution(1, portrait_resolution); - let portrait_input2 = TestInput::new_with_resolution(2, portrait_resolution); - let portrait_input3 = TestInput::new_with_resolution(3, portrait_resolution); - let portrait_input4 = TestInput::new_with_resolution(4, portrait_resolution); - let portrait_input5 = TestInput::new_with_resolution(5, portrait_resolution); - let portrait_input6 = TestInput::new_with_resolution(6, portrait_resolution); - let portrait_input7 = TestInput::new_with_resolution(7, portrait_resolution); - let portrait_input8 = TestInput::new_with_resolution(8, portrait_resolution); - let portrait_input9 = TestInput::new_with_resolution(9, portrait_resolution); - let portrait_input10 = TestInput::new_with_resolution(10, portrait_resolution); - let portrait_input11 = TestInput::new_with_resolution(11, portrait_resolution); - let portrait_input12 = TestInput::new_with_resolution(12, portrait_resolution); - let portrait_input13 = TestInput::new_with_resolution(13, portrait_resolution); - let portrait_input14 = TestInput::new_with_resolution(14, portrait_resolution); - let portrait_input15 = TestInput::new_with_resolution(15, portrait_resolution); - Vec::from([ - TestCase { - name: "tiles_transitions/tile_resize_entire_component_with_parent_transition", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/tiles_transitions/start_tile_resize.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/tiles_transitions/end_tile_resize_with_view_transition.scene.json"), - DEFAULT_RESOLUTION, - ) - ]), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - ], - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(150), - Duration::from_millis(350), - // TODO: This transition does not look great, but it would require automatic - // transitions triggered by a size change (not scene update) - Duration::from_millis(450), - Duration::from_millis(500), - ], - ..Default::default() - }, - TestCase { - name: "tiles_transitions/tile_resize_entire_component_without_parent_transition", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/tiles_transitions/start_tile_resize.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/tiles_transitions/end_tile_resize.scene.json"), - DEFAULT_RESOLUTION, - ) - ]), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - ], - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(150), - Duration::from_millis(350), - Duration::from_millis(500), - ], - ..Default::default() - }, - TestCase { - name: "tiles_transitions/change_order_of_3_inputs_with_id", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/tiles_transitions/start_with_3_inputs_all_id.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/tiles_transitions/end_with_3_inputs_3_id_different_order.scene.json"), - DEFAULT_RESOLUTION, - ) - ]), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - ], - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(150), - Duration::from_millis(350), - Duration::from_millis(500), - ], - ..Default::default() - }, - TestCase { - name: "tiles_transitions/replace_component_by_adding_id", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/tiles_transitions/start_with_3_inputs_no_id.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/tiles_transitions/end_with_3_inputs_1_id.scene.json"), - DEFAULT_RESOLUTION, - ) - ]), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - input4.clone(), - ], - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(150), - Duration::from_millis(350), - Duration::from_millis(500), - ], - ..Default::default() - }, - TestCase { - name: "tiles_transitions/add_2_inputs_at_the_end_to_3_tiles_scene", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/tiles_transitions/start_with_3_inputs_no_id.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/tiles_transitions/end_with_5_inputs_no_id.scene.json"), - DEFAULT_RESOLUTION, - ) - ]), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - input4.clone(), - input5.clone(), - ], - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(150), - Duration::from_millis(350), - Duration::from_millis(500), - ], - ..Default::default() - }, - TestCase { - name: "tiles_transitions/add_input_on_2nd_pos_to_3_tiles_scene", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/tiles_transitions/start_with_3_inputs_no_id.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/tiles_transitions/end_with_4_inputs_1_id.scene.json"), - DEFAULT_RESOLUTION, - ) - ]), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - input4.clone(), - ], - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(150), - Duration::from_millis(350), - Duration::from_millis(500), - ], - ..Default::default() - }, - TestCase { - name: "tiles_transitions/add_input_at_the_end_to_3_tiles_scene", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/tiles_transitions/start_with_3_inputs_no_id.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/tiles_transitions/end_with_4_inputs_no_id.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/tiles_transitions/after_end_with_4_inputs_no_id.scene.json"), - DEFAULT_RESOLUTION, - ) - ]), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - input4.clone(), - ], - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(150), - Duration::from_millis(350), - Duration::from_millis(500), - ], - ..Default::default() - }, - TestCase { - name: "tiles/01_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/01_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/02_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/02_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone(), input2.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/03_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/03_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone(), input2.clone(), input3.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/04_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/04_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - input4.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/05_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/05_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - input4.clone(), - input5.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/15_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/15_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![ - input1.clone(), - input2.clone(), - input3.clone(), - input4.clone(), - input5.clone(), - input6.clone(), - input7.clone(), - input8.clone(), - input9.clone(), - input10.clone(), - input11.clone(), - input12.clone(), - input13.clone(), - input14.clone(), - input15.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/01_portrait_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/01_portrait_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![portrait_input1.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/02_portrait_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/02_portrait_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![portrait_input1.clone(), portrait_input2.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/03_portrait_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/03_portrait_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![ - portrait_input1.clone(), - portrait_input2.clone(), - portrait_input3.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/05_portrait_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/05_portrait_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![ - portrait_input1.clone(), - portrait_input2.clone(), - portrait_input3.clone(), - portrait_input4.clone(), - portrait_input5.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/15_portrait_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/15_portrait_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![ - portrait_input1.clone(), - portrait_input2.clone(), - portrait_input3.clone(), - portrait_input4.clone(), - portrait_input5.clone(), - portrait_input6.clone(), - portrait_input7.clone(), - portrait_input8.clone(), - portrait_input9.clone(), - portrait_input10.clone(), - portrait_input11.clone(), - portrait_input12.clone(), - portrait_input13.clone(), - portrait_input14.clone(), - portrait_input15.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/01_portrait_inputs_on_portrait_output", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/01_portrait_inputs.scene.json"), - portrait_resolution, - ), - inputs: vec![portrait_input1.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/03_portrait_inputs_on_portrait_output", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/03_portrait_inputs.scene.json"), - portrait_resolution, - ), - inputs: vec![ - portrait_input1.clone(), - portrait_input2.clone(), - portrait_input3.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/03_inputs_on_portrait_output", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/03_inputs.scene.json"), - portrait_resolution, - ), - inputs: vec![input1.clone(), input2.clone(), input3.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/05_portrait_inputs_on_portrait_output", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/05_portrait_inputs.scene.json"), - portrait_resolution, - ), - inputs: vec![ - portrait_input1.clone(), - portrait_input2.clone(), - portrait_input3.clone(), - portrait_input4.clone(), - portrait_input5.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/15_portrait_inputs_on_portrait_output", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/15_portrait_inputs.scene.json"), - portrait_resolution, - ), - inputs: vec![ - portrait_input1.clone(), - portrait_input2.clone(), - portrait_input3.clone(), - portrait_input4.clone(), - portrait_input5.clone(), - portrait_input6.clone(), - portrait_input7.clone(), - portrait_input8.clone(), - portrait_input9.clone(), - portrait_input10.clone(), - portrait_input11.clone(), - portrait_input12.clone(), - portrait_input13.clone(), - portrait_input14.clone(), - portrait_input15.clone(), - ], - ..Default::default() - }, - TestCase { - name: "tiles/align_center_with_03_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/align_center_with_03_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone(), input2.clone(), input3.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/align_top_left_with_03_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/align_top_left_with_03_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone(), input2.clone(), input3.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/align_with_margin_and_padding_with_03_inputs", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/tiles/align_with_margin_and_padding_with_03_inputs.scene.json" - ), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone(), input2.clone(), input3.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/margin_with_03_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/margin_with_03_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone(), input2.clone(), input3.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/margin_and_padding_with_03_inputs", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/tiles/margin_and_padding_with_03_inputs.scene.json" - ), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone(), input2.clone(), input3.clone()], - ..Default::default() - }, - TestCase { - name: "tiles/padding_with_03_inputs", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/tiles/padding_with_03_inputs.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![input1.clone(), input2.clone(), input3.clone()], - ..Default::default() - }, - TestCase{ - name: "tiles/video_call_with_labels", - scene_updates: Updates::Scene(include_str!("../../snapshot_tests/tiles/video_call_with_labels.scene.json"), DEFAULT_RESOLUTION), - inputs: vec![portrait_input1.clone(), portrait_input2.clone(), portrait_input3.clone()], - ..Default::default() - } - ]) -} - -fn text_snapshot_tests() -> Vec { - Vec::from([ - TestCase { - name: "text/align_center", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/align_center.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/align_right", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/align_right.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/bold_text", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/bold_text.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/dimensions_fitted_column_with_long_text", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/text/dimensions_fitted_column_with_long_text.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/dimensions_fitted_column_with_short_text", - scene_updates: Updates::Scene( - include_str!( - "../../snapshot_tests/text/dimensions_fitted_column_with_short_text.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/dimensions_fitted", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/dimensions_fitted.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/dimensions_fixed", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/dimensions_fixed.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/dimensions_fixed_with_overflow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/dimensions_fixed_with_overflow.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/red_text_on_blue_background", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/red_text_on_blue_background.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/wrap_glyph", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/wrap_glyph.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/wrap_none", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/wrap_none.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - name: "text/wrap_word", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/wrap_word.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - TestCase { - // Test if removing text from scene works - name: "text/remove_text_in_view", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/text/align_center.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/view/empty_view.scene.json"), - DEFAULT_RESOLUTION, - ), - ]), - ..Default::default() - }, - TestCase { - // Test if removing text from scene works - name: "text/remove_text_as_root", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/text/root_text.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/view/empty_view.scene.json"), - DEFAULT_RESOLUTION, - ), - ]), - ..Default::default() - }, - TestCase { - name: "text/text_as_root", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/text/root_text.scene.json"), - DEFAULT_RESOLUTION, - ), - ..Default::default() - }, - ]) -} - -fn image_snapshot_tests() -> Vec { - let image_renderer = ( - RendererId("image_jpeg".into()), - RendererSpec::Image(ImageSpec { - src: ImageSource::Url { - url: "https://www.rust-lang.org/static/images/rust-social.jpg".to_string(), - }, - image_type: ImageType::Jpeg, - }), - ); - - Vec::from([ - TestCase { - name: "image/jpeg_as_root", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/image/jpeg_as_root.scene.json"), - DEFAULT_RESOLUTION, - ), - renderers: vec![image_renderer.clone()], - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "image/jpeg_in_view", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/image/jpeg_in_view.scene.json"), - DEFAULT_RESOLUTION, - ), - renderers: vec![image_renderer.clone()], - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "image/jpeg_in_view_overflow_fit", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/image/jpeg_in_view_overflow_fit.scene.json"), - DEFAULT_RESOLUTION, - ), - renderers: vec![image_renderer.clone()], - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - // Test if removing image from scene works - name: "image/remove_jpeg_as_root", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/image/jpeg_as_root.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/view/empty_view.scene.json"), - DEFAULT_RESOLUTION, - ), - ]), - renderers: vec![image_renderer.clone()], - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - // Test if removing image from scene works - name: "image/remove_jpeg_in_view", - scene_updates: Updates::Scenes(vec![ - ( - include_str!("../../snapshot_tests/image/jpeg_in_view.scene.json"), - DEFAULT_RESOLUTION, - ), - ( - include_str!("../../snapshot_tests/view/empty_view.scene.json"), - DEFAULT_RESOLUTION, - ), - ]), - renderers: vec![image_renderer.clone()], - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - ]) -} - -fn transition_snapshot_tests() -> Vec { - Vec::from([ - TestCase { - name: "transition/change_rescaler_absolute_and_send_next_update", - scene_updates: Updates::Scenes(vec![ - ( - include_str!( - "../../snapshot_tests/transition/change_rescaler_absolute_start.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_rescaler_absolute_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_rescaler_absolute_after_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ]), - timestamps: vec![ - Duration::from_secs(0), - Duration::from_secs(5), - Duration::from_secs(9), - Duration::from_secs(10), - ], - ..Default::default() - }, - TestCase { - name: "transition/change_view_width_and_send_abort_transition", - scene_updates: Updates::Scenes(vec![ - ( - include_str!( - "../../snapshot_tests/transition/change_view_width_start.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_width_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_width_after_end_without_id.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ]), - timestamps: vec![ - Duration::from_secs(0), - Duration::from_secs(5), - Duration::from_secs(10), - ], - ..Default::default() - }, - TestCase { - name: "transition/change_view_width_and_send_next_update", - scene_updates: Updates::Scenes(vec![ - ( - include_str!( - "../../snapshot_tests/transition/change_view_width_start.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_width_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_width_after_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ]), - timestamps: vec![ - Duration::from_secs(0), - Duration::from_secs(5), - Duration::from_secs(10), - ], - ..Default::default() - }, - TestCase { - name: "transition/change_view_width", - scene_updates: Updates::Scenes(vec![ - ( - include_str!( - "../../snapshot_tests/transition/change_view_width_start.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_width_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ]), - timestamps: vec![ - Duration::from_secs(0), - Duration::from_secs(5), - Duration::from_secs(10), - Duration::from_secs(100), - ], - ..Default::default() - }, - TestCase { - name: "transition/change_view_height", - scene_updates: Updates::Scenes(vec![ - ( - include_str!( - "../../snapshot_tests/transition/change_view_height_start.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_height_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ]), - timestamps: vec![ - Duration::from_secs(0), - Duration::from_secs(5), - Duration::from_secs(10), - ], - ..Default::default() - }, - TestCase { - name: "transition/change_view_absolute", - scene_updates: Updates::Scenes(vec![ - ( - include_str!( - "../../snapshot_tests/transition/change_view_absolute_start.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_absolute_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ]), - timestamps: vec![ - Duration::from_secs(0), - Duration::from_secs(5), - Duration::from_secs(9), - Duration::from_secs(10), - ], - ..Default::default() - }, - TestCase { - name: "transition/change_view_absolute_cubic_bezier", - scene_updates: Updates::Scenes(vec![ - ( - include_str!( - "../../snapshot_tests/transition/change_view_absolute_cubic_bezier_start.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_absolute_cubic_bezier_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ]), - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(2500), - Duration::from_secs(5000), - ], - ..Default::default() - }, - TestCase { - name: "transition/change_view_absolute_cubic_bezier_linear_like", - scene_updates: Updates::Scenes(vec![ - ( - include_str!( - "../../snapshot_tests/transition/change_view_absolute_cubic_bezier_linear_like_start.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ( - include_str!( - "../../snapshot_tests/transition/change_view_absolute_cubic_bezier_linear_like_end.scene.json" - ), - DEFAULT_RESOLUTION, - ), - ]), - timestamps: vec![ - Duration::from_millis(0), - Duration::from_millis(2500), - Duration::from_secs(5000), - ], - ..Default::default() - }, - ]) -} - -fn view_snapshot_tests() -> Vec { - Vec::from([ - TestCase { - name: "view/overflow_hidden_with_input_stream_children", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/overflow_hidden_with_input_stream_children.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new_with_resolution(1, Resolution { width: 180, height: 200 })], - ..Default::default() - }, - TestCase { - name: "view/overflow_hidden_with_view_children", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/overflow_hidden_with_view_children.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![], - ..Default::default() - }, - TestCase { - name: "view/constant_width_views_row", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/constant_width_views_row.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/constant_width_views_row_with_overflow_hidden", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/constant_width_views_row_with_overflow_hidden.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/constant_width_views_row_with_overflow_visible", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/constant_width_views_row_with_overflow_visible.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/constant_width_views_row_with_overflow_fit", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/constant_width_views_row_with_overflow_fit.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/dynamic_width_views_row", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/dynamic_width_views_row.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/dynamic_and_constant_width_views_row", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/dynamic_and_constant_width_views_row.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/dynamic_and_constant_width_views_row_with_overflow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/dynamic_and_constant_width_views_row_with_overflow.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/constant_width_and_height_views_row", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/constant_width_and_height_views_row.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/view_with_absolute_positioning_partially_covered_by_sibling", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/view_with_absolute_positioning_partially_covered_by_sibling.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/view_with_absolute_positioning_render_over_siblings", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/view_with_absolute_positioning_render_over_siblings.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/root_view_with_background_color", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/root_view_with_background_color.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/border_radius", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_radius.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/border_width", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_width.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/box_shadow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/box_shadow.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/box_shadow_sibling", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/box_shadow_sibling.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/border_radius_border_box_shadow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_radius_border_box_shadow.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/border_radius_box_shadow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_radius_box_shadow.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/border_radius_box_shadow_overflow_hidden", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_radius_box_shadow_overflow_hidden.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/border_radius_box_shadow_overflow_fit", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_radius_box_shadow_overflow_fit.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/border_radius_box_shadow_rescaler_input_stream", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_radius_box_shadow_rescaler_input_stream.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/nested_border_width_radius", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/nested_border_width_radius.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/nested_border_width_radius_aligned", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/nested_border_width_radius_aligned.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/nested_border_width_radius_multi_child", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/nested_border_width_radius_multi_child.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - // it is supposed to be cut off because of the rescaler that wraps it - name: "view/border_radius_border_box_shadow_rescaled", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_radius_border_box_shadow_rescaled.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/root_border_radius_border_box_shadow", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/root_border_radius_border_box_shadow.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - TestCase { - name: "view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }, - ]) -} - -fn base_snapshot_tests() -> Vec { - Vec::from([TestCase { - name: "simple_input_pass_through", - scene_updates: Updates::Scene( - include_str!("../../snapshot_tests/simple_input_pass_through.scene.json"), - DEFAULT_RESOLUTION, - ), - inputs: vec![TestInput::new(1)], - ..Default::default() - }]) -} diff --git a/src/snapshot_tests/text_tests.rs b/src/snapshot_tests/text_tests.rs new file mode 100644 index 000000000..da14b75d5 --- /dev/null +++ b/src/snapshot_tests/text_tests.rs @@ -0,0 +1,118 @@ +use super::{scene_from_json, scenes_from_json, snapshots_path, test_case::TestCase, TestRunner}; + +#[test] +fn text_tests() { + let mut runner = TestRunner::new(snapshots_path().join("text")); + + runner.add(TestCase { + name: "text/align_center", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/align_center.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/align_right", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/align_right.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/bold_text", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/bold_text.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/dimensions_fitted_column_with_long_text", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/dimensions_fitted_column_with_long_text.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/dimensions_fitted_column_with_short_text", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/dimensions_fitted_column_with_short_text.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/dimensions_fitted", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/dimensions_fitted.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/dimensions_fixed", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/dimensions_fixed.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/dimensions_fixed_with_overflow", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/dimensions_fixed_with_overflow.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/red_text_on_blue_background", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/red_text_on_blue_background.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/wrap_glyph", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/wrap_glyph.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/wrap_none", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/wrap_none.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + name: "text/wrap_word", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/wrap_word.scene.json" + )), + ..Default::default() + }); + runner.add(TestCase { + // Test if removing text from scene works + name: "text/remove_text_in_view", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/text/align_center.scene.json"), + include_str!("../../snapshot_tests/view/empty_view.scene.json"), + ]), + ..Default::default() + }); + runner.add(TestCase { + // Test if removing text from scene works + name: "text/remove_text_as_root", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/text/root_text.scene.json"), + include_str!("../../snapshot_tests/view/empty_view.scene.json"), + ]), + ..Default::default() + }); + runner.add(TestCase { + name: "text/text_as_root", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/text/root_text.scene.json" + )), + ..Default::default() + }); + + runner.run() +} diff --git a/src/snapshot_tests/tiles_tests.rs b/src/snapshot_tests/tiles_tests.rs new file mode 100644 index 000000000..2e8f64315 --- /dev/null +++ b/src/snapshot_tests/tiles_tests.rs @@ -0,0 +1,318 @@ +use compositor_render::Resolution; + +use super::{input::TestInput, scene_from_json, snapshots_path, test_case::TestCase, TestRunner}; + +#[test] +fn tiles_tests() { + let mut runner = TestRunner::new(snapshots_path().join("tiles")); + + let input1 = TestInput::new(1); + let input2 = TestInput::new(2); + let input3 = TestInput::new(3); + let input4 = TestInput::new(4); + let input5 = TestInput::new(5); + let input6 = TestInput::new(6); + let input7 = TestInput::new(7); + let input8 = TestInput::new(8); + let input9 = TestInput::new(9); + let input10 = TestInput::new(10); + let input11 = TestInput::new(11); + let input12 = TestInput::new(12); + let input13 = TestInput::new(13); + let input14 = TestInput::new(14); + let input15 = TestInput::new(15); + let portrait_resolution = Resolution { + width: 360, + height: 640, + }; + let portrait_input1 = TestInput::new_with_resolution(1, portrait_resolution); + let portrait_input2 = TestInput::new_with_resolution(2, portrait_resolution); + let portrait_input3 = TestInput::new_with_resolution(3, portrait_resolution); + let portrait_input4 = TestInput::new_with_resolution(4, portrait_resolution); + let portrait_input5 = TestInput::new_with_resolution(5, portrait_resolution); + let portrait_input6 = TestInput::new_with_resolution(6, portrait_resolution); + let portrait_input7 = TestInput::new_with_resolution(7, portrait_resolution); + let portrait_input8 = TestInput::new_with_resolution(8, portrait_resolution); + let portrait_input9 = TestInput::new_with_resolution(9, portrait_resolution); + let portrait_input10 = TestInput::new_with_resolution(10, portrait_resolution); + let portrait_input11 = TestInput::new_with_resolution(11, portrait_resolution); + let portrait_input12 = TestInput::new_with_resolution(12, portrait_resolution); + let portrait_input13 = TestInput::new_with_resolution(13, portrait_resolution); + let portrait_input14 = TestInput::new_with_resolution(14, portrait_resolution); + let portrait_input15 = TestInput::new_with_resolution(15, portrait_resolution); + + runner.add(TestCase { + name: "tiles/01_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/01_inputs.scene.json" + )), + inputs: vec![input1.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/02_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/02_inputs.scene.json" + )), + inputs: vec![input1.clone(), input2.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/03_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/03_inputs.scene.json" + )), + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/04_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/04_inputs.scene.json" + )), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + input4.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/05_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/05_inputs.scene.json" + )), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + input4.clone(), + input5.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/15_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/15_inputs.scene.json" + )), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + input4.clone(), + input5.clone(), + input6.clone(), + input7.clone(), + input8.clone(), + input9.clone(), + input10.clone(), + input11.clone(), + input12.clone(), + input13.clone(), + input14.clone(), + input15.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/01_portrait_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/01_portrait_inputs.scene.json" + )), + inputs: vec![portrait_input1.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/02_portrait_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/02_portrait_inputs.scene.json" + )), + inputs: vec![portrait_input1.clone(), portrait_input2.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/03_portrait_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/03_portrait_inputs.scene.json" + )), + inputs: vec![ + portrait_input1.clone(), + portrait_input2.clone(), + portrait_input3.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/05_portrait_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/05_portrait_inputs.scene.json" + )), + inputs: vec![ + portrait_input1.clone(), + portrait_input2.clone(), + portrait_input3.clone(), + portrait_input4.clone(), + portrait_input5.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/15_portrait_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/15_portrait_inputs.scene.json" + )), + inputs: vec![ + portrait_input1.clone(), + portrait_input2.clone(), + portrait_input3.clone(), + portrait_input4.clone(), + portrait_input5.clone(), + portrait_input6.clone(), + portrait_input7.clone(), + portrait_input8.clone(), + portrait_input9.clone(), + portrait_input10.clone(), + portrait_input11.clone(), + portrait_input12.clone(), + portrait_input13.clone(), + portrait_input14.clone(), + portrait_input15.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/01_portrait_inputs_on_portrait_output", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/01_portrait_inputs.scene.json" + )), + resolution: portrait_resolution, + inputs: vec![portrait_input1.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/03_portrait_inputs_on_portrait_output", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/03_portrait_inputs.scene.json" + )), + resolution: portrait_resolution, + inputs: vec![ + portrait_input1.clone(), + portrait_input2.clone(), + portrait_input3.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/03_inputs_on_portrait_output", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/03_inputs.scene.json" + )), + resolution: portrait_resolution, + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/05_portrait_inputs_on_portrait_output", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/05_portrait_inputs.scene.json" + )), + resolution: portrait_resolution, + inputs: vec![ + portrait_input1.clone(), + portrait_input2.clone(), + portrait_input3.clone(), + portrait_input4.clone(), + portrait_input5.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/15_portrait_inputs_on_portrait_output", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/15_portrait_inputs.scene.json" + )), + resolution: portrait_resolution, + inputs: vec![ + portrait_input1.clone(), + portrait_input2.clone(), + portrait_input3.clone(), + portrait_input4.clone(), + portrait_input5.clone(), + portrait_input6.clone(), + portrait_input7.clone(), + portrait_input8.clone(), + portrait_input9.clone(), + portrait_input10.clone(), + portrait_input11.clone(), + portrait_input12.clone(), + portrait_input13.clone(), + portrait_input14.clone(), + portrait_input15.clone(), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/align_center_with_03_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/align_center_with_03_inputs.scene.json" + )), + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/align_top_left_with_03_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/align_top_left_with_03_inputs.scene.json" + )), + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/align_with_margin_and_padding_with_03_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/align_with_margin_and_padding_with_03_inputs.scene.json" + )), + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/margin_with_03_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/margin_with_03_inputs.scene.json" + )), + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/margin_and_padding_with_03_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/margin_and_padding_with_03_inputs.scene.json" + )), + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/padding_with_03_inputs", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/padding_with_03_inputs.scene.json" + )), + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles/video_call_with_labels", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/tiles/video_call_with_labels.scene.json" + )), + inputs: vec![ + portrait_input1.clone(), + portrait_input2.clone(), + portrait_input3.clone(), + ], + ..Default::default() + }); + + runner.run() +} diff --git a/src/snapshot_tests/tiles_transitions_tests.rs b/src/snapshot_tests/tiles_transitions_tests.rs new file mode 100644 index 000000000..1b71e75c6 --- /dev/null +++ b/src/snapshot_tests/tiles_transitions_tests.rs @@ -0,0 +1,174 @@ +use std::time::Duration; + +use super::{input::TestInput, scenes_from_json, snapshots_path, test_case::TestCase, TestRunner}; + +#[test] +fn tiles_transitions_tests() { + let mut runner = TestRunner::new(snapshots_path().join("tiles_transitions")); + + let input1 = TestInput::new(1); + let input2 = TestInput::new(2); + let input3 = TestInput::new(3); + let input4 = TestInput::new(4); + let input5 = TestInput::new(5); + + runner.add(TestCase { + name: "tiles_transitions/tile_resize_entire_component_with_parent_transition", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/tiles_transitions/start_tile_resize.scene.json"), + include_str!("../../snapshot_tests/tiles_transitions/end_tile_resize_with_view_transition.scene.json"), + ]), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + ], + timestamps: vec![ + Duration::from_millis(0), + Duration::from_millis(150), + Duration::from_millis(350), + // TODO: This transition does not look great, but it would require automatic + // transitions triggered by a size change (not scene update) + Duration::from_millis(450), + Duration::from_millis(500), + ], + ..Default::default() + }); + + runner.add(TestCase { + name: "tiles_transitions/tile_resize_entire_component_without_parent_transition", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/tiles_transitions/start_tile_resize.scene.json"), + include_str!("../../snapshot_tests/tiles_transitions/end_tile_resize.scene.json"), + ]), + inputs: vec![input1.clone(), input2.clone(), input3.clone()], + timestamps: vec![ + Duration::from_millis(0), + Duration::from_millis(150), + Duration::from_millis(350), + Duration::from_millis(500), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles_transitions/change_order_of_3_inputs_with_id", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/tiles_transitions/start_with_3_inputs_all_id.scene.json"), + include_str!("../../snapshot_tests/tiles_transitions/end_with_3_inputs_3_id_different_order.scene.json"), + ]), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + ], + timestamps: vec![ + Duration::from_millis(0), + Duration::from_millis(150), + Duration::from_millis(350), + Duration::from_millis(500), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles_transitions/replace_component_by_adding_id", + scene_updates: scenes_from_json(&[ + include_str!( + "../../snapshot_tests/tiles_transitions/start_with_3_inputs_no_id.scene.json" + ), + include_str!( + "../../snapshot_tests/tiles_transitions/end_with_3_inputs_1_id.scene.json" + ), + ]), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + input4.clone(), + ], + timestamps: vec![ + Duration::from_millis(0), + Duration::from_millis(150), + Duration::from_millis(350), + Duration::from_millis(500), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles_transitions/add_2_inputs_at_the_end_to_3_tiles_scene", + scene_updates: scenes_from_json(&[ + include_str!( + "../../snapshot_tests/tiles_transitions/start_with_3_inputs_no_id.scene.json" + ), + include_str!( + "../../snapshot_tests/tiles_transitions/end_with_5_inputs_no_id.scene.json" + ), + ]), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + input4.clone(), + input5.clone(), + ], + timestamps: vec![ + Duration::from_millis(0), + Duration::from_millis(150), + Duration::from_millis(350), + Duration::from_millis(500), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles_transitions/add_input_on_2nd_pos_to_3_tiles_scene", + scene_updates: scenes_from_json(&[ + include_str!( + "../../snapshot_tests/tiles_transitions/start_with_3_inputs_no_id.scene.json" + ), + include_str!( + "../../snapshot_tests/tiles_transitions/end_with_4_inputs_1_id.scene.json" + ), + ]), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + input4.clone(), + ], + timestamps: vec![ + Duration::from_millis(0), + Duration::from_millis(150), + Duration::from_millis(350), + Duration::from_millis(500), + ], + ..Default::default() + }); + runner.add(TestCase { + name: "tiles_transitions/add_input_at_the_end_to_3_tiles_scene", + scene_updates: scenes_from_json(&[ + include_str!( + "../../snapshot_tests/tiles_transitions/start_with_3_inputs_no_id.scene.json" + ), + include_str!( + "../../snapshot_tests/tiles_transitions/end_with_4_inputs_no_id.scene.json" + ), + include_str!( + "../../snapshot_tests/tiles_transitions/after_end_with_4_inputs_no_id.scene.json" + ), + ]), + inputs: vec![ + input1.clone(), + input2.clone(), + input3.clone(), + input4.clone(), + ], + timestamps: vec![ + Duration::from_millis(0), + Duration::from_millis(150), + Duration::from_millis(350), + Duration::from_millis(500), + ], + ..Default::default() + }); + + runner.run() +} diff --git a/src/snapshot_tests/transition_tests.rs b/src/snapshot_tests/transition_tests.rs new file mode 100644 index 000000000..0a813f698 --- /dev/null +++ b/src/snapshot_tests/transition_tests.rs @@ -0,0 +1,95 @@ +use std::time::Duration; + +use super::{scenes_from_json, snapshots_path, test_case::TestCase, TestRunner}; + +#[test] +fn transitions_tests() { + let mut runner = TestRunner::new(snapshots_path().join("transition")); + let default = TestCase { + timestamps: vec![ + Duration::from_millis(0), + Duration::from_millis(2500), + Duration::from_millis(5000), + Duration::from_millis(7500), + Duration::from_millis(9000), + Duration::from_millis(10000), + ], + ..Default::default() + }; + + runner.add(TestCase { + name: "transition/change_rescaler_absolute_and_send_next_update", + scene_updates: scenes_from_json(&[ + include_str!( + "../../snapshot_tests/transition/change_rescaler_absolute_start.scene.json" + ), + include_str!("../../snapshot_tests/transition/change_rescaler_absolute_end.scene.json"), + include_str!( + "../../snapshot_tests/transition/change_rescaler_absolute_after_end.scene.json" + ), + ]), + ..default.clone() + }); + runner.add(TestCase { + name: "transition/change_view_width_and_send_abort_transition", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/transition/change_view_width_start.scene.json"), + include_str!("../../snapshot_tests/transition/change_view_width_end.scene.json"), + include_str!( + "../../snapshot_tests/transition/change_view_width_after_end_without_id.scene.json" + ), + ]), + ..default.clone() + }); + runner.add(TestCase { + name: "transition/change_view_width_and_send_next_update", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/transition/change_view_width_start.scene.json"), + include_str!("../../snapshot_tests/transition/change_view_width_end.scene.json"), + include_str!("../../snapshot_tests/transition/change_view_width_after_end.scene.json"), + ]), + ..default.clone() + }); + runner.add(TestCase { + name: "transition/change_view_width", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/transition/change_view_width_start.scene.json"), + include_str!("../../snapshot_tests/transition/change_view_width_end.scene.json"), + ]), + ..default.clone() + }); + runner.add(TestCase { + name: "transition/change_view_height", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/transition/change_view_height_start.scene.json"), + include_str!("../../snapshot_tests/transition/change_view_height_end.scene.json"), + ]), + ..default.clone() + }); + runner.add(TestCase { + name: "transition/change_view_absolute", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/transition/change_view_absolute_start.scene.json"), + include_str!("../../snapshot_tests/transition/change_view_absolute_end.scene.json"), + ]), + ..default.clone() + }); + runner.add(TestCase { + name: "transition/change_view_absolute_cubic_bezier", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/transition/change_view_absolute_cubic_bezier_start.scene.json"), + include_str!("../../snapshot_tests/transition/change_view_absolute_cubic_bezier_end.scene.json"), + ]), + ..default.clone() + }); + runner.add(TestCase { + name: "transition/change_view_absolute_cubic_bezier_linear_like", + scene_updates: scenes_from_json(&[ + include_str!("../../snapshot_tests/transition/change_view_absolute_cubic_bezier_linear_like_start.scene.json"), + include_str!("../../snapshot_tests/transition/change_view_absolute_cubic_bezier_linear_like_end.scene.json"), + ]), + ..default.clone() + }); + + runner.run() +} diff --git a/src/snapshot_tests/utils.rs b/src/snapshot_tests/utils.rs index 893133f82..5454d0adc 100644 --- a/src/snapshot_tests/utils.rs +++ b/src/snapshot_tests/utils.rs @@ -1,8 +1,5 @@ use core::panic; use std::{ - collections::HashSet, - fs, - path::PathBuf, sync::{Arc, OnceLock}, time::Duration, }; @@ -12,20 +9,8 @@ use compositor_render::{ WgpuFeatures, YuvPlanes, }; -use super::test_case::OUTPUT_ID; - pub const SNAPSHOTS_DIR_NAME: &str = "snapshot_tests/snapshots/render_snapshots"; -fn global_wgpu_ctx( - force_gpu: bool, - features: wgpu::Features, -) -> (Arc, Arc) { - static CTX: OnceLock<(Arc, Arc)> = OnceLock::new(); - - CTX.get_or_init(|| create_wgpu_ctx(force_gpu, features, Default::default()).unwrap()) - .clone() -} - pub(super) fn frame_to_rgba(frame: &Frame) -> Vec { let FrameData::PlanarYuv420(YuvPlanes { y_plane, @@ -61,20 +46,11 @@ pub(super) fn frame_to_rgba(frame: &Frame) -> Vec { rgba_data } -pub(super) fn snapshots_diff(old_snapshot: &[u8], new_snapshot: &[u8]) -> f32 { - if old_snapshot.len() != new_snapshot.len() { - return 10000.0; - } - let square_error: f32 = old_snapshot - .iter() - .zip(new_snapshot) - .map(|(a, b)| (*a as i32 - *b as i32).pow(2) as f32) - .sum(); - - square_error / old_snapshot.len() as f32 -} - pub(super) fn create_renderer() -> Renderer { + static CTX: OnceLock<(Arc, Arc)> = OnceLock::new(); + let wgpu_ctx = + CTX.get_or_init(|| create_wgpu_ctx(false, Default::default(), Default::default()).unwrap()); + let (renderer, _event_loop) = Renderer::new(RendererOptions { web_renderer: web_renderer::WebRendererInitOptions { enable: false, @@ -84,42 +60,9 @@ pub(super) fn create_renderer() -> Renderer { framerate: Framerate { num: 30, den: 1 }, stream_fallback_timeout: Duration::from_secs(3), wgpu_features: WgpuFeatures::default(), - wgpu_ctx: Some(global_wgpu_ctx(false, Default::default())), + wgpu_ctx: Some(wgpu_ctx.clone()), load_system_fonts: false, }) .unwrap(); renderer } - -pub fn snapshots_path() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(SNAPSHOTS_DIR_NAME) -} - -pub fn find_unused_snapshots( - produced_snapshots: &HashSet, - snapshots_path: PathBuf, -) -> Vec { - let mut unused_snapshots = Vec::new(); - for entry in fs::read_dir(snapshots_path).unwrap() { - let entry = entry.unwrap(); - if entry.file_type().unwrap().is_dir() { - let mut snapshots = find_unused_snapshots(produced_snapshots, entry.path()); - unused_snapshots.append(&mut snapshots); - continue; - } - if !entry.file_name().to_string_lossy().ends_with(".png") { - continue; - } - - if !produced_snapshots.contains(&entry.path()) { - unused_snapshots.push(entry.path()) - } - } - - unused_snapshots -} - -pub(super) fn snaphot_save_path(test_name: &str, pts: &Duration) -> PathBuf { - let out_file_name = format!("{}_{}_{}.png", test_name, pts.as_millis(), OUTPUT_ID); - snapshots_path().join(out_file_name) -} diff --git a/src/snapshot_tests/view_tests.rs b/src/snapshot_tests/view_tests.rs new file mode 100644 index 000000000..225983484 --- /dev/null +++ b/src/snapshot_tests/view_tests.rs @@ -0,0 +1,219 @@ +use compositor_render::Resolution; + +use super::{input::TestInput, scene_from_json, snapshots_path, test_case::TestCase, TestRunner}; + +#[test] +fn view_tests() { + let mut runner = TestRunner::new(snapshots_path().join("view")); + let default = TestCase { + inputs: vec![TestInput::new(1)], + ..Default::default() + }; + + runner.add(TestCase { + name: "view/overflow_hidden_with_input_stream_children", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/overflow_hidden_with_input_stream_children.scene.json" + )), + inputs: vec![TestInput::new_with_resolution( + 1, + Resolution { + width: 180, + height: 200, + }, + )], + ..Default::default() + }); + runner.add(TestCase { + name: "view/overflow_hidden_with_view_children", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/overflow_hidden_with_view_children.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/constant_width_views_row", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/constant_width_views_row.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/constant_width_views_row_with_overflow_hidden", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/constant_width_views_row_with_overflow_hidden.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/constant_width_views_row_with_overflow_visible", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/constant_width_views_row_with_overflow_visible.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/constant_width_views_row_with_overflow_fit", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/constant_width_views_row_with_overflow_fit.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/dynamic_width_views_row", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/dynamic_width_views_row.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/dynamic_and_constant_width_views_row", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/dynamic_and_constant_width_views_row.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/dynamic_and_constant_width_views_row_with_overflow", + scene_updates: scene_from_json( + include_str!("../../snapshot_tests/view/dynamic_and_constant_width_views_row_with_overflow.scene.json"), + ), + ..default.clone() + }); + runner.add(TestCase { + name: "view/constant_width_and_height_views_row", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/constant_width_and_height_views_row.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/view_with_absolute_positioning_partially_covered_by_sibling", + scene_updates: scene_from_json( + include_str!("../../snapshot_tests/view/view_with_absolute_positioning_partially_covered_by_sibling.scene.json"), + ), + ..default.clone() + }); + runner.add(TestCase { + name: "view/view_with_absolute_positioning_render_over_siblings", + scene_updates: scene_from_json( + include_str!("../../snapshot_tests/view/view_with_absolute_positioning_render_over_siblings.scene.json"), + ), + ..default.clone() + }); + runner.add(TestCase { + name: "view/root_view_with_background_color", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/root_view_with_background_color.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/border_radius", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_radius.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/border_width", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_width.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/box_shadow", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/box_shadow.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/box_shadow_sibling", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/box_shadow_sibling.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/border_radius_border_box_shadow", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_radius_border_box_shadow.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/border_radius_box_shadow", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_radius_box_shadow.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/border_radius_box_shadow_overflow_hidden", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_radius_box_shadow_overflow_hidden.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/border_radius_box_shadow_overflow_fit", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_radius_box_shadow_overflow_fit.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/border_radius_box_shadow_rescaler_input_stream", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_radius_box_shadow_rescaler_input_stream.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/nested_border_width_radius", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/nested_border_width_radius.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/nested_border_width_radius_aligned", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/nested_border_width_radius_aligned.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/nested_border_width_radius_multi_child", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/nested_border_width_radius_multi_child.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + // it is supposed to be cut off because of the rescaler that wraps it + name: "view/border_radius_border_box_shadow_rescaled", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_radius_border_box_shadow_rescaled.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/root_border_radius_border_box_shadow", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/root_border_radius_border_box_shadow.scene.json" + )), + ..default.clone() + }); + runner.add(TestCase { + name: "view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent", + scene_updates: scene_from_json(include_str!( + "../../snapshot_tests/view/border_radius_border_box_shadow_rescaled_and_hidden_by_parent.scene.json" + )), + ..default.clone() + }); + + runner.run() +} From a4186fef6ce019a79a7a9fe2fc1ff9256dd711d3 Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Tue, 12 Nov 2024 19:01:11 +0100 Subject: [PATCH 23/51] [tests] Add required audio stream snapshot tests (#851) --- .../src/tests/required_inputs.rs | 282 +++++++++++++++++- snapshot_tests/snapshots | 2 +- 2 files changed, 277 insertions(+), 7 deletions(-) diff --git a/integration_tests/src/tests/required_inputs.rs b/integration_tests/src/tests/required_inputs.rs index ca8320df0..c6a167027 100644 --- a/integration_tests/src/tests/required_inputs.rs +++ b/integration_tests/src/tests/required_inputs.rs @@ -1,8 +1,9 @@ use std::{thread, time::Duration}; use crate::{ - compare_video_dumps, input_dump_from_disk, split_rtp_packet_dump, CommunicationProtocol, - CompositorInstance, OutputReceiver, PacketSender, VideoValidationConfig, + compare_audio_dumps, compare_video_dumps, input_dump_from_disk, split_rtp_packet_dump, + AudioValidationConfig, CommunicationProtocol, CompositorInstance, OutputReceiver, PacketSender, + VideoValidationConfig, }; use anyhow::Result; use serde_json::json; @@ -12,8 +13,8 @@ use serde_json::json; /// /// Show `input_1` and `input_2` side by side for 20 seconds. #[test] -pub fn required_inputs_no_offset() -> Result<()> { - const OUTPUT_DUMP_FILE: &str = "required_inputs_no_offset_output.rtp"; +pub fn required_video_inputs_no_offset() -> Result<()> { + const OUTPUT_DUMP_FILE: &str = "required_video_inputs_no_offset_output.rtp"; let instance = CompositorInstance::start(None); let input_1_port = instance.get_port(); let input_2_port = instance.get_port(); @@ -129,8 +130,8 @@ pub fn required_inputs_no_offset() -> Result<()> { /// /// Show `input_1` and `input_2` side by side for 20 seconds. #[test] -pub fn required_inputs_with_offset() -> Result<()> { - const OUTPUT_DUMP_FILE: &str = "required_inputs_with_offset_output.rtp"; +pub fn required_video_inputs_with_offset() -> Result<()> { + const OUTPUT_DUMP_FILE: &str = "required_video_inputs_with_offset_output.rtp"; let instance = CompositorInstance::start(None); let input_1_port = instance.get_port(); let input_2_port = instance.get_port(); @@ -244,6 +245,275 @@ pub fn required_inputs_with_offset() -> Result<()> { Ok(()) } +/// Required inputs with some packets delayed. +/// +/// Countdown from 10 from the beginning +#[test] +pub fn required_audio_inputs_no_offset() -> Result<()> { + const OUTPUT_DUMP_FILE: &str = "required_audio_inputs_no_offset_output.rtp"; + let instance = CompositorInstance::start(None); + let input_1_port = instance.get_port(); + let output_port = instance.get_port(); + + instance.send_request( + "output/output_1/register", + json!({ + "type": "rtp_stream", + "transport_protocol": "tcp_server", + "port": output_port, + "audio": { + "initial": { + "inputs": [ + { + "input_id": "input_1", + "volume": 1.0, + }, + ] + }, + "encoder": { + "type": "opus", + "channels": "stereo", + } + }, + }), + )?; + + instance.send_request( + "output/output_1/unregister", + json!({ + "schedule_time_ms": 10000, + }), + )?; + + let output_receiver = OutputReceiver::start(output_port, CommunicationProtocol::Tcp)?; + + instance.send_request( + "input/input_1/register", + json!({ + "type": "rtp_stream", + "transport_protocol": "tcp_server", + "port": input_1_port, + "audio": { + "decoder": "opus" + }, + "required": true, + }), + )?; + + let mut input_sender = PacketSender::new(CommunicationProtocol::Tcp, input_1_port)?; + let input_dump = input_dump_from_disk("countdown_audio.rtp")?; + let (input_first_part, input_second_part) = + split_rtp_packet_dump(input_dump, Duration::from_secs(1))?; + + let input_handle = thread::spawn(move || { + input_sender.send(&input_first_part).unwrap(); + thread::sleep(Duration::from_secs(3)); + input_sender.send(&input_second_part).unwrap(); + }); + + instance.send_request("start", json!({}))?; + + input_handle.join().unwrap(); + let new_output_dump = output_receiver.wait_for_output()?; + + compare_audio_dumps( + OUTPUT_DUMP_FILE, + &new_output_dump, + AudioValidationConfig { + sampling_intervals: vec![ + Duration::from_millis(0)..Duration::from_millis(2000), + Duration::from_millis(2000)..Duration::from_millis(4000), + Duration::from_millis(6000)..Duration::from_millis(8000), + ], + ..Default::default() + }, + )?; + + Ok(()) +} + +/// Required inputs with some packets delayed. Offset set to 1000ms. +/// +/// Countdown from 10 delayed by one second +#[test] +pub fn required_audio_inputs_with_offset() -> Result<()> { + const OUTPUT_DUMP_FILE: &str = "required_audio_inputs_with_offset_output.rtp"; + let instance = CompositorInstance::start(None); + let input_1_port = instance.get_port(); + let output_port = instance.get_port(); + + instance.send_request( + "output/output_1/register", + json!({ + "type": "rtp_stream", + "transport_protocol": "tcp_server", + "port": output_port, + "audio": { + "initial": { + "inputs": [ + { + "input_id": "input_1", + "volume": 1.0, + }, + ] + }, + "encoder": { + "type": "opus", + "channels": "stereo", + } + }, + }), + )?; + + instance.send_request( + "output/output_1/unregister", + json!({ + "schedule_time_ms": 10000, + }), + )?; + + let output_receiver = OutputReceiver::start(output_port, CommunicationProtocol::Tcp)?; + + instance.send_request( + "input/input_1/register", + json!({ + "type": "rtp_stream", + "transport_protocol": "tcp_server", + "port": input_1_port, + "audio": { + "decoder": "opus" + }, + "offset_ms": 1000, + "required": true, + }), + )?; + + let mut input_sender = PacketSender::new(CommunicationProtocol::Tcp, input_1_port)?; + let input_dump = input_dump_from_disk("countdown_audio.rtp")?; + let (input_first_part, input_second_part) = + split_rtp_packet_dump(input_dump, Duration::from_secs(1))?; + + let input_handle = thread::spawn(move || { + input_sender.send(&input_first_part).unwrap(); + thread::sleep(Duration::from_secs(3)); + input_sender.send(&input_second_part).unwrap(); + }); + + instance.send_request("start", json!({}))?; + + input_handle.join().unwrap(); + let new_output_dump = output_receiver.wait_for_output()?; + + compare_audio_dumps( + OUTPUT_DUMP_FILE, + &new_output_dump, + AudioValidationConfig { + sampling_intervals: vec![ + Duration::from_millis(0)..Duration::from_millis(2000), + Duration::from_millis(2000)..Duration::from_millis(4000), + Duration::from_millis(6000)..Duration::from_millis(8000), + ], + ..Default::default() + }, + )?; + + Ok(()) +} + +/// Required inputs with some packets delayed and some dropped. Offset set to 1000ms. +/// +/// Countdown from 10 +/// - 1 seconds of silence +/// - 1 second of audio (from the start of the recording) +/// - 2 seconds of silence (cuts of part of "10" and "9" from countdown) +/// - remaining part of audio (2 seconds from previous step are missing) +#[test] +pub fn required_audio_inputs_with_offset_missing_data() -> Result<()> { + const OUTPUT_DUMP_FILE: &str = "required_audio_inputs_with_offset_missing_data_output.rtp"; + let instance = CompositorInstance::start(None); + let input_1_port = instance.get_port(); + let output_port = instance.get_port(); + + instance.send_request( + "output/output_1/register", + json!({ + "type": "rtp_stream", + "transport_protocol": "tcp_server", + "port": output_port, + "audio": { + "initial": { + "inputs": [ + { + "input_id": "input_1", + "volume": 1.0, + }, + ] + }, + "encoder": { + "type": "opus", + "channels": "stereo", + } + }, + }), + )?; + + instance.send_request( + "output/output_1/unregister", + json!({ + "schedule_time_ms": 10000, + }), + )?; + + let output_receiver = OutputReceiver::start(output_port, CommunicationProtocol::Tcp)?; + + instance.send_request( + "input/input_1/register", + json!({ + "type": "rtp_stream", + "transport_protocol": "tcp_server", + "port": input_1_port, + "audio": { + "decoder": "opus" + }, + "offset_ms": 1000, + "required": true, + }), + )?; + + let mut input_sender = PacketSender::new(CommunicationProtocol::Tcp, input_1_port)?; + let input_dump = input_dump_from_disk("countdown_audio.rtp")?; + let (input_first_part, input_second_part) = + split_rtp_packet_dump(input_dump, Duration::from_secs(1))?; + let (_dropped_2_seconds, input_second_part_2) = + split_rtp_packet_dump(input_second_part, Duration::from_secs(2))?; + + let input_handle = thread::spawn(move || { + input_sender.send(&input_first_part).unwrap(); + thread::sleep(Duration::from_secs(3)); + input_sender.send(&input_second_part_2).unwrap(); + }); + + instance.send_request("start", json!({}))?; + + input_handle.join().unwrap(); + let new_output_dump = output_receiver.wait_for_output()?; + + compare_audio_dumps( + OUTPUT_DUMP_FILE, + &new_output_dump, + AudioValidationConfig { + sampling_intervals: vec![ + Duration::from_millis(0)..Duration::from_millis(2000), + Duration::from_millis(2000)..Duration::from_millis(4000), + Duration::from_millis(6000)..Duration::from_millis(8000), + ], + ..Default::default() + }, + )?; + + Ok(()) +} + /// Optional inputs with some packets delayed in the middle /// No offset /// diff --git a/snapshot_tests/snapshots b/snapshot_tests/snapshots index 0d8cc569b..243f38ace 160000 --- a/snapshot_tests/snapshots +++ b/snapshot_tests/snapshots @@ -1 +1 @@ -Subproject commit 0d8cc569b9f616de79c62dbe1e10d3aa3db0cd39 +Subproject commit 243f38ace6a87ba1c5bd113d3f94ea9cb929e79e From 505fc0743899cf28bde20a72961ad4cee7056eaf Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:00:48 +0100 Subject: [PATCH 24/51] Update wgpu to 23.0.0 (#846) --- Cargo.lock | 200 ++++++++---------- Cargo.toml | 4 +- compositor_render/Cargo.toml | 2 +- compositor_render/src/wgpu/common_pipeline.rs | 4 +- .../wgpu/format/interleaved_yuv_to_rgba.rs | 4 +- .../src/wgpu/format/nv12_to_rgba.rs | 4 +- .../src/wgpu/format/planar_yuv_to_rgba.rs | 4 +- .../src/wgpu/format/rgba_to_yuv.rs | 4 +- .../src/wgpu/utils/r8_fill_with_color.rs | 4 +- vk-video/Cargo.toml | 2 +- vk-video/src/vulkan_decoder.rs | 9 +- vk-video/src/vulkan_decoder/vulkan_ctx.rs | 18 +- 12 files changed, 128 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50d40658d..6838ec633 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,18 +272,18 @@ dependencies = [ [[package]] name = "bit-set" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bit_field" @@ -332,9 +332,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" dependencies = [ "bytemuck_derive", ] @@ -464,37 +464,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" -[[package]] -name = "com" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" -dependencies = [ - "com_macros", -] - -[[package]] -name = "com_macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" -dependencies = [ - "com_macros_support", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "com_macros_support" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "compositor_api" version = "0.1.0" @@ -778,17 +747,6 @@ dependencies = [ "syn 2.0.75", ] -[[package]] -name = "d3d12" -version = "22.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017" -dependencies = [ - "bitflags 2.6.0", - "libloading 0.8.0", - "winapi", -] - [[package]] name = "data-encoding" version = "2.6.0" @@ -1253,9 +1211,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "glow" -version = "0.13.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483" dependencies = [ "js-sys", "slotmap", @@ -1275,8 +1233,7 @@ dependencies = [ [[package]] name = "glyphon" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b11b1afb04c1a1be055989042258499473d0a9447f16450b433aba10bc2a46e7" +source = "git+https://github.com/grovesNL/glyphon?rev=f1f50ab#f1f50ab7b1d35291c3504f4b0a50c7f12e0099db" dependencies = [ "cosmic-text", "etagere", @@ -1306,15 +1263,14 @@ dependencies = [ [[package]] name = "gpu-allocator" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" dependencies = [ "log", "presser", "thiserror", - "winapi", - "windows 0.52.0", + "windows 0.58.0", ] [[package]] @@ -1393,21 +1349,6 @@ dependencies = [ "allocator-api2", ] -[[package]] -name = "hassle-rs" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" -dependencies = [ - "bitflags 2.6.0", - "com", - "libc", - "libloading 0.8.0", - "thiserror", - "widestring", - "winapi", -] - [[package]] name = "hermit-abi" version = "0.3.2" @@ -1557,7 +1498,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -1706,9 +1647,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -2041,9 +1982,9 @@ checksum = "96a1fe2275b68991faded2c80aa4a33dba398b77d276038b8f50701a22e55918" [[package]] name = "naga" -version = "22.1.0" +version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad" +checksum = "3d5941e45a15b53aad4375eedf02033adb7a28931eedc31117faffa52e6a857e" dependencies = [ "arrayvec", "bit-set", @@ -2252,9 +2193,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" @@ -3381,18 +3322,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", @@ -3851,9 +3792,9 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -4001,9 +3942,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -4012,9 +3953,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -4027,9 +3968,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -4039,9 +3980,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4049,9 +3990,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -4062,9 +4003,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-log" @@ -4079,9 +4020,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -4115,9 +4056,9 @@ checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" [[package]] name = "wgpu" -version = "22.1.0" +version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d1c4ba43f80542cf63a0a6ed3134629ae73e8ab51e4b765a67f3aa062eb433" +checksum = "76ab52f2d3d18b70d5ab8dd270a1cff3ebe6dbe4a7d13c1cc2557138a9777fdc" dependencies = [ "arrayvec", "cfg_aliases 0.1.1", @@ -4140,9 +4081,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "22.1.0" +version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0348c840d1051b8e86c3bcd31206080c5e71e5933dabd79be1ce732b0b2f089a" +checksum = "0e0c68e7b6322a03ee5b83fcd92caeac5c2a932f6457818179f4652ad2a9c065" dependencies = [ "arrayvec", "bit-vec", @@ -4165,9 +4106,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "22.0.0" +version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f" +checksum = "de6e7266b869de56c7e3ed72a954899f71d14fec6cc81c102b7530b92947601b" dependencies = [ "android_system_properties", "arrayvec", @@ -4175,15 +4116,14 @@ dependencies = [ "bit-set", "bitflags 2.6.0", "block", + "bytemuck", "cfg_aliases 0.1.1", "core-graphics-types", - "d3d12", "glow", "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", "gpu-descriptor", - "hassle-rs", "js-sys", "khronos-egl", "libc", @@ -4205,14 +4145,15 @@ dependencies = [ "wasm-bindgen", "web-sys", "wgpu-types", - "winapi", + "windows 0.58.0", + "windows-core 0.58.0", ] [[package]] name = "wgpu-types" -version = "22.0.0" +version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d" +checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068" dependencies = [ "bitflags 2.6.0", "js-sys", @@ -4301,11 +4242,11 @@ dependencies = [ [[package]] name = "windows" -version = "0.52.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core", + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -4318,6 +4259,41 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + [[package]] name = "windows-registry" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index c0261eb4a..5607ce975 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ socket2 = "0.5.5" webrtc-util = "0.8.0" opus = "0.3.0" rubato = "0.15.0" -glyphon = "0.6.0" +glyphon = { git = "https://github.com/grovesNL/glyphon", rev = "f1f50ab" } futures-util = "0.3.30" tokio = { version = "1", features = ["full"] } schemars = { git = "https://github.com/membraneframework-labs/schemars", rev = "a5ad1f9", features = [ @@ -59,7 +59,7 @@ schemars = { git = "https://github.com/membraneframework-labs/schemars", rev = " ] } shared_memory = "0.12.4" vk-video = { path = "vk-video" } -wgpu = { version = "22.1.0", default-features = false, features = [ +wgpu = { version = "23.0.0", default-features = false, features = [ "wgsl", "dx12", "metal", diff --git a/compositor_render/Cargo.toml b/compositor_render/Cargo.toml index b1e47a3f7..b3b09df27 100644 --- a/compositor_render/Cargo.toml +++ b/compositor_render/Cargo.toml @@ -22,7 +22,7 @@ glyphon = { workspace = true } crossbeam-channel = { workspace = true } resvg = "0.35.0" nalgebra-glm = { version = "0.18.0", features = ["convert-bytemuck"] } -naga = "22.1.0" +naga = "23.0.0" rand = { workspace = true } tracing = { workspace = true } shared_memory = { workspace = true, optional = true } diff --git a/compositor_render/src/wgpu/common_pipeline.rs b/compositor_render/src/wgpu/common_pipeline.rs index 5c22de2cd..68a48796d 100644 --- a/compositor_render/src/wgpu/common_pipeline.rs +++ b/compositor_render/src/wgpu/common_pipeline.rs @@ -111,12 +111,12 @@ pub fn create_render_pipeline( vertex: wgpu::VertexState { buffers: &[Vertex::LAYOUT], module: shader_module, - entry_point: crate::wgpu::common_pipeline::VERTEX_ENTRYPOINT_NAME, + entry_point: Some(crate::wgpu::common_pipeline::VERTEX_ENTRYPOINT_NAME), compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: shader_module, - entry_point: crate::wgpu::common_pipeline::FRAGMENT_ENTRYPOINT_NAME, + entry_point: Some(crate::wgpu::common_pipeline::FRAGMENT_ENTRYPOINT_NAME), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs b/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs index 5b7e9b909..e60702524 100644 --- a/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs +++ b/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs @@ -33,14 +33,14 @@ impl InterleavedYuv422ToRgbaConverter { vertex: wgpu::VertexState { module: &shader_module, - entry_point: "vs_main", + entry_point: Some("vs_main"), buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: "fs_main", + entry_point: Some("fs_main"), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/format/nv12_to_rgba.rs b/compositor_render/src/wgpu/format/nv12_to_rgba.rs index dddcb5091..0a8deac30 100644 --- a/compositor_render/src/wgpu/format/nv12_to_rgba.rs +++ b/compositor_render/src/wgpu/format/nv12_to_rgba.rs @@ -32,14 +32,14 @@ impl Nv12ToRgbaConverter { vertex: wgpu::VertexState { module: &shader_module, - entry_point: "vs_main", + entry_point: Some("vs_main"), buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: "fs_main", + entry_point: Some("fs_main"), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs b/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs index 79fed53a8..a9e6f4b61 100644 --- a/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs +++ b/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs @@ -38,14 +38,14 @@ impl PlanarYuvToRgbaConverter { vertex: wgpu::VertexState { module: &shader_module, - entry_point: "vs_main", + entry_point: Some("vs_main"), buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: "fs_main", + entry_point: Some("fs_main"), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/format/rgba_to_yuv.rs b/compositor_render/src/wgpu/format/rgba_to_yuv.rs index e1f8e46db..866ea3bae 100644 --- a/compositor_render/src/wgpu/format/rgba_to_yuv.rs +++ b/compositor_render/src/wgpu/format/rgba_to_yuv.rs @@ -36,14 +36,14 @@ impl RgbaToYuvConverter { vertex: wgpu::VertexState { module: &shader_module, - entry_point: "vs_main", + entry_point: Some("vs_main"), buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: "fs_main", + entry_point: Some("fs_main"), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::R8Unorm, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/utils/r8_fill_with_color.rs b/compositor_render/src/wgpu/utils/r8_fill_with_color.rs index 65b4d67fb..c5554d01e 100644 --- a/compositor_render/src/wgpu/utils/r8_fill_with_color.rs +++ b/compositor_render/src/wgpu/utils/r8_fill_with_color.rs @@ -30,13 +30,13 @@ impl R8FillWithValue { primitive: PRIMITIVE_STATE, vertex: wgpu::VertexState { module: &shader_module, - entry_point: "vs_main", + entry_point: Some("vs_main"), buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: "fs_main", + entry_point: Some("fs_main"), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::R8Unorm, write_mask: wgpu::ColorWrites::all(), diff --git a/vk-video/Cargo.toml b/vk-video/Cargo.toml index d5e84402e..ea60ae5fc 100644 --- a/vk-video/Cargo.toml +++ b/vk-video/Cargo.toml @@ -17,7 +17,7 @@ h264-reader = { git = "https://github.com/membraneframework-labs/h264-reader.git thiserror = "1.0.59" tracing = "0.1.40" vk-mem = "0.4.0" -wgpu = "22.1.0" +wgpu = "23.0.0" [dev-dependencies] tracing-subscriber = "0.3.18" diff --git a/vk-video/src/vulkan_decoder.rs b/vk-video/src/vulkan_decoder.rs index 099c92d10..d6486d478 100644 --- a/vk-video/src/vulkan_decoder.rs +++ b/vk-video/src/vulkan_decoder.rs @@ -727,6 +727,11 @@ impl VulkanDecoder<'_> { } } + // this has to be done with Option and mut, because the closure we create has to be FnMut. + // this means we cannot consume its captures, so we have to take the option to be able to + // drop the resource. + let mut image_clone = Some(image.clone()); + let hal_texture = unsafe { wgpu::hal::vulkan::Device::texture_from_raw( **image, @@ -747,7 +752,9 @@ impl VulkanDecoder<'_> { format: wgpu::TextureFormat::NV12, mip_level_count: 1, }, - Some(Box::new(image.clone())), + Some(Box::new(move || { + image_clone.take(); + })), ) }; diff --git a/vk-video/src/vulkan_decoder/vulkan_ctx.rs b/vk-video/src/vulkan_decoder/vulkan_ctx.rs index 0785f1ff7..24d94c37b 100644 --- a/vk-video/src/vulkan_decoder/vulkan_ctx.rs +++ b/vk-video/src/vulkan_decoder/vulkan_ctx.rs @@ -211,6 +211,11 @@ impl VulkanCtx { None }; + // this has to be done with Option and mut, because the closure we create has to be FnMut. + // this means we cannot consume its captures, so we have to take the option to be able to + // drop the resource. + let mut instance_clone = Some(instance.clone()); + let wgpu_instance = unsafe { wgpu::hal::vulkan::Instance::from_raw( (*entry).clone(), @@ -221,7 +226,9 @@ impl VulkanCtx { extensions, wgpu::InstanceFlags::empty(), false, - None, + Some(Box::new(move || { + instance_clone.take(); + })), )? }; @@ -323,10 +330,17 @@ impl VulkanCtx { }, }; + // this has to be done with Option and mut, because the closure we create has to be FnMut. + // this means we cannot consume its captures, so we have to take the option to be able to + // drop the resource. + let mut device_clone = Some(device.clone()); + let wgpu_device = unsafe { wgpu_adapter.adapter.device_from_raw( device.device.clone(), - false, + Some(Box::new(move || { + device_clone.take(); + })), &required_extensions, wgpu_features, &wgpu::MemoryHints::default(), From f84f8cc07ec696dcc15c8432794410cd78ad9290 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Tue, 12 Nov 2024 15:33:36 +0100 Subject: [PATCH 25/51] fixes --- .../src/types/from_register_output.rs | 7 ++ compositor_api/src/types/register_output.rs | 2 +- compositor_pipeline/src/pipeline.rs | 2 +- compositor_pipeline/src/pipeline/encoder.rs | 2 +- .../src/pipeline/encoder/ffmpeg_h264.rs | 2 +- compositor_pipeline/src/pipeline/output.rs | 3 +- .../src/pipeline/output/whip.rs | 119 +++++++----------- .../output/whip/establish_peer_connection.rs | 91 ++++++-------- .../output/whip/init_peer_connection.rs | 2 +- .../src/pipeline/pipeline_output.rs | 4 + 10 files changed, 106 insertions(+), 128 deletions(-) diff --git a/compositor_api/src/types/from_register_output.rs b/compositor_api/src/types/from_register_output.rs index 5731c39cd..ff7a3ebe2 100644 --- a/compositor_api/src/types/from_register_output.rs +++ b/compositor_api/src/types/from_register_output.rs @@ -1,3 +1,4 @@ +use axum::http::HeaderValue; use compositor_pipeline::pipeline::{ self, encoder::{ @@ -196,6 +197,12 @@ impl TryFrom for pipeline::RegisterOutputOptions pipeline::AudioCodec::Opus, }); + if let Some(token) = &bearer_token { + if HeaderValue::from_str(format!("Bearer {token}").as_str()).is_err() { + return Err(TypeError::new("Bearer token string is not valid. It must contain only 32-127 ASCII characters")); + }; + } + let (video_encoder_options, output_video_options) = maybe_video_options(video)?; let (audio_encoder_options, output_audio_options) = match audio { Some(OutputRtpAudioOptions { diff --git a/compositor_api/src/types/register_output.rs b/compositor_api/src/types/register_output.rs index bf4da3c43..c70fad968 100644 --- a/compositor_api/src/types/register_output.rs +++ b/compositor_api/src/types/register_output.rs @@ -44,7 +44,7 @@ pub struct WhipOutput { /// WHIP server endpoint pub endpoint_url: String, // Bearer token - pub bearer_token: Option, + pub bearer_token: Option>, /// Video track configuration. pub video: Option, /// Audio track configuration. diff --git a/compositor_pipeline/src/pipeline.rs b/compositor_pipeline/src/pipeline.rs index d4edc5c98..00cfce8cf 100644 --- a/compositor_pipeline/src/pipeline.rs +++ b/compositor_pipeline/src/pipeline.rs @@ -134,7 +134,7 @@ pub struct PipelineCtx { pub output_framerate: Framerate, pub download_dir: Arc, pub event_emitter: Arc, - pub tokio_rt: Arc, + pub tokio_rt: Arc, #[cfg(feature = "vk-video")] pub vulkan_ctx: Option>, } diff --git a/compositor_pipeline/src/pipeline/encoder.rs b/compositor_pipeline/src/pipeline/encoder.rs index 1e6f8eca0..136542d23 100644 --- a/compositor_pipeline/src/pipeline/encoder.rs +++ b/compositor_pipeline/src/pipeline/encoder.rs @@ -148,7 +148,7 @@ impl VideoEncoder { } } - pub fn request_keyframe(&self) -> Sender<()> { + pub fn keyframe_request_sender(&self) -> Sender<()> { match self { Self::H264(encoder) => encoder.keyframe_request_sender(), } diff --git a/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs b/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs index c7bb467ce..c04b3a182 100644 --- a/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs +++ b/compositor_pipeline/src/pipeline/encoder/ffmpeg_h264.rs @@ -148,7 +148,7 @@ impl LibavH264Encoder { self.resolution } - pub fn keyframe_request_sender(&self) -> crossbeam_channel::Sender<()> { + pub fn keyframe_request_sender(&self) -> Sender<()> { self.keyframe_req_sender.clone() } } diff --git a/compositor_pipeline/src/pipeline/output.rs b/compositor_pipeline/src/pipeline/output.rs index f5c84b02d..2e97d3514 100644 --- a/compositor_pipeline/src/pipeline/output.rs +++ b/compositor_pipeline/src/pipeline/output.rs @@ -19,6 +19,7 @@ use whip::{WhipSender, WhipSenderOptions}; pub mod mp4; pub mod rtp; pub mod whip; + /// Options to configure public outputs that can be constructed via REST API #[derive(Debug, Clone)] pub struct OutputOptions { @@ -233,7 +234,7 @@ impl Output { .video .as_ref() .ok_or(RequestKeyframeError::NoVideoOutput(output_id))? - .request_keyframe() + .keyframe_request_sender() .send(()) { debug!(%err, "Failed to send keyframe request to the encoder."); diff --git a/compositor_pipeline/src/pipeline/output/whip.rs b/compositor_pipeline/src/pipeline/output/whip.rs index 8e9f3e9f9..e0ef5aab1 100644 --- a/compositor_pipeline/src/pipeline/output/whip.rs +++ b/compositor_pipeline/src/pipeline/output/whip.rs @@ -1,26 +1,23 @@ use compositor_render::OutputId; use crossbeam_channel::{Receiver, Sender}; use establish_peer_connection::connect; -use init_peer_connection::init_pc; +use init_peer_connection::init_peer_connection; use packet_stream::PacketStream; use payloader::{Payload, Payloader, PayloadingError}; -use reqwest::{Method, StatusCode, Url}; +use reqwest::{Method, StatusCode}; use std::{ sync::{atomic::AtomicBool, Arc}, thread, - time::{Duration, SystemTime}, + time::{Duration, Instant}, }; -use tokio::sync::oneshot; +use tokio::{runtime::Runtime, sync::oneshot}; use tracing::{debug, error, span, Instrument, Level}; -use url::ParseError; -use webrtc::{ - peer_connection::RTCPeerConnection, - track::track_local::{track_local_static_rtp::TrackLocalStaticRTP, TrackLocalWriter}, -}; +use url::{ParseError, Url}; +use webrtc::track::track_local::TrackLocalWriter; use crate::{ error::OutputInitError, - event::Event, + event::{Event, EventEmitter}, pipeline::{AudioCodec, EncoderOutputEvent, PipelineCtx, VideoCodec}, }; @@ -38,11 +35,19 @@ pub struct WhipSender { #[derive(Debug, Clone)] pub struct WhipSenderOptions { pub endpoint_url: String, - pub bearer_token: Option, + pub bearer_token: Option>, pub video: Option, pub audio: Option, } +pub struct WhipCtx { + options: WhipSenderOptions, + output_id: OutputId, + request_keyframe_sender: Option>, + should_close: Arc, + tokio_rt: Arc, +} + #[derive(Debug, thiserror::Error)] pub enum WhipError { #[error("Bad status in WHIP response\nStatus: {0}\nBody: {1}")] @@ -75,7 +80,7 @@ pub enum WhipError { RemoteDescriptionError(webrtc::Error), #[error("Failed to parse {0} response body: {1}")] - BodyParsingError(String, reqwest::Error), + BodyParsingError(&'static str, reqwest::Error), #[error("Failed to create offer: {0}")] OfferCreationError(webrtc::Error), @@ -105,37 +110,25 @@ impl WhipSender { ) -> Result { let payloader = Payloader::new(options.video, options.audio); let packet_stream = PacketStream::new(packets_receiver, payloader, 1400); - let should_close = Arc::new(AtomicBool::new(false)); - let endpoint_url = options.endpoint_url.clone(); - let bearer_token = options.bearer_token.clone(); - let output_id = output_id.clone(); - let should_close2 = should_close.clone(); - let event_emitter = pipeline_ctx.event_emitter.clone(); - let request_keyframe_sender = request_keyframe_sender.clone(); - - let tokio_rt = pipeline_ctx.tokio_rt.clone(); - let tokio_rt_clone = tokio_rt.clone(); - let output_id_clone = output_id.clone(); - let (init_confirmation_sender, mut init_confirmation_receiver) = oneshot::channel::>(); - tokio_rt.spawn( - async move { - run_whip_sender_thread( - endpoint_url, - bearer_token, - should_close2, - packet_stream, - request_keyframe_sender, - tokio_rt_clone, - init_confirmation_sender, - ) - .await; - event_emitter.emit(Event::OutputDone(output_id_clone)); - debug!("Closing WHIP sender thread.") - } + let whip_ctx = WhipCtx { + options: options.clone(), + output_id: output_id.clone(), + request_keyframe_sender, + should_close: should_close.clone(), + tokio_rt: pipeline_ctx.tokio_rt.clone(), + }; + + pipeline_ctx.tokio_rt.spawn( + run_whip_sender_task( + whip_ctx, + packet_stream, + init_confirmation_sender, + pipeline_ctx.event_emitter.clone(), + ) .instrument(span!( Level::INFO, "WHIP sender", @@ -143,10 +136,10 @@ impl WhipSender { )), ); - let start_time = SystemTime::now(); + let start_time = Instant::now(); loop { - thread::sleep(Duration::from_secs(5)); - let elapsed_time = SystemTime::now().duration_since(start_time).unwrap(); + thread::sleep(Duration::from_millis(500)); + let elapsed_time = Instant::now().duration_since(start_time); if elapsed_time > WHIP_INIT_TIMEOUT { return Err(OutputInitError::WhipInitTimeout); } @@ -178,41 +171,23 @@ impl Drop for WhipSender { } } -async fn run_whip_sender_thread( - endpoint_url: String, - bearer_token: Option, - should_close: Arc, +async fn run_whip_sender_task( + whip_ctx: WhipCtx, packet_stream: PacketStream, - request_keyframe_sender: Option>, - tokio_rt: Arc, init_confirmation_sender: oneshot::Sender>, + event_emitter: Arc, ) { - let client = reqwest::Client::new(); - let peer_connection: Arc; - let video_track: Arc; - let audio_track: Arc; - match init_pc().await { - Ok((pc, video, audio)) => { - peer_connection = pc; - video_track = video; - audio_track = audio; - } + let client = Arc::new(reqwest::Client::new()); + let (peer_connection, video_track, audio_track) = match init_peer_connection().await { + Ok(pc) => pc, Err(err) => { init_confirmation_sender.send(Err(err)).unwrap(); return; } - } - let whip_session_url = match connect( - peer_connection, - endpoint_url, - bearer_token, - should_close.clone(), - tokio_rt, - client.clone(), - request_keyframe_sender, - ) - .await - { + }; + let output_id_clone = whip_ctx.output_id.clone(); + let should_close_clone = whip_ctx.should_close.clone(); + let whip_session_url = match connect(peer_connection, client.clone(), whip_ctx).await { Ok(val) => val, Err(err) => { init_confirmation_sender.send(Err(err)).unwrap(); @@ -222,7 +197,7 @@ async fn run_whip_sender_thread( init_confirmation_sender.send(Ok(())).unwrap(); for chunk in packet_stream { - if should_close.load(std::sync::atomic::Ordering::Relaxed) { + if should_close_clone.load(std::sync::atomic::Ordering::Relaxed) { break; } let chunk = match chunk { @@ -257,4 +232,6 @@ async fn run_whip_sender_thread( } } let _ = client.delete(whip_session_url).send().await; + event_emitter.emit(Event::OutputDone(output_id_clone)); + debug!("Closing WHIP sender thread.") } diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs index 8edc4fb54..c623d2fc2 100644 --- a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -1,8 +1,9 @@ -use crossbeam_channel::Sender; - -use super::WhipError; -use reqwest::{header::HeaderMap, Client, Method, StatusCode, Url}; -use std::sync::{atomic::AtomicBool, Arc}; +use super::{WhipCtx, WhipError}; +use reqwest::{ + header::{HeaderMap, HeaderValue}, + Client, Method, StatusCode, Url, +}; +use std::sync::Arc; use tracing::{debug, error, info, warn}; use webrtc::{ ice_transport::{ice_candidate::RTCIceCandidate, ice_connection_state::RTCIceConnectionState}, @@ -12,12 +13,8 @@ use webrtc::{ pub async fn connect( peer_connection: Arc, - endpoint_url: String, - bearer_token: Option, - should_close: Arc, - tokio_rt: Arc, - client: reqwest::Client, - request_keyframe_sender: Option>, + client: Arc, + whip_ctx: WhipCtx, ) -> Result { peer_connection.on_ice_connection_state_change(Box::new( move |connection_state: RTCIceConnectionState| { @@ -26,17 +23,19 @@ pub async fn connect( debug!("Ice connected."); } else if connection_state == RTCIceConnectionState::Failed { debug!("Ice connection failed."); - should_close.store(true, std::sync::atomic::Ordering::Relaxed); + whip_ctx + .should_close + .store(true, std::sync::atomic::Ordering::Relaxed); } Box::pin(async {}) }, )); - if let Some(keyframe_sender) = request_keyframe_sender { + if let Some(keyframe_sender) = whip_ctx.request_keyframe_sender { let senders = peer_connection.get_senders().await; for sender in senders { let keyframe_sender_clone = keyframe_sender.clone(); - tokio_rt.spawn(async move { + whip_ctx.tokio_rt.spawn(async move { loop { if let Ok((packets, _)) = &sender.read_rtcp().await { for packet in packets { @@ -63,39 +62,34 @@ pub async fn connect( .await .map_err(WhipError::OfferCreationError)?; - let endpoint_url = Url::parse(&endpoint_url) - .map_err(|e| WhipError::InvalidEndpointUrl(e, endpoint_url.clone()))?; + let endpoint_url = Url::parse(&whip_ctx.options.endpoint_url) + .map_err(|e| WhipError::InvalidEndpointUrl(e, whip_ctx.options.endpoint_url.clone()))?; info!("Endpoint url: {}", endpoint_url); let mut header_map = HeaderMap::new(); - header_map.append("Content-Type", "application/sdp".parse().unwrap()); + header_map.append("Content-Type", HeaderValue::from_static("application/sdp")); - let bearer_token = bearer_token.map(Arc::new); - - if let Some(token) = bearer_token.clone() { + if let Some(token) = &whip_ctx.options.bearer_token { header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); } - let response = match client + let response = client .post(endpoint_url.clone()) .headers(header_map) .body(offer.sdp.clone()) .send() .await - { - Ok(res) => res, - Err(_) => return Err(WhipError::RequestFailed(Method::POST, endpoint_url)), - }; + .map_err(|_| WhipError::RequestFailed(Method::POST, endpoint_url.clone()))?; - if response.status() >= StatusCode::BAD_REQUEST { - let status = response.status(); - let answer = response + if let Err(err) = &response.error_for_status_ref() { + let status = err.status().unwrap(); + let answer = &response .text() .await - .map_err(|e| WhipError::BodyParsingError("sdp offer".to_string(), e))?; - return Err(WhipError::BadStatus(status, answer)); - } + .map_err(|e| WhipError::BodyParsingError("sdp offer", e))?; + return Err(WhipError::BadStatus(status, answer.to_string())); + }; let location_url_path = response .headers() @@ -123,7 +117,7 @@ pub async fn connect( let answer = response .text() .await - .map_err(|e| WhipError::BodyParsingError("sdp offer".to_string(), e))?; + .map_err(|e| WhipError::BodyParsingError("sdp offer", e))?; let rtc_answer = RTCSessionDescription::answer(answer).map_err(WhipError::RTCSessionDescriptionError)?; @@ -133,33 +127,28 @@ pub async fn connect( .await .map_err(WhipError::RemoteDescriptionError)?; - let client = Arc::new(client); - - let location_clone: Url = location_url.clone(); - + let location_url_clone = location_url.clone(); peer_connection.on_ice_candidate(Box::new(move |candidate| { - if let Some(candidate) = candidate { - let client_clone = client.clone(); - let location_clone = location_clone.clone(); - let bearer_token_clone = bearer_token.clone(); - tokio_rt.spawn(async move { + let bearer_token = whip_ctx.options.bearer_token.clone(); + let client = client.clone(); + let location_url = location_url_clone.clone(); + Box::pin(async move { + if let Some(candidate) = candidate { if let Err(err) = - handle_candidate(candidate, bearer_token_clone, client_clone, location_clone) - .await + handle_candidate(candidate, bearer_token, client, location_url.clone()).await { error!("{err}"); } - }); - } - Box::pin(async {}) + } + }) })); - Ok(location_url.clone()) + Ok(location_url) } async fn handle_candidate( candidate: RTCIceCandidate, - bearer_token: Option>, + bearer_token: Option>, client: Arc, location: Url, ) -> Result<(), WhipError> { @@ -170,7 +159,7 @@ async fn handle_candidate( let mut header_map = HeaderMap::new(); header_map.append( "Content-Type", - "application/trickle-ice-sdpfrag".parse().unwrap(), + HeaderValue::from_static("application/trickle-ice-sdpfrag"), ); if let Some(token) = bearer_token { @@ -185,7 +174,7 @@ async fn handle_candidate( .await { Ok(res) => res, - Err(_) => return Err(WhipError::RequestFailed(Method::PATCH, location)), + Err(_) => return Err(WhipError::RequestFailed(Method::PATCH, location.clone())), }; if response.status() >= StatusCode::BAD_REQUEST { @@ -193,7 +182,7 @@ async fn handle_candidate( let body_str = response .text() .await - .map_err(|e| WhipError::BodyParsingError("Trickle ICE patch".to_string(), e))?; + .map_err(|e| WhipError::BodyParsingError("Trickle ICE patch", e))?; if status == StatusCode::UNPROCESSABLE_ENTITY || status == StatusCode::METHOD_NOT_ALLOWED { warn!("Error while sending Ice Candidate do WHIP Server (Trickle ICE is probably not supported):\nStaus code: {status}\nBody: {body_str}") } else { diff --git a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs index 6f686c963..3b379e01b 100644 --- a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs @@ -16,7 +16,7 @@ use webrtc::{ track::track_local::track_local_static_rtp::TrackLocalStaticRTP, }; -pub async fn init_pc() -> Result< +pub async fn init_peer_connection() -> Result< ( Arc, Arc, diff --git a/compositor_pipeline/src/pipeline/pipeline_output.rs b/compositor_pipeline/src/pipeline/pipeline_output.rs index f62eeb8d8..e4c7bf08f 100644 --- a/compositor_pipeline/src/pipeline/pipeline_output.rs +++ b/compositor_pipeline/src/pipeline/pipeline_output.rs @@ -56,6 +56,10 @@ pub(super) fn register_pipeline_output( let mut guard = pipeline.lock().unwrap(); + if guard.outputs.contains_key(&output_id) { + return Err(RegisterOutputError::AlreadyRegistered(output_id)); + } + let output = PipelineOutput { output, audio_end_condition: audio.as_ref().map(|audio| { From 8432a17f9b7ab9d317850785c9b060fa3e1dc490 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Nov 2024 09:29:36 +0100 Subject: [PATCH 26/51] Bump http-proxy-middleware from 2.0.6 to 2.0.7 in /docs (#837) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index e079c334b..3355a1773 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -9158,9 +9158,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", From f7597aef39b66fca887f6fce0af11ce2e01d382f Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Thu, 14 Nov 2024 11:00:07 +0100 Subject: [PATCH 27/51] Box shadow implementation closer to CSS specs (#858) --- .../src/transformations/layout/apply_layouts.wgsl | 2 +- .../src/transformations/layout/flatten.rs | 13 ++++++------- snapshot_tests/snapshots | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/compositor_render/src/transformations/layout/apply_layouts.wgsl b/compositor_render/src/transformations/layout/apply_layouts.wgsl index 8fb19918a..8a2b5bad7 100644 --- a/compositor_render/src/transformations/layout/apply_layouts.wgsl +++ b/compositor_render/src/transformations/layout/apply_layouts.wgsl @@ -361,7 +361,7 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { rotation_degrees ); - let blur_alpha = smoothstep(0.0, blur_radius, edge_distance) * mask_alpha; + let blur_alpha = smoothstep(-blur_radius / 2.0, blur_radius / 2.0, edge_distance) * mask_alpha; return vec4(color.rgb, color.a * blur_alpha); } diff --git a/compositor_render/src/transformations/layout/flatten.rs b/compositor_render/src/transformations/layout/flatten.rs index fe4215ab4..33abd9fe8 100644 --- a/compositor_render/src/transformations/layout/flatten.rs +++ b/compositor_render/src/transformations/layout/flatten.rs @@ -346,16 +346,15 @@ impl NestedLayout { /// calculate RenderLayout for one of self box shadows fn box_shadow_layout(&self, box_shadow: &BoxShadow, parent_masks: &[Mask]) -> RenderLayout { RenderLayout { - top: self.top + box_shadow.offset_y - 0.5 * box_shadow.blur_radius, - left: self.left + box_shadow.offset_x - 0.5 * box_shadow.blur_radius, - width: self.width + box_shadow.blur_radius, - height: self.height + box_shadow.blur_radius, + top: self.top + box_shadow.offset_y, + left: self.left + box_shadow.offset_x, + width: self.width, + height: self.height, rotation_degrees: self.rotation_degrees, // TODO: this is incorrect - border_radius: self.border_radius + box_shadow.blur_radius, + border_radius: self.border_radius + (box_shadow.blur_radius / 2.0), content: RenderLayoutContent::BoxShadow { color: box_shadow.color, - blur_radius: box_shadow.blur_radius * 2.0, // TODO: 2.0 is empirically selected - // value + blur_radius: box_shadow.blur_radius, }, masks: parent_masks.to_vec(), } diff --git a/snapshot_tests/snapshots b/snapshot_tests/snapshots index 243f38ace..57fbdbaa6 160000 --- a/snapshot_tests/snapshots +++ b/snapshot_tests/snapshots @@ -1 +1 @@ -Subproject commit 243f38ace6a87ba1c5bd113d3f94ea9cb929e79e +Subproject commit 57fbdbaa6cf83e4cfe907c04af409221e5a1d566 From 01e55fd4db8c954643c718b4eb0c48b0c7376c1d Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Thu, 14 Nov 2024 12:16:28 +0100 Subject: [PATCH 28/51] Add file logger (#853) --- CHANGELOG.md | 3 + docs/pages/deployment/configuration.md | 4 ++ generate/src/compositor_instance.rs | 13 +--- .../examples/encoded_channel_output.rs | 14 +--- .../examples/raw_channel_input.rs | 10 +-- .../examples/raw_channel_output.rs | 10 +-- integration_tests/examples/vulkan.rs | 10 +-- integration_tests/src/compositor_instance.rs | 11 ++-- src/config.rs | 15 ++++- src/logger.rs | 64 +++++++++++++------ 10 files changed, 82 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94d6e3d8c..24cf8e270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ ### โœจ New features - Add `loop` option for MP4 input. ([#699](https://github.com/software-mansion/live-compositor/pull/699) by [@WojciechBarczynski](https://github.com/WojciechBarczynski)) +- Add `LIVE_COMPOSITOR_LOG_FILE` environment variable to enable logging to file ([#853](https://github.com/software-mansion/live-compositor/pull/853) by [@wkozyra95](https://github.com/wkozyra95)) +- Add border, border radius and box shadow options to `Rescaler` and `View` components. ([#815](https://github.com/software-mansion/live-compositor/pull/815) by [@WojciechBarczynski](https://github.com/WojciechBarczynski), ([#839](https://github.com/software-mansion/live-compositor/pull/839), [#842](https://github.com/software-mansion/live-compositor/pull/842), [#858](https://github.com/software-mansion/live-compositor/pull/858) by [@wkozyra95](https://github.com/wkozyra95)) + ### ๐Ÿ› Bug fixes diff --git a/docs/pages/deployment/configuration.md b/docs/pages/deployment/configuration.md index be638d4b5..913c53ba7 100644 --- a/docs/pages/deployment/configuration.md +++ b/docs/pages/deployment/configuration.md @@ -128,3 +128,7 @@ Increasing this value always increases the latency of the stream by the same amo ::: Defaults to `80ms` (about 5 frames in 60 fps). + +### `LIVE_COMPOSITOR_LOG_FILE` + +Path to the file were Live Compositor logs should be written. Setting this option does not disable logging to the standard output. diff --git a/generate/src/compositor_instance.rs b/generate/src/compositor_instance.rs index 6970c1191..aa36656ce 100644 --- a/generate/src/compositor_instance.rs +++ b/generate/src/compositor_instance.rs @@ -1,11 +1,6 @@ use anyhow::{anyhow, Result}; use crossbeam_channel::Sender; -use live_compositor::{ - config::{read_config, LoggerConfig, LoggerFormat}, - logger::{self, FfmpegLogLevel}, - server::run_api, - state::ApiState, -}; +use live_compositor::{config::read_config, logger, server::run_api, state::ApiState}; use reqwest::StatusCode; use std::{ env, @@ -113,10 +108,6 @@ fn init_compositor_prerequisites() { GLOBAL_PREREQUISITES_INITIALIZED.get_or_init(|| { env::set_var("LIVE_COMPOSITOR_WEB_RENDERER_ENABLE", "0"); ffmpeg_next::format::network::init(); - logger::init_logger(LoggerConfig { - ffmpeg_logger_level: FfmpegLogLevel::Info, - format: LoggerFormat::Compact, - level: "warn,wgpu_hal=warn,wgpu_core=warn".to_string(), - }); + logger::init_logger(read_config().logger); }); } diff --git a/integration_tests/examples/encoded_channel_output.rs b/integration_tests/examples/encoded_channel_output.rs index 00397e0a7..fdf5e6d26 100644 --- a/integration_tests/examples/encoded_channel_output.rs +++ b/integration_tests/examples/encoded_channel_output.rs @@ -23,11 +23,7 @@ use compositor_render::{ InputId, OutputId, Resolution, }; use integration_tests::examples::download_file; -use live_compositor::{ - config::{read_config, LoggerConfig, LoggerFormat}, - logger::{self, FfmpegLogLevel}, - state::ApiState, -}; +use live_compositor::{config::read_config, logger, state::ApiState}; const BUNNY_FILE_URL: &str = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"; @@ -38,13 +34,9 @@ const BUNNY_FILE_PATH: &str = "examples/assets/BigBuckBunny.mp4"; // Data read from channels are dumped into files as it is without any timestamp data. fn main() { ffmpeg_next::format::network::init(); - logger::init_logger(LoggerConfig { - ffmpeg_logger_level: FfmpegLogLevel::Info, - format: LoggerFormat::Compact, - level: "info,wgpu_hal=warn,wgpu_core=warn".to_string(), - }); - let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut config = read_config(); + logger::init_logger(config.logger.clone()); + let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); config.queue_options.ahead_of_time_processing = true; // no chromium support, so we can ignore _event_loop let (state, _event_loop) = ApiState::new(config).unwrap_or_else(|err| { diff --git a/integration_tests/examples/raw_channel_input.rs b/integration_tests/examples/raw_channel_input.rs index 163442b01..06fb7d50e 100644 --- a/integration_tests/examples/raw_channel_input.rs +++ b/integration_tests/examples/raw_channel_input.rs @@ -29,8 +29,8 @@ use compositor_render::{ }; use integration_tests::{gstreamer::start_gst_receive_tcp, test_input::TestInput}; use live_compositor::{ - config::{read_config, LoggerConfig, LoggerFormat}, - logger::{self, FfmpegLogLevel}, + config::read_config, + logger::{self}, }; const VIDEO_OUTPUT_PORT: u16 = 8002; @@ -38,12 +38,8 @@ const VIDEO_OUTPUT_PORT: u16 = 8002; // Start simple pipeline with input that sends PCM audio and wgpu::Textures via Rust channel. fn main() { ffmpeg_next::format::network::init(); - logger::init_logger(LoggerConfig { - ffmpeg_logger_level: FfmpegLogLevel::Info, - format: LoggerFormat::Compact, - level: "info,wgpu_hal=warn,wgpu_core=warn".to_string(), - }); let config = read_config(); + logger::init_logger(config.logger); let ctx = GraphicsContext::new(false, Default::default(), Default::default()).unwrap(); let (wgpu_device, wgpu_queue) = (ctx.device.clone(), ctx.queue.clone()); // no chromium support, so we can ignore _event_loop diff --git a/integration_tests/examples/raw_channel_output.rs b/integration_tests/examples/raw_channel_output.rs index 8d18ca3b3..4f7143a47 100644 --- a/integration_tests/examples/raw_channel_output.rs +++ b/integration_tests/examples/raw_channel_output.rs @@ -31,8 +31,8 @@ use crossbeam_channel::bounded; use image::{codecs::png::PngEncoder, ColorType, ImageEncoder}; use integration_tests::{examples::download_file, read_rgba_texture}; use live_compositor::{ - config::{read_config, LoggerConfig, LoggerFormat}, - logger::{self, FfmpegLogLevel}, + config::read_config, + logger::{self}, }; const BUNNY_FILE_URL: &str = @@ -50,11 +50,7 @@ fn root_dir() -> PathBuf { // - read audio samples and write raw value using debug formatting fn main() { ffmpeg_next::format::network::init(); - logger::init_logger(LoggerConfig { - ffmpeg_logger_level: FfmpegLogLevel::Info, - format: LoggerFormat::Compact, - level: "info,wgpu_hal=warn,wgpu_core=warn".to_string(), - }); + logger::init_logger(read_config().logger); let mut config = read_config(); config.queue_options.ahead_of_time_processing = true; let ctx = GraphicsContext::new(false, Default::default(), Default::default()).unwrap(); diff --git a/integration_tests/examples/vulkan.rs b/integration_tests/examples/vulkan.rs index fa884563c..dc7fd4e7f 100644 --- a/integration_tests/examples/vulkan.rs +++ b/integration_tests/examples/vulkan.rs @@ -1,17 +1,13 @@ use anyhow::Result; use integration_tests::examples::download_all_assets; use live_compositor::{ - config::{LoggerConfig, LoggerFormat}, - logger::{self, FfmpegLogLevel}, + config::read_config, + logger::{self}, }; fn main() { ffmpeg_next::format::network::init(); - logger::init_logger(LoggerConfig { - ffmpeg_logger_level: FfmpegLogLevel::Info, - format: LoggerFormat::Compact, - level: "info,wgpu_hal=warn,wgpu_core=warn".to_string(), - }); + logger::init_logger(read_config().logger); download_all_assets().unwrap(); diff --git a/integration_tests/src/compositor_instance.rs b/integration_tests/src/compositor_instance.rs index 8c707f9e1..9f90e4244 100644 --- a/integration_tests/src/compositor_instance.rs +++ b/integration_tests/src/compositor_instance.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; use crossbeam_channel::Sender; use live_compositor::{ - config::{read_config, Config, LoggerConfig, LoggerFormat}, - logger::{self, FfmpegLogLevel}, + config::{read_config, Config}, + logger::{self}, server::run_api, state::ApiState, }; @@ -112,10 +112,7 @@ fn init_compositor_prerequisites() { GLOBAL_PREREQUISITES_INITIALIZED.get_or_init(|| { env::set_var("LIVE_COMPOSITOR_WEB_RENDERER_ENABLE", "0"); ffmpeg_next::format::network::init(); - logger::init_logger(LoggerConfig { - ffmpeg_logger_level: FfmpegLogLevel::Info, - format: LoggerFormat::Compact, - level: "info,wgpu_hal=warn,wgpu_core=warn".to_string(), - }); + let config = read_config(); + logger::init_logger(config.logger); }); } diff --git a/src/config.rs b/src/config.rs index 7035ff010..1869cb65e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,10 @@ -use std::{env, path::PathBuf, str::FromStr, time::Duration}; +use std::{ + env, + path::{Path, PathBuf}, + str::FromStr, + sync::Arc, + time::Duration, +}; use compositor_pipeline::queue::{self, QueueOptions}; use compositor_render::{web_renderer::WebRendererInitOptions, Framerate, WgpuFeatures}; @@ -25,6 +31,7 @@ pub struct LoggerConfig { pub ffmpeg_logger_level: FfmpegLogLevel, pub format: LoggerFormat, pub level: String, + pub log_file: Option>, } #[derive(Debug, Copy, Clone)] @@ -182,6 +189,11 @@ fn try_read_config() -> Result { Err(_) => queue::DEFAULT_BUFFER_DURATION, }; + let log_file = match env::var("LIVE_COMPOSITOR_LOG_FILE") { + Ok(path) => Some(Arc::from(PathBuf::from(path))), + Err(_) => None, + }; + let config = Config { instance_id, api_port, @@ -189,6 +201,7 @@ fn try_read_config() -> Result { ffmpeg_logger_level, format: logger_format, level: logger_level, + log_file, }, queue_options: QueueOptions { default_buffer_duration, diff --git a/src/logger.rs b/src/logger.rs index 69a562414..4f3925209 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,4 +1,16 @@ -use std::{str::FromStr, sync::OnceLock}; +use std::{ + fmt::Debug, + fs::{self, File}, + str::FromStr, + sync::OnceLock, +}; + +use tracing_subscriber::{ + fmt::{self}, + layer::SubscriberExt, + util::SubscriberInitExt, + Layer, Registry, +}; use crate::config::{read_config, LoggerConfig, LoggerFormat}; @@ -58,27 +70,37 @@ extern "C" fn ffmpeg_log_callback( } pub fn init_logger(opts: LoggerConfig) { - let env_filter = tracing_subscriber::EnvFilter::new(opts.level); - match opts.format { - LoggerFormat::Pretty => { - tracing_subscriber::fmt() - .pretty() - .with_env_filter(env_filter) - .init(); - } - LoggerFormat::Json => { - tracing_subscriber::fmt() - .json() - .with_env_filter(env_filter) - .init(); - } - LoggerFormat::Compact => { - tracing_subscriber::fmt() - .compact() - .with_env_filter(env_filter) - .init(); - } + let env_filter = tracing_subscriber::EnvFilter::new(opts.level.clone()); + + let stdout_layer = match opts.format { + LoggerFormat::Pretty => fmt::Layer::default().pretty().boxed(), + LoggerFormat::Json => fmt::Layer::default().json().boxed(), + LoggerFormat::Compact => fmt::Layer::default().compact().boxed(), + }; + + let file_layer = if let Some(log_file) = opts.log_file { + if log_file.exists() { + fs::remove_file(&log_file).unwrap() + }; + fs::create_dir_all(log_file.parent().unwrap()).unwrap(); + let writer = File::create(log_file).unwrap(); + Some(fmt::Layer::default().json().with_writer(writer)) + } else { + None + }; + + match file_layer { + Some(file_layer) => Registry::default() + .with(stdout_layer) + .with(file_layer) + .with(env_filter) + .init(), + None => Registry::default() + .with(stdout_layer) + .with(env_filter) + .init(), } + unsafe { ffmpeg_next::sys::av_log_set_callback(Some(ffmpeg_log_callback)); } From 004cdd4fd7726994aab70982c3c4fb060bc0bfc3 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Thu, 14 Nov 2024 18:01:59 +0100 Subject: [PATCH 29/51] get stun servers from env --- .../output/whip/init_peer_connection.rs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs index 3b379e01b..90c6b5b04 100644 --- a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs @@ -1,5 +1,9 @@ use super::WhipError; -use std::sync::Arc; +use std::{ + env::{self, VarError}, + sync::Arc, +}; +use tracing::{info, warn}; use webrtc::{ api::{ interceptor_registry::register_default_interceptors, @@ -16,6 +20,8 @@ use webrtc::{ track::track_local::track_local_static_rtp::TrackLocalStaticRTP, }; +const STUN_SERVER_ENV: &str = "LIVE_COMPOSITOR_STUN_SERVERS"; + pub async fn init_peer_connection() -> Result< ( Arc, @@ -61,9 +67,27 @@ pub async fn init_peer_connection() -> Result< .with_interceptor_registry(registry) .build(); + let mut stun_servers_urls = vec!["stun:stun.l.google.com:19302".to_owned()]; + + match env::var(STUN_SERVER_ENV) { + Ok(var) => { + if var.len() == 0 { + info!("Empty LIVE_COMPOSITOR_STUN_SERVERS environment variable, using default"); + } else { + let env_url_list: Vec = var.split(',').map(String::from).collect(); + stun_servers_urls.extend(env_url_list); + info!("Using custom stun servers defined in LIVE_COMPOSITOR_STUN_SERVERS environment variable"); + } + } + Err(err) => match err { + VarError::NotPresent => info!("No stun servers provided, using default"), + VarError::NotUnicode(_) => warn!("Invalid LIVE_COMPOSITOR_STUN_SERVERS environment variable, it is not a valid Unicode, using default") + }, + } + let config = RTCConfiguration { ice_servers: vec![RTCIceServer { - urls: vec!["stun:stun.l.google.com:19302".to_owned()], + urls: stun_servers_urls, ..Default::default() }], ..Default::default() From 90b2dd6390166675bd60fbeca84f840573d8f565 Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Fri, 15 Nov 2024 10:47:08 +0100 Subject: [PATCH 30/51] [tests] Add tests that verify YUV conversion (#860) --- src/snapshot_tests.rs | 1 + src/snapshot_tests/test_case.rs | 34 +++--- src/snapshot_tests/utils.rs | 120 ++++++++++++++++++-- src/snapshot_tests/yuv_tests.rs | 125 +++++++++++++++++++++ src/snapshot_tests/yuv_tests/gradient.wgsl | 37 ++++++ 5 files changed, 294 insertions(+), 23 deletions(-) create mode 100644 src/snapshot_tests/yuv_tests.rs create mode 100644 src/snapshot_tests/yuv_tests/gradient.wgsl diff --git a/src/snapshot_tests.rs b/src/snapshot_tests.rs index 54122e53e..1ead65b80 100644 --- a/src/snapshot_tests.rs +++ b/src/snapshot_tests.rs @@ -24,6 +24,7 @@ mod tiles_tests; mod tiles_transitions_tests; mod transition_tests; mod view_tests; +mod yuv_tests; const DEFAULT_RESOLUTION: Resolution = Resolution { width: 640, diff --git a/src/snapshot_tests/test_case.rs b/src/snapshot_tests/test_case.rs index 48d46dd58..fbef84ba2 100644 --- a/src/snapshot_tests/test_case.rs +++ b/src/snapshot_tests/test_case.rs @@ -25,6 +25,7 @@ pub(super) struct TestCase { pub only: bool, pub allowed_error: f32, pub resolution: Resolution, + pub output_format: OutputFrameFormat, } impl Default for TestCase { @@ -41,6 +42,7 @@ impl Default for TestCase { width: 640, height: 360, }, + output_format: OutputFrameFormat::PlanarYuv420Bytes, } } } @@ -51,8 +53,8 @@ pub(super) enum TestResult { } impl TestCase { - fn renderer(&self) -> Renderer { - let renderer = create_renderer(); + pub(super) fn renderer(&self) -> Renderer { + let mut renderer = create_renderer(); for (id, spec) in self.renderers.iter() { renderer .register_renderer(id.clone(), spec.clone()) @@ -63,27 +65,27 @@ impl TestCase { renderer.register_input(InputId(format!("input_{}", index + 1).into())) } - renderer - } - - pub(super) fn run(&self) -> TestResult { - if self.name.is_empty() { - panic!("Snapshot test name has to be provided"); - } - let mut renderer = self.renderer(); - let mut result = TestResult::Success; - for update in &self.scene_updates { renderer .update_scene( OutputId(OUTPUT_ID.into()), self.resolution, - OutputFrameFormat::PlanarYuv420Bytes, + self.output_format, update.clone(), ) .unwrap(); } + renderer + } + + pub(super) fn run(&self) -> TestResult { + if self.name.is_empty() { + panic!("Snapshot test name has to be provided"); + } + let mut renderer = self.renderer(); + let mut result = TestResult::Success; + for pts in self.timestamps.iter().copied() { if let TestResult::Failure = self.test_snapshots_for_pts(&mut renderer, pts) { result = TestResult::Failure; @@ -122,7 +124,11 @@ impl TestCase { .collect() } - fn snapshot_for_pts(&self, renderer: &mut Renderer, pts: Duration) -> Result { + pub(super) fn snapshot_for_pts( + &self, + renderer: &mut Renderer, + pts: Duration, + ) -> Result { let mut frame_set = FrameSet::new(pts); for input in self.inputs.iter() { let input_id = InputId::from(Arc::from(input.name.clone())); diff --git a/src/snapshot_tests/utils.rs b/src/snapshot_tests/utils.rs index 5454d0adc..6de77f988 100644 --- a/src/snapshot_tests/utils.rs +++ b/src/snapshot_tests/utils.rs @@ -1,25 +1,36 @@ use core::panic; use std::{ + io::Write, sync::{Arc, OnceLock}, time::Duration, }; +use bytes::BufMut; use compositor_render::{ create_wgpu_ctx, web_renderer, Frame, FrameData, Framerate, Renderer, RendererOptions, WgpuFeatures, YuvPlanes, }; +use crossbeam_channel::bounded; +use tracing::error; pub const SNAPSHOTS_DIR_NAME: &str = "snapshot_tests/snapshots/render_snapshots"; pub(super) fn frame_to_rgba(frame: &Frame) -> Vec { - let FrameData::PlanarYuv420(YuvPlanes { + match &frame.data { + FrameData::PlanarYuv420(planes) => yuv_frame_to_rgba(frame, planes), + FrameData::PlanarYuvJ420(_) => panic!("unsupported"), + FrameData::InterleavedYuv422(_) => panic!("unsupported"), + FrameData::Rgba8UnormWgpuTexture(texture) => read_rgba_texture(texture).to_vec(), + FrameData::Nv12WgpuTexture(_) => panic!("unsupported"), + } +} + +pub(super) fn yuv_frame_to_rgba(frame: &Frame, planes: &YuvPlanes) -> Vec { + let YuvPlanes { y_plane, u_plane, v_plane, - }) = &frame.data - else { - panic!("Wrong pixel format") - }; + } = planes; // Renderer can sometimes produce resolution that is not dividable by 2 let corrected_width = frame.resolution.width - (frame.resolution.width % 2); @@ -46,11 +57,13 @@ pub(super) fn frame_to_rgba(frame: &Frame) -> Vec { rgba_data } -pub(super) fn create_renderer() -> Renderer { +fn get_wgpu_ctx() -> (Arc, Arc) { static CTX: OnceLock<(Arc, Arc)> = OnceLock::new(); - let wgpu_ctx = - CTX.get_or_init(|| create_wgpu_ctx(false, Default::default(), Default::default()).unwrap()); + CTX.get_or_init(|| create_wgpu_ctx(false, Default::default(), Default::default()).unwrap()) + .clone() +} +pub(super) fn create_renderer() -> Renderer { let (renderer, _event_loop) = Renderer::new(RendererOptions { web_renderer: web_renderer::WebRendererInitOptions { enable: false, @@ -60,9 +73,98 @@ pub(super) fn create_renderer() -> Renderer { framerate: Framerate { num: 30, den: 1 }, stream_fallback_timeout: Duration::from_secs(3), wgpu_features: WgpuFeatures::default(), - wgpu_ctx: Some(wgpu_ctx.clone()), + wgpu_ctx: Some(get_wgpu_ctx()), load_system_fonts: false, }) .unwrap(); renderer } + +fn read_rgba_texture(texture: &wgpu::Texture) -> bytes::Bytes { + let (device, queue) = get_wgpu_ctx(); + let buffer = new_download_buffer(&device, texture); + + let mut encoder = device.create_command_encoder(&Default::default()); + copy_to_buffer(&mut encoder, texture, &buffer); + queue.submit(Some(encoder.finish())); + + download_buffer(&device, texture.size(), &buffer) +} + +fn new_download_buffer(device: &wgpu::Device, texture: &wgpu::Texture) -> wgpu::Buffer { + let size = texture.size(); + let block_size = texture.format().block_copy_size(None).unwrap(); + + device.create_buffer(&wgpu::BufferDescriptor { + label: Some("texture buffer"), + mapped_at_creation: false, + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, + size: (pad_to_256(block_size * size.width) * size.height) as u64, + }) +} + +fn copy_to_buffer( + encoder: &mut wgpu::CommandEncoder, + texture: &wgpu::Texture, + buffer: &wgpu::Buffer, +) { + let size = texture.size(); + let block_size = texture.format().block_copy_size(None).unwrap(); + encoder.copy_texture_to_buffer( + wgpu::ImageCopyTexture { + aspect: wgpu::TextureAspect::All, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + texture, + }, + wgpu::ImageCopyBuffer { + buffer, + layout: wgpu::ImageDataLayout { + bytes_per_row: Some(pad_to_256(size.width * block_size)), + rows_per_image: Some(size.height), + offset: 0, + }, + }, + size, + ); +} + +fn download_buffer( + device: &wgpu::Device, + size: wgpu::Extent3d, + source: &wgpu::Buffer, +) -> bytes::Bytes { + let buffer = bytes::BytesMut::with_capacity((size.width * size.height * 4) as usize); + let (s, r) = bounded(1); + source + .slice(..) + .map_async(wgpu::MapMode::Read, move |result| { + if let Err(err) = s.send(result) { + error!("channel send error: {err}") + } + }); + + device.poll(wgpu::MaintainBase::Wait); + + r.recv().unwrap().unwrap(); + let mut buffer = buffer.writer(); + { + let range = source.slice(..).get_mapped_range(); + let chunks = range.chunks(pad_to_256(size.width * 4) as usize); + for chunk in chunks { + buffer + .write_all(&chunk[..(size.width * 4) as usize]) + .unwrap(); + } + }; + source.unmap(); + buffer.into_inner().into() +} + +fn pad_to_256(value: u32) -> u32 { + if value % 256 == 0 { + value + } else { + value + (256 - (value % 256)) + } +} diff --git a/src/snapshot_tests/yuv_tests.rs b/src/snapshot_tests/yuv_tests.rs new file mode 100644 index 000000000..f877f40e0 --- /dev/null +++ b/src/snapshot_tests/yuv_tests.rs @@ -0,0 +1,125 @@ +use core::panic; +use std::{sync::Arc, time::Duration}; + +use compositor_render::{ + scene::{ + BorderRadius, Component, Overflow, Position, RGBAColor, ShaderComponent, Size, + ViewChildrenDirection, ViewComponent, + }, + shader::ShaderSpec, + OutputFrameFormat, RendererId, RendererSpec, Resolution, +}; + +use super::test_case::TestCase; + +fn run_case(test_case: TestCase, expected: &[u8]) { + let mut renderer = test_case.renderer(); + let snapshot = test_case + .snapshot_for_pts(&mut renderer, Duration::ZERO) + .unwrap(); + let failed = snapshot + .data + .iter() + .zip(expected) + .any(|(actual, expected)| u8::abs_diff(*actual, *expected) > 2); + if failed { + panic!("Sample mismatched {:?}", snapshot.data) + } +} + +/// Test how yuv output is generated for smooth color change +#[test] +fn yuv_test_gradient() { + let shader_id = RendererId(Arc::from("example_shader")); + let width = 8; + let height = 2; + + let yuv_case = TestCase { + scene_updates: vec![Component::Shader(ShaderComponent { + id: None, + children: vec![], + shader_id: shader_id.clone(), + shader_param: None, + size: Size { + width: width as f32, + height: height as f32, + }, + })], + renderers: vec![( + shader_id.clone(), + RendererSpec::Shader(ShaderSpec { + source: include_str!("./yuv_tests/gradient.wgsl").into(), + }), + )], + resolution: Resolution { width, height }, + ..Default::default() + }; + let rgb_case = TestCase { + output_format: OutputFrameFormat::RgbaWgpuTexture, + ..yuv_case.clone() + }; + + #[rustfmt::skip] + run_case( + yuv_case, + &[ + 91, 0, 0, 255, 106, 6, 5, 255, 161, 0, 0, 255, 169, 3, 3, 255, 204, 0, 0, 255, 210, 2, 2, 255, 238, 0, 0, 255, 242, 2, 1, 255, + 91, 0, 0, 255, 106, 6, 5, 255, 161, 0, 0, 255, 169, 3, 3, 255, 204, 0, 0, 255, 210, 2, 2, 255, 238, 0, 0, 255, 242, 2, 1, 255, + ], + ); + #[rustfmt::skip] + run_case(rgb_case, + &[ + 71, 0, 0, 255, 120, 0, 0, 255, 152, 0, 0, 255, 177, 0, 0, 255, 198, 0, 0, 255, 216, 0, 0, 255, 233, 0, 0, 255, 248, 0, 0, 255, + 71, 0, 0, 255, 120, 0, 0, 255, 152, 0, 0, 255, 177, 0, 0, 255, 198, 0, 0, 255, 216, 0, 0, 255, 233, 0, 0, 255, 248, 0, 0, 255, + ], + ); +} + +/// Test how yuv output is generated for unified color +#[test] +fn yuv_test_uniform_color() { + let width = 8; + let height = 2; + + let yuv_case = TestCase { + scene_updates: vec![Component::View(ViewComponent { + id: None, + children: vec![], + direction: ViewChildrenDirection::Row, + position: Position::Static { + width: None, + height: None, + }, + transition: None, + overflow: Overflow::Hidden, + background_color: RGBAColor(50, 0, 0, 255), + border_radius: BorderRadius::ZERO, + border_width: 0.0, + border_color: RGBAColor(0, 0, 0, 0), + box_shadow: vec![], + })], + resolution: Resolution { width, height }, + ..Default::default() + }; + let rgb_case = TestCase { + output_format: OutputFrameFormat::RgbaWgpuTexture, + ..yuv_case.clone() + }; + + #[rustfmt::skip] + run_case( + yuv_case, + &[ + 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, + 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255 + ], + ); + #[rustfmt::skip] + run_case(rgb_case, + &[ + 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, + 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255, 50, 0, 0, 255 + ], + ); +} diff --git a/src/snapshot_tests/yuv_tests/gradient.wgsl b/src/snapshot_tests/yuv_tests/gradient.wgsl new file mode 100644 index 000000000..e3fbcdace --- /dev/null +++ b/src/snapshot_tests/yuv_tests/gradient.wgsl @@ -0,0 +1,37 @@ +struct VertexInput { + @location(0) position: vec3, + @location(1) tex_coords: vec2, +} + +struct VertexOutput { + @builtin(position) position: vec4, + @location(0) tex_coords: vec2, +} + +@vertex +fn vs_main(input: VertexInput) -> VertexOutput { + var output: VertexOutput; + + output.position = vec4(input.position, 1.0); + output.tex_coords = input.tex_coords; + + return output; +} + +struct BaseShaderParameters { + plane_id: i32, + time: f32, + output_resolution: vec2, + texture_count: u32, +} + +@group(0) @binding(0) var textures: binding_array, 16>; +@group(2) @binding(0) var sampler_: sampler; + +var base_params: BaseShaderParameters; + +@fragment +fn fs_main(input: VertexOutput) -> @location(0) vec4 { + return vec4(input.tex_coords.x, 0.0, 0.0, 1.0); +} + From f39dcd506fe09124cf3d4f899bebb7b835d4e411 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Fri, 15 Nov 2024 12:18:32 +0100 Subject: [PATCH 31/51] support trickle ice error handling --- .../src/pipeline/output/whip.rs | 9 +++ .../output/whip/establish_peer_connection.rs | 61 +++++++++++++------ .../output/whip/init_peer_connection.rs | 2 +- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/compositor_pipeline/src/pipeline/output/whip.rs b/compositor_pipeline/src/pipeline/output/whip.rs index e0ef5aab1..e43988a29 100644 --- a/compositor_pipeline/src/pipeline/output/whip.rs +++ b/compositor_pipeline/src/pipeline/output/whip.rs @@ -96,6 +96,15 @@ pub enum WhipError { #[error(transparent)] PayloadingError(#[from] PayloadingError), + + #[error("Trickle ICE not supported")] + TrickleIceNotSupported, + + #[error("Entity Tag missing")] + EntityTagMissing, + + #[error("Entity Tag non-matching")] + EntityTagNonMatching, } const WHIP_INIT_TIMEOUT: Duration = Duration::from_secs(60); diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs index c623d2fc2..3a1ff0414 100644 --- a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -3,8 +3,11 @@ use reqwest::{ header::{HeaderMap, HeaderValue}, Client, Method, StatusCode, Url, }; -use std::sync::Arc; -use tracing::{debug, error, info, warn}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; +use tracing::{debug, error, info}; use webrtc::{ ice_transport::{ice_candidate::RTCIceCandidate, ice_connection_state::RTCIceConnectionState}, peer_connection::{sdp::session_description::RTCSessionDescription, RTCPeerConnection}, @@ -127,17 +130,32 @@ pub async fn connect( .await .map_err(WhipError::RemoteDescriptionError)?; + let should_stop = Arc::new(AtomicBool::new(false)); let location_url_clone = location_url.clone(); peer_connection.on_ice_candidate(Box::new(move |candidate| { let bearer_token = whip_ctx.options.bearer_token.clone(); let client = client.clone(); let location_url = location_url_clone.clone(); + let should_stop_clone = should_stop.clone(); Box::pin(async move { + if should_stop_clone.load(Ordering::Relaxed) { + return; + } if let Some(candidate) = candidate { if let Err(err) = handle_candidate(candidate, bearer_token, client, location_url.clone()).await { - error!("{err}"); + match err { + WhipError::TrickleIceNotSupported => { + info!("Trickle ICE not supported by WHIP server"); + should_stop_clone.store(true, Ordering::Relaxed); + } + WhipError::EntityTagMissing | WhipError::EntityTagNonMatching => { + info!("Entity tags not supported by WHIP output"); + should_stop_clone.store(true, Ordering::Relaxed); + } + _ => error!("{err}"), + } } } }) @@ -166,29 +184,32 @@ async fn handle_candidate( header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); } - let response = match client + let response = client .patch(location.clone()) .headers(header_map) .body(serde_json::to_string(&ice_candidate)?) .send() .await - { - Ok(res) => res, - Err(_) => return Err(WhipError::RequestFailed(Method::PATCH, location.clone())), - }; + .map_err(|_| WhipError::RequestFailed(Method::PATCH, location.clone()))?; - if response.status() >= StatusCode::BAD_REQUEST { - let status = response.status(); - let body_str = response - .text() - .await - .map_err(|e| WhipError::BodyParsingError("Trickle ICE patch", e))?; - if status == StatusCode::UNPROCESSABLE_ENTITY || status == StatusCode::METHOD_NOT_ALLOWED { - warn!("Error while sending Ice Candidate do WHIP Server (Trickle ICE is probably not supported):\nStaus code: {status}\nBody: {body_str}") - } else { - return Err(WhipError::BadStatus(status, body_str)); - } - } + if let Err(err) = &response.error_for_status_ref() { + let status_code = err.status().unwrap(); + let trickle_ice_error = match status_code { + StatusCode::UNPROCESSABLE_ENTITY | StatusCode::METHOD_NOT_ALLOWED => { + WhipError::TrickleIceNotSupported + } + StatusCode::PRECONDITION_REQUIRED => WhipError::EntityTagMissing, + StatusCode::PRECONDITION_FAILED => WhipError::EntityTagNonMatching, + _ => { + let answer = &response + .text() + .await + .map_err(|e| WhipError::BodyParsingError("ICE Candidate", e))?; + WhipError::BadStatus(status_code, answer.to_string()) + } + }; + return Err(trickle_ice_error); + }; Ok(()) } diff --git a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs index 90c6b5b04..2cd9cc2a3 100644 --- a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs @@ -71,7 +71,7 @@ pub async fn init_peer_connection() -> Result< match env::var(STUN_SERVER_ENV) { Ok(var) => { - if var.len() == 0 { + if var.is_empty() { info!("Empty LIVE_COMPOSITOR_STUN_SERVERS environment variable, using default"); } else { let env_url_list: Vec = var.split(',').map(String::from).collect(); From d9e7684e54b93692e178b5cc738e6b626c815d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Kraso=C5=84?= <45288762+BrtqKr@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:42:09 +0100 Subject: [PATCH 32/51] [ts-sdk] Modify view interface (#818) --- .github/workflows/demos_check.yml | 1 + .github/workflows/lint.yml | 1 + .github/workflows/macos_lint.yml | 1 + .github/workflows/shellcheck.yml | 1 + .github/workflows/test.yml | 1 + .github/workflows/ts_sdk_check.yml | 5 +- .github/workflows/wasm.yml | 1 + docs/src/components/ExampleSceneJsx.tsx | 7 +-- .../node-express-zustand/src/App.tsx | 6 +- .../templates/node-minimal/src/index.tsx | 4 +- ts/examples/node-examples/src/audio.tsx | 2 +- .../node-examples/src/dynamic-inputs.tsx | 2 +- .../node-examples/src/dynamic-outputs.tsx | 2 +- .../node-examples/src/dynamic-text.tsx | 2 +- ts/examples/node-examples/src/simple.tsx | 2 +- .../src/examples/MP4Player.tsx | 8 +-- ts/live-compositor/README.md | 4 +- ts/live-compositor/src/components/View.ts | 60 +++++++++++-------- ts/package.json | 2 +- ts/pnpm-lock.yaml | 6 +- 20 files changed, 64 insertions(+), 54 deletions(-) diff --git a/.github/workflows/demos_check.yml b/.github/workflows/demos_check.yml index 5c05d27dc..ab18f9dfb 100644 --- a/.github/workflows/demos_check.yml +++ b/.github/workflows/demos_check.yml @@ -1,6 +1,7 @@ name: demos lint on: + workflow_dispatch: {} push: branches: [master] paths: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6bff07b7a..c886e4242 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,5 +1,6 @@ name: lint on: + workflow_dispatch: {} push: branches: [master] pull_request: diff --git a/.github/workflows/macos_lint.yml b/.github/workflows/macos_lint.yml index 66b034242..59ca596ec 100644 --- a/.github/workflows/macos_lint.yml +++ b/.github/workflows/macos_lint.yml @@ -1,5 +1,6 @@ name: macos lint on: + workflow_dispatch: {} push: branches: [master] pull_request: diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index b30a5cd92..c0d791868 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -1,5 +1,6 @@ name: shellcheck on: + workflow_dispatch: {} push: branches: [master] paths: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 36a91fd60..e3938507a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,6 @@ name: build and test on: + workflow_dispatch: {} push: branches: [master] pull_request: diff --git a/.github/workflows/ts_sdk_check.yml b/.github/workflows/ts_sdk_check.yml index f42397c9b..9b1e0358b 100644 --- a/.github/workflows/ts_sdk_check.yml +++ b/.github/workflows/ts_sdk_check.yml @@ -1,14 +1,11 @@ name: TS SDK check on: + workflow_dispatch: {} push: branches: [master] - paths: - - "ts/**" pull_request: types: [opened, synchronize] - paths: - - "ts/**" concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 844ea4253..791b49e46 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -1,5 +1,6 @@ name: wasm build on: + workflow_dispatch: {} push: branches: [master] pull_request: diff --git a/docs/src/components/ExampleSceneJsx.tsx b/docs/src/components/ExampleSceneJsx.tsx index 1ee85c0d0..9a7d53b2d 100644 --- a/docs/src/components/ExampleSceneJsx.tsx +++ b/docs/src/components/ExampleSceneJsx.tsx @@ -21,17 +21,14 @@ function Example() { - + LiveCompositor ๐Ÿ˜ƒ๐Ÿ˜ + ); } diff --git a/ts/create-live-compositor/templates/node-express-zustand/src/App.tsx b/ts/create-live-compositor/templates/node-express-zustand/src/App.tsx index 18e87dcde..6d463fda6 100644 --- a/ts/create-live-compositor/templates/node-express-zustand/src/App.tsx +++ b/ts/create-live-compositor/templates/node-express-zustand/src/App.tsx @@ -25,16 +25,16 @@ function OutputScene() { function Instructions() { return ( - + Open index.ts and get started. - + This example renders static text and sends the output stream via RTP to local port 8001. Generated code includes helpers in liveCompositorFfplayHelper.ts that display the output stream using ffplay, make sure to remove them for any real production use. - + Where to go next? - ./src/App.tsx defines content of the streams. diff --git a/ts/create-live-compositor/templates/node-minimal/src/index.tsx b/ts/create-live-compositor/templates/node-minimal/src/index.tsx index 92abd2f63..3e5b71a7c 100644 --- a/ts/create-live-compositor/templates/node-minimal/src/index.tsx +++ b/ts/create-live-compositor/templates/node-minimal/src/index.tsx @@ -4,10 +4,10 @@ import { ffplayStartPlayerAsync } from './liveCompositorFfplayHelper'; function App() { return ( - + Open index.ts and get started - + This example renders static text and sends the output stream via RTP to local port 8001. Generated code includes helpers in liveCompositorFfplayHelper.ts that display the output diff --git a/ts/examples/node-examples/src/audio.tsx b/ts/examples/node-examples/src/audio.tsx index 1516b5b55..aa622d677 100644 --- a/ts/examples/node-examples/src/audio.tsx +++ b/ts/examples/node-examples/src/audio.tsx @@ -40,7 +40,7 @@ function InputTile({ inputId, mute }: { inputId: string; mute: boolean }) { - + Input ID: {inputId}, volume: {volume.toFixed(2)} {mute ? 'muted' : 'live'} diff --git a/ts/examples/node-examples/src/dynamic-inputs.tsx b/ts/examples/node-examples/src/dynamic-inputs.tsx index 241bd6f7f..823336f90 100644 --- a/ts/examples/node-examples/src/dynamic-inputs.tsx +++ b/ts/examples/node-examples/src/dynamic-inputs.tsx @@ -32,7 +32,7 @@ function InputTile({ inputId }: { inputId: string }) { - + Input ID: {inputId} diff --git a/ts/examples/node-examples/src/dynamic-outputs.tsx b/ts/examples/node-examples/src/dynamic-outputs.tsx index fb1d7b04e..9982e5418 100644 --- a/ts/examples/node-examples/src/dynamic-outputs.tsx +++ b/ts/examples/node-examples/src/dynamic-outputs.tsx @@ -21,7 +21,7 @@ function InputTile({ inputId }: { inputId: string }) { - + Input ID: {inputId} diff --git a/ts/examples/node-examples/src/dynamic-text.tsx b/ts/examples/node-examples/src/dynamic-text.tsx index 1d93ae4d0..6ae25b12a 100644 --- a/ts/examples/node-examples/src/dynamic-text.tsx +++ b/ts/examples/node-examples/src/dynamic-text.tsx @@ -43,7 +43,7 @@ function PartialText(props: PartialTextProps) { function ExampleApp() { return ( - + diff --git a/ts/examples/node-examples/src/simple.tsx b/ts/examples/node-examples/src/simple.tsx index c2811c84d..a03867e33 100644 --- a/ts/examples/node-examples/src/simple.tsx +++ b/ts/examples/node-examples/src/simple.tsx @@ -27,7 +27,7 @@ function ExampleApp() { }); return ( - + {[...Array(count)].map((_value, index) => ( ))} diff --git a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx index 13c20c0bc..f0e9017d8 100644 --- a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx +++ b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx @@ -32,8 +32,8 @@ function Scene() { if (inputState !== 'playing') { return ( - - + + Loading MP4 file @@ -43,9 +43,9 @@ function Scene() { } return ( - + - + Playing MP4 file diff --git a/ts/live-compositor/README.md b/ts/live-compositor/README.md index 0e5622986..65db3189c 100644 --- a/ts/live-compositor/README.md +++ b/ts/live-compositor/README.md @@ -15,11 +15,11 @@ npm create live-compositor ## Usage ```tsx -import { View, Text, InputStream, Rescaler } from 'live-compositor'; +import { View, Text, InputStream, Rescaler } from "live-compositor"; function ExampleApp() { return ( - + diff --git a/ts/live-compositor/src/components/View.ts b/ts/live-compositor/src/components/View.ts index f54827686..0168795d6 100644 --- a/ts/live-compositor/src/components/View.ts +++ b/ts/live-compositor/src/components/View.ts @@ -4,11 +4,7 @@ import { createCompositorComponent, sceneComponentIntoApi } from '../component.j import type { Transition } from './common.js'; import { intoApiRgbaColor, intoApiTransition } from './common.js'; -export type ViewProps = { - /** - * Id of a component. - */ - id?: Api.ComponentId; +export type ViewStyle = { /** * Width of a component in pixels. Exact behavior might be different based on the parent * component: @@ -57,11 +53,6 @@ export type ViewProps = { * absolutely positioned, instead of being laid out by its parent. */ rotation?: number; - /** - * Defines how this component will behave during a scene update. This will only have an - * effect if the previous scene already contained a `View` component with the same id. - */ - transition?: Transition; /** * (**default=`"hidden"`**) Controls what happens to content that is too big to fit into an area. */ @@ -72,28 +63,47 @@ export type ViewProps = { backgroundColor?: string; }; +export type ViewProps = { + /** + * Id of a component. + */ + id?: Api.ComponentId; + + /** + * Component styling properties. + */ + style?: ViewStyle; + + /** + * Defines how this component will behave during a scene update. This will only have an + * effect if the previous scene already contained a `View` component with the same id. + */ + transition?: Transition; +}; + const View = createCompositorComponent(sceneBuilder); -function sceneBuilder(props: ViewProps, children: SceneComponent[]): Api.Component { +function sceneBuilder( + { id, style = {}, transition }: ViewProps, + children: SceneComponent[] +): Api.Component { return { type: 'view', - + id, children: children.map(sceneComponentIntoApi), + width: style.width, + height: style.height, + direction: style.direction, - id: props.id, - width: props.width, - height: props.height, - direction: props.direction, - - top: props.top, - left: props.left, - bottom: props.bottom, - right: props.right, - rotation: props.rotation, + top: style.top, + right: style.right, + bottom: style.bottom, + left: style.left, - transition: props.transition && intoApiTransition(props.transition), - overflow: props.overflow, - background_color_rgba: props.backgroundColor && intoApiRgbaColor(props.backgroundColor), + rotation: style.rotation, + overflow: style.overflow, + background_color_rgba: style?.backgroundColor && intoApiRgbaColor(style.backgroundColor), + transition: transition && intoApiTransition(transition), }; } diff --git a/ts/package.json b/ts/package.json index f4aeb0e78..00622df23 100644 --- a/ts/package.json +++ b/ts/package.json @@ -9,7 +9,7 @@ "build": "pnpm -r run build", "build:sdk": "pnpm -C @live-compositor/core run build && pnpm -C @live-compositor/node run build && pnpm -C @live-compositor/web-wasm run build && pnpm -C live-compositor run build", "build:all": "pnpm -C @live-compositor/browser-render run build-wasm && pnpm -r run build", - "typecheck": "pnpm -r run typecheck", + "typecheck": "pnpm -r --filter '!@live-compositor/browser-render' run typecheck", "clean": "pnpm -r run clean", "watch": "pnpm -r --parallel --stream run watch", "generate-types": "node ./scripts/generateTypes.mjs" diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index 1b0bd08d7..0dc1faf27 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -3596,7 +3596,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 9.13.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0))(eslint@9.13.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -3609,7 +3609,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0))(eslint@9.13.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -3631,7 +3631,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.13.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0))(eslint@9.13.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 From 3478d18722008a633b27cb016535bbce52804f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Kraso=C5=84?= <45288762+BrtqKr@users.noreply.github.com> Date: Mon, 18 Nov 2024 15:01:49 +0100 Subject: [PATCH 33/51] Rule cleanup (#862) --- ts/eslint.config.js | 1 - ts/examples/vite-browser-render/src/examples/MP4Player.tsx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ts/eslint.config.js b/ts/eslint.config.js index 2a94483a4..95422988a 100644 --- a/ts/eslint.config.js +++ b/ts/eslint.config.js @@ -56,7 +56,6 @@ export default [ '@typescript-eslint/no-floating-promises': ['error'], 'no-constant-condition': [0], 'no-unused-vars': 'off', - '@typescript-eslint/no-floating-promises': 'off', '@typescript-eslint/no-unused-vars': [ 'error', { diff --git a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx index f0e9017d8..6242d98ce 100644 --- a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx +++ b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx @@ -56,7 +56,7 @@ function Scene() { function useCompositor(): [LiveCompositor | undefined, (canvas: HTMLCanvasElement) => void] { const [compositor, setCompositor] = useState(undefined); - const canvasRef = useCallback((canvas: HTMLCanvasElement) => { + const canvasRef = useCallback(async (canvas: HTMLCanvasElement) => { if (!canvas) { return; } @@ -89,7 +89,7 @@ function useCompositor(): [LiveCompositor | undefined, (canvas: HTMLCanvasElemen }); }; - setupCompositor(); + await setupCompositor(); }, []); return [compositor, canvasRef]; From ff150c2717e49aa7b3aade31e9def98c585961b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Kraso=C5=84?= <45288762+BrtqKr@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:26:18 +0100 Subject: [PATCH 34/51] [ts-sdk] Modify text interface, update examples (#867) --- .../node-express-zustand/src/App.tsx | 14 +- .../templates/node-minimal/src/index.tsx | 4 +- ts/examples/node-examples/src/audio.tsx | 2 +- .../node-examples/src/dynamic-inputs.tsx | 7 +- .../node-examples/src/dynamic-outputs.tsx | 3 +- .../node-examples/src/dynamic-text.tsx | 2 +- ts/examples/node-examples/src/simple.tsx | 4 +- .../src/examples/MP4Player.tsx | 8 +- ts/live-compositor/src/component.ts | 4 +- ts/live-compositor/src/components/Text.ts | 58 +- ts/pnpm-lock.yaml | 647 +++++++++--------- 11 files changed, 392 insertions(+), 361 deletions(-) diff --git a/ts/create-live-compositor/templates/node-express-zustand/src/App.tsx b/ts/create-live-compositor/templates/node-express-zustand/src/App.tsx index 6d463fda6..49fb7befb 100644 --- a/ts/create-live-compositor/templates/node-express-zustand/src/App.tsx +++ b/ts/create-live-compositor/templates/node-express-zustand/src/App.tsx @@ -27,26 +27,26 @@ function Instructions() { return ( - Open index.ts and get started. + Open index.ts and get started. - + This example renders static text and sends the output stream via RTP to local port 8001. Generated code includes helpers in liveCompositorFfplayHelper.ts that display the output stream using ffplay, make sure to remove them for any real production use. - Where to go next? - + Where to go next? + - ./src/App.tsx defines content of the streams. - + - ./src/routes.ts controls HTTP API that can be used to interact with this example. - + - ./compositor.tsx exposes LiveCompositor instance that can be used to add/remove new streams/images/shader. - + - ./store.ts implements global store using Zustand, enabling express API and React to share common settings. diff --git a/ts/create-live-compositor/templates/node-minimal/src/index.tsx b/ts/create-live-compositor/templates/node-minimal/src/index.tsx index 3e5b71a7c..61562af6d 100644 --- a/ts/create-live-compositor/templates/node-minimal/src/index.tsx +++ b/ts/create-live-compositor/templates/node-minimal/src/index.tsx @@ -6,9 +6,9 @@ function App() { return ( - Open index.ts and get started + Open index.ts and get started - + This example renders static text and sends the output stream via RTP to local port 8001. Generated code includes helpers in liveCompositorFfplayHelper.ts that display the output stream using ffplay, make sure to remove them for any real production use. diff --git a/ts/examples/node-examples/src/audio.tsx b/ts/examples/node-examples/src/audio.tsx index aa622d677..b1ca61a24 100644 --- a/ts/examples/node-examples/src/audio.tsx +++ b/ts/examples/node-examples/src/audio.tsx @@ -41,7 +41,7 @@ function InputTile({ inputId, mute }: { inputId: string; mute: boolean }) { - + Input ID: {inputId}, volume: {volume.toFixed(2)} {mute ? 'muted' : 'live'} diff --git a/ts/examples/node-examples/src/dynamic-inputs.tsx b/ts/examples/node-examples/src/dynamic-inputs.tsx index 823336f90..11fbf818c 100644 --- a/ts/examples/node-examples/src/dynamic-inputs.tsx +++ b/ts/examples/node-examples/src/dynamic-inputs.tsx @@ -9,13 +9,13 @@ function ExampleApp() { {Object.values(inputs).map(input => !input.videoState ? ( - + Waiting for stream {input.inputId} to connect ) : input.videoState === 'playing' ? ( ) : input.videoState === 'finished' ? ( - + Stream {input.inputId} finished ) : ( @@ -33,7 +33,8 @@ function InputTile({ inputId }: { inputId: string }) { - + Input ID: {inputId} diff --git a/ts/examples/node-examples/src/dynamic-outputs.tsx b/ts/examples/node-examples/src/dynamic-outputs.tsx index 9982e5418..0cb4c34a5 100644 --- a/ts/examples/node-examples/src/dynamic-outputs.tsx +++ b/ts/examples/node-examples/src/dynamic-outputs.tsx @@ -22,7 +22,8 @@ function InputTile({ inputId }: { inputId: string }) { - + Input ID: {inputId} diff --git a/ts/examples/node-examples/src/dynamic-text.tsx b/ts/examples/node-examples/src/dynamic-text.tsx index 6ae25b12a..17dc13d9b 100644 --- a/ts/examples/node-examples/src/dynamic-text.tsx +++ b/ts/examples/node-examples/src/dynamic-text.tsx @@ -36,7 +36,7 @@ function PartialText(props: PartialTextProps) { return ( - {props.text.substring(0, textPart.characters)} + {props.text.substring(0, textPart.characters)} ); } diff --git a/ts/examples/node-examples/src/simple.tsx b/ts/examples/node-examples/src/simple.tsx index a03867e33..d65eca2ac 100644 --- a/ts/examples/node-examples/src/simple.tsx +++ b/ts/examples/node-examples/src/simple.tsx @@ -8,7 +8,7 @@ type PartialTextProps = { }; function SimpleComponent(props: PartialTextProps) { - return {props.text}; + return {props.text}; } function ExampleApp() { @@ -32,7 +32,7 @@ function ExampleApp() { ))} - Text component example (fontSize={30}) + Text component example (fontSize={30}) Raw text example (default fontSize={50}) Counter: {count} diff --git a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx index 6242d98ce..39cddd8d9 100644 --- a/ts/examples/vite-browser-render/src/examples/MP4Player.tsx +++ b/ts/examples/vite-browser-render/src/examples/MP4Player.tsx @@ -34,9 +34,7 @@ function Scene() { return ( - - Loading MP4 file - + Loading MP4 file ); @@ -46,9 +44,7 @@ function Scene() { - - Playing MP4 file - + Playing MP4 file ); diff --git a/ts/live-compositor/src/component.ts b/ts/live-compositor/src/component.ts index 15d9bae3a..ef2b79038 100644 --- a/ts/live-compositor/src/component.ts +++ b/ts/live-compositor/src/component.ts @@ -2,6 +2,8 @@ import type React from 'react'; import { createElement, useId } from 'react'; import type * as Api from './api.js'; +export const DEFAULT_FONT_SIZE = 50; + type ComponentProps

= { children?: React.ReactNode; id?: Api.ComponentId } & P; export type SceneComponent = Api.Component | string; @@ -30,7 +32,7 @@ export function sceneComponentIntoApi(component: SceneComponent): Api.Component return { type: 'text', text: component, - font_size: 50, + font_size: DEFAULT_FONT_SIZE, }; } return component; diff --git a/ts/live-compositor/src/components/Text.ts b/ts/live-compositor/src/components/Text.ts index bd3643288..eb51e9223 100644 --- a/ts/live-compositor/src/components/Text.ts +++ b/ts/live-compositor/src/components/Text.ts @@ -1,15 +1,9 @@ import type * as Api from '../api.js'; import type { SceneComponent } from '../component.js'; -import { createCompositorComponent } from '../component.js'; +import { createCompositorComponent, DEFAULT_FONT_SIZE } from '../component.js'; import { intoApiRgbaColor } from './common.js'; -export type TextProps = { - children?: (string | number)[] | string | number; - - /** - * Id of a component. - */ - id?: Api.ComponentId; +export type TextStyle = { /** * Width of a texture that text will be rendered on. If not provided, the resulting texture * will be sized based on the defined text but limited to `max_width` value. @@ -55,7 +49,7 @@ export type TextProps = { /** * (**default=`"normal"`**) Font style. The selected font needs to support the specified style. */ - style?: Api.TextStyle; + fontStyle?: Api.TextStyle; /** * (**default=`"left"`**) Text align. */ @@ -67,29 +61,45 @@ export type TextProps = { /** * (**default=`"normal"`**) Font weight. The selected font needs to support the specified weight. */ - weight?: Api.TextWeight; + fontWeight?: Api.TextWeight; +}; + +export type TextProps = { + children?: (string | number)[] | string | number; + + /** + * Id of a component. + */ + id?: Api.ComponentId; + + /** + * Text styling properties + */ + style?: TextStyle; }; const Text = createCompositorComponent(sceneBuilder); function sceneBuilder(props: TextProps, children: SceneComponent[]): Api.Component { + const { id, style } = props; + return { type: 'text', - id: props.id, + id: id, text: children.map(child => (typeof child === 'string' ? child : String(child))).join(''), - width: props.width, - height: props.height, - max_width: props.maxWidth, - max_height: props.maxHeight, - font_size: props.fontSize, - line_height: props.lineHeight, - color_rgba: props.color && intoApiRgbaColor(props.color), - background_color_rgba: props.backgroundColor && intoApiRgbaColor(props.backgroundColor), - font_family: props.fontFamily, - style: props.style, - align: props.align, - wrap: props.wrap, - weight: props.weight, + width: style?.width, + height: style?.height, + max_width: style?.maxWidth, + max_height: style?.maxHeight, + font_size: style?.fontSize ?? DEFAULT_FONT_SIZE, + line_height: style?.lineHeight, + color_rgba: style?.color && intoApiRgbaColor(style?.color), + background_color_rgba: style?.backgroundColor && intoApiRgbaColor(style?.backgroundColor), + font_family: style?.fontFamily, + style: style?.fontStyle, + align: style?.align, + wrap: style?.wrap, + weight: style?.fontWeight, }; } diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index 0dc1faf27..1faa9833e 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -10,43 +10,43 @@ importers: devDependencies: '@eslint/plugin-kit': specifier: ^0.2.0 - version: 0.2.2 + version: 0.2.3 '@typescript-eslint/eslint-plugin': specifier: ^8.8.1 - version: 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint@9.13.0)(typescript@5.5.3) + version: 8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint@9.15.0)(typescript@5.5.3) '@typescript-eslint/parser': specifier: ^8.8.1 - version: 8.12.2(eslint@9.13.0)(typescript@5.5.3) + version: 8.14.0(eslint@9.15.0)(typescript@5.5.3) concurrently: specifier: ^9.0.1 - version: 9.0.1 + version: 9.1.0 eslint: specifier: ^9.12.0 - version: 9.13.0 + version: 9.15.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@9.13.0) + version: 9.1.0(eslint@9.15.0) eslint-import-resolver-typescript: specifier: ^3.6.3 - version: 3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0) + version: 3.6.3(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.15.0) eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0) + version: 2.31.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.15.0) eslint-plugin-prettier: specifier: ^5.2.1 - version: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.13.0))(eslint@9.13.0)(prettier@3.3.3) + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.15.0))(eslint@9.15.0)(prettier@3.3.3) eslint-plugin-react-hooks: specifier: ^5.0.0 - version: 5.0.0(eslint@9.13.0) + version: 5.0.0(eslint@9.15.0) eslint-plugin-react-refresh: specifier: ^0.4.9 - version: 0.4.14(eslint@9.13.0) + version: 0.4.14(eslint@9.15.0) globals: specifier: ^15.9.0 - version: 15.11.0 + version: 15.12.0 json-schema-to-typescript: specifier: ^15.0.1 - version: 15.0.2 + version: 15.0.3 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -62,16 +62,16 @@ importers: devDependencies: '@rollup/plugin-typescript': specifier: ^11.1.6 - version: 11.1.6(rollup@4.24.3)(tslib@2.8.0)(typescript@5.5.3) + version: 11.1.6(rollup@4.27.2)(tslib@2.8.1)(typescript@5.5.3) rollup: specifier: ^4.21.2 - version: 4.24.3 + version: 4.27.2 rollup-plugin-copy: specifier: ^3.5.0 version: 3.5.0 rollup-plugin-dts: specifier: ^6.1.1 - version: 6.1.1(rollup@4.24.3)(typescript@5.5.3) + version: 6.1.1(rollup@4.27.2)(typescript@5.5.3) wasm-pack: specifier: ^0.13.0 version: 0.13.1 @@ -121,16 +121,16 @@ importers: version: 11.0.4 '@types/node': specifier: ^20.14.10 - version: 20.17.3 + version: 20.17.6 '@types/node-fetch': specifier: ^2.6.11 - version: 2.6.11 + version: 2.6.12 '@types/uuid': specifier: ^10.0.0 version: 10.0.0 '@types/ws': specifier: ^8.5.12 - version: 8.5.12 + version: 8.5.13 '@live-compositor/web-wasm': dependencies: @@ -148,7 +148,7 @@ importers: version: link:../../live-compositor mp4box: specifier: ^0.5.2 - version: 0.5.2 + version: 0.5.3 path-parser: specifier: ^6.1.0 version: 6.1.0 @@ -199,7 +199,7 @@ importers: version: 4.17.21 '@types/node': specifier: ^20.14.10 - version: 20.17.3 + version: 20.17.6 '@types/react': specifier: ^18.3.3 version: 18.3.12 @@ -218,7 +218,7 @@ importers: devDependencies: '@types/node': specifier: ^20.14.10 - version: 20.17.3 + version: 20.17.6 '@types/react': specifier: ^18.3.3 version: 18.3.12 @@ -245,17 +245,17 @@ importers: version: 18.3.1 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.17.3)(typescript@5.5.3) + version: 10.9.2(@types/node@20.17.6)(typescript@5.5.3) devDependencies: '@types/fs-extra': specifier: ^11.0.4 version: 11.0.4 '@types/node': specifier: ^20.14.10 - version: 20.17.3 + version: 20.17.6 '@types/node-fetch': specifier: ^2.6.11 - version: 2.6.11 + version: 2.6.12 '@types/react': specifier: ^18.3.3 version: 18.3.12 @@ -273,7 +273,7 @@ importers: version: link:../../live-compositor mp4box: specifier: ^0.5.2 - version: 0.5.2 + version: 0.5.3 react: specifier: ^18.3.1 version: 18.3.1 @@ -289,19 +289,19 @@ importers: version: 18.3.1 '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.3(vite@5.4.10(@types/node@20.17.3)) + version: 4.3.3(vite@5.4.11(@types/node@20.17.6)) typescript: specifier: ^5.5.3 version: 5.5.3 typescript-eslint: specifier: ^8.0.1 - version: 8.12.2(eslint@9.13.0)(typescript@5.5.3) + version: 8.14.0(eslint@9.15.0)(typescript@5.5.3) vite: specifier: ^5.4.1 - version: 5.4.10(@types/node@20.17.3) + version: 5.4.11(@types/node@20.17.6) vite-plugin-static-copy: specifier: ^1.0.6 - version: 1.0.6(vite@5.4.10(@types/node@20.17.3)) + version: 1.0.6(vite@5.4.11(@types/node@20.17.6)) live-compositor: dependencies: @@ -557,28 +557,28 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.18.0': - resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + '@eslint/config-array@0.19.0': + resolution: {integrity: sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.7.0': - resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} + '@eslint/core@0.9.0': + resolution: {integrity: sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.1.0': - resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + '@eslint/eslintrc@3.2.0': + resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.13.0': - resolution: {integrity: sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==} + '@eslint/js@9.15.0': + resolution: {integrity: sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.4': resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.2': - resolution: {integrity: sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==} + '@eslint/plugin-kit@0.2.3': + resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@humanfs/core@0.19.1': @@ -597,6 +597,10 @@ packages: resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} engines: {node: '>=18.18'} + '@humanwhocodes/retry@0.4.1': + resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} + engines: {node: '>=18.18'} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -675,93 +679,93 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.24.3': - resolution: {integrity: sha512-ufb2CH2KfBWPJok95frEZZ82LtDl0A6QKTa8MoM+cWwDZvVGl5/jNb79pIhRvAalUu+7LD91VYR0nwRD799HkQ==} + '@rollup/rollup-android-arm-eabi@4.27.2': + resolution: {integrity: sha512-Tj+j7Pyzd15wAdSJswvs5CJzJNV+qqSUcr/aCD+jpQSBtXvGnV0pnrjoc8zFTe9fcKCatkpFpOO7yAzpO998HA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.24.3': - resolution: {integrity: sha512-iAHpft/eQk9vkWIV5t22V77d90CRofgR2006UiCjHcHJFVI1E0oBkQIAbz+pLtthFw3hWEmVB4ilxGyBf48i2Q==} + '@rollup/rollup-android-arm64@4.27.2': + resolution: {integrity: sha512-xsPeJgh2ThBpUqlLgRfiVYBEf/P1nWlWvReG+aBWfNv3XEBpa6ZCmxSVnxJgLgkNz4IbxpLy64h2gCmAAQLneQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.24.3': - resolution: {integrity: sha512-QPW2YmkWLlvqmOa2OwrfqLJqkHm7kJCIMq9kOz40Zo9Ipi40kf9ONG5Sz76zszrmIZZ4hgRIkez69YnTHgEz1w==} + '@rollup/rollup-darwin-arm64@4.27.2': + resolution: {integrity: sha512-KnXU4m9MywuZFedL35Z3PuwiTSn/yqRIhrEA9j+7OSkji39NzVkgxuxTYg5F8ryGysq4iFADaU5osSizMXhU2A==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.24.3': - resolution: {integrity: sha512-KO0pN5x3+uZm1ZXeIfDqwcvnQ9UEGN8JX5ufhmgH5Lz4ujjZMAnxQygZAVGemFWn+ZZC0FQopruV4lqmGMshow==} + '@rollup/rollup-darwin-x64@4.27.2': + resolution: {integrity: sha512-Hj77A3yTvUeCIx/Vi+4d4IbYhyTwtHj07lVzUgpUq9YpJSEiGJj4vXMKwzJ3w5zp5v3PFvpJNgc/J31smZey6g==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.24.3': - resolution: {integrity: sha512-CsC+ZdIiZCZbBI+aRlWpYJMSWvVssPuWqrDy/zi9YfnatKKSLFCe6fjna1grHuo/nVaHG+kiglpRhyBQYRTK4A==} + '@rollup/rollup-freebsd-arm64@4.27.2': + resolution: {integrity: sha512-RjgKf5C3xbn8gxvCm5VgKZ4nn0pRAIe90J0/fdHUsgztd3+Zesb2lm2+r6uX4prV2eUByuxJNdt647/1KPRq5g==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.24.3': - resolution: {integrity: sha512-F0nqiLThcfKvRQhZEzMIXOQG4EeX61im61VYL1jo4eBxv4aZRmpin6crnBJQ/nWnCsjH5F6J3W6Stdm0mBNqBg==} + '@rollup/rollup-freebsd-x64@4.27.2': + resolution: {integrity: sha512-duq21FoXwQtuws+V9H6UZ+eCBc7fxSpMK1GQINKn3fAyd9DFYKPJNcUhdIKOrMFjLEJgQskoMoiuizMt+dl20g==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.24.3': - resolution: {integrity: sha512-KRSFHyE/RdxQ1CSeOIBVIAxStFC/hnBgVcaiCkQaVC+EYDtTe4X7z5tBkFyRoBgUGtB6Xg6t9t2kulnX6wJc6A==} + '@rollup/rollup-linux-arm-gnueabihf@4.27.2': + resolution: {integrity: sha512-6npqOKEPRZkLrMcvyC/32OzJ2srdPzCylJjiTJT2c0bwwSGm7nz2F9mNQ1WrAqCBZROcQn91Fno+khFhVijmFA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.24.3': - resolution: {integrity: sha512-h6Q8MT+e05zP5BxEKz0vi0DhthLdrNEnspdLzkoFqGwnmOzakEHSlXfVyA4HJ322QtFy7biUAVFPvIDEDQa6rw==} + '@rollup/rollup-linux-arm-musleabihf@4.27.2': + resolution: {integrity: sha512-V9Xg6eXtgBtHq2jnuQwM/jr2mwe2EycnopO8cbOvpzFuySCGtKlPCI3Hj9xup/pJK5Q0388qfZZy2DqV2J8ftw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.24.3': - resolution: {integrity: sha512-fKElSyXhXIJ9pqiYRqisfirIo2Z5pTTve5K438URf08fsypXrEkVmShkSfM8GJ1aUyvjakT+fn2W7Czlpd/0FQ==} + '@rollup/rollup-linux-arm64-gnu@4.27.2': + resolution: {integrity: sha512-uCFX9gtZJoQl2xDTpRdseYuNqyKkuMDtH6zSrBTA28yTfKyjN9hQ2B04N5ynR8ILCoSDOrG/Eg+J2TtJ1e/CSA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.24.3': - resolution: {integrity: sha512-YlddZSUk8G0px9/+V9PVilVDC6ydMz7WquxozToozSnfFK6wa6ne1ATUjUvjin09jp34p84milxlY5ikueoenw==} + '@rollup/rollup-linux-arm64-musl@4.27.2': + resolution: {integrity: sha512-/PU9P+7Rkz8JFYDHIi+xzHabOu9qEWR07L5nWLIUsvserrxegZExKCi2jhMZRd0ATdboKylu/K5yAXbp7fYFvA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.24.3': - resolution: {integrity: sha512-yNaWw+GAO8JjVx3s3cMeG5Esz1cKVzz8PkTJSfYzE5u7A+NvGmbVFEHP+BikTIyYWuz0+DX9kaA3pH9Sqxp69g==} + '@rollup/rollup-linux-powerpc64le-gnu@4.27.2': + resolution: {integrity: sha512-eCHmol/dT5odMYi/N0R0HC8V8QE40rEpkyje/ZAXJYNNoSfrObOvG/Mn+s1F/FJyB7co7UQZZf6FuWnN6a7f4g==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.24.3': - resolution: {integrity: sha512-lWKNQfsbpv14ZCtM/HkjCTm4oWTKTfxPmr7iPfp3AHSqyoTz5AgLemYkWLwOBWc+XxBbrU9SCokZP0WlBZM9lA==} + '@rollup/rollup-linux-riscv64-gnu@4.27.2': + resolution: {integrity: sha512-DEP3Njr9/ADDln3kNi76PXonLMSSMiCir0VHXxmGSHxCxDfQ70oWjHcJGfiBugzaqmYdTC7Y+8Int6qbnxPBIQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.24.3': - resolution: {integrity: sha512-HoojGXTC2CgCcq0Woc/dn12wQUlkNyfH0I1ABK4Ni9YXyFQa86Fkt2Q0nqgLfbhkyfQ6003i3qQk9pLh/SpAYw==} + '@rollup/rollup-linux-s390x-gnu@4.27.2': + resolution: {integrity: sha512-NHGo5i6IE/PtEPh5m0yw5OmPMpesFnzMIS/lzvN5vknnC1sXM5Z/id5VgcNPgpD+wHmIcuYYgW+Q53v+9s96lQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.24.3': - resolution: {integrity: sha512-mnEOh4iE4USSccBOtcrjF5nj+5/zm6NcNhbSEfR3Ot0pxBwvEn5QVUXcuOwwPkapDtGZ6pT02xLoPaNv06w7KQ==} + '@rollup/rollup-linux-x64-gnu@4.27.2': + resolution: {integrity: sha512-PaW2DY5Tan+IFvNJGHDmUrORadbe/Ceh8tQxi8cmdQVCCYsLoQo2cuaSj+AU+YRX8M4ivS2vJ9UGaxfuNN7gmg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.24.3': - resolution: {integrity: sha512-rMTzawBPimBQkG9NKpNHvquIUTQPzrnPxPbCY1Xt+mFkW7pshvyIS5kYgcf74goxXOQk0CP3EoOC1zcEezKXhw==} + '@rollup/rollup-linux-x64-musl@4.27.2': + resolution: {integrity: sha512-dOlWEMg2gI91Qx5I/HYqOD6iqlJspxLcS4Zlg3vjk1srE67z5T2Uz91yg/qA8sY0XcwQrFzWWiZhMNERylLrpQ==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.24.3': - resolution: {integrity: sha512-2lg1CE305xNvnH3SyiKwPVsTVLCg4TmNCF1z7PSHX2uZY2VbUpdkgAllVoISD7JO7zu+YynpWNSKAtOrX3AiuA==} + '@rollup/rollup-win32-arm64-msvc@4.27.2': + resolution: {integrity: sha512-euMIv/4x5Y2/ImlbGl88mwKNXDsvzbWUlT7DFky76z2keajCtcbAsN9LUdmk31hAoVmJJYSThgdA0EsPeTr1+w==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.24.3': - resolution: {integrity: sha512-9SjYp1sPyxJsPWuhOCX6F4jUMXGbVVd5obVpoVEi8ClZqo52ViZewA6eFz85y8ezuOA+uJMP5A5zo6Oz4S5rVQ==} + '@rollup/rollup-win32-ia32-msvc@4.27.2': + resolution: {integrity: sha512-RsnE6LQkUHlkC10RKngtHNLxb7scFykEbEwOFDjr3CeCMG+Rr+cKqlkKc2/wJ1u4u990urRHCbjz31x84PBrSQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.24.3': - resolution: {integrity: sha512-HGZgRFFYrMrP3TJlq58nR1xy8zHKId25vhmm5S9jETEfDf6xybPxsavFTJaufe2zgOGYJBskGlj49CwtEuFhWQ==} + '@rollup/rollup-win32-x64-msvc@4.27.2': + resolution: {integrity: sha512-foJM5vv+z2KQmn7emYdDLyTbkoO5bkHZE1oth2tWbQNGW7mX32d46Hz6T0MqXdWS2vBZhaEtHqdy9WYwGfiliA==} cpu: [x64] os: [win32] @@ -837,11 +841,11 @@ packages: '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - '@types/node-fetch@2.6.11': - resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} + '@types/node-fetch@2.6.12': + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} - '@types/node@20.17.3': - resolution: {integrity: sha512-tSQrmKKatLDGnG92h40GD7FzUt0MjahaHwOME4VAFeeA/Xopayq5qLyQRy7Jg/pjgKIFBXuKcGhJo+UdYG55jQ==} + '@types/node@20.17.6': + resolution: {integrity: sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==} '@types/prompts@2.4.9': resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} @@ -849,8 +853,8 @@ packages: '@types/prop-types@15.7.13': resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} - '@types/qs@6.9.16': - resolution: {integrity: sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==} + '@types/qs@6.9.17': + resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} @@ -873,11 +877,11 @@ packages: '@types/uuid@10.0.0': resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} - '@types/ws@8.5.12': - resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} - '@typescript-eslint/eslint-plugin@8.12.2': - resolution: {integrity: sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==} + '@typescript-eslint/eslint-plugin@8.14.0': + resolution: {integrity: sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -887,8 +891,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.12.2': - resolution: {integrity: sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==} + '@typescript-eslint/parser@8.14.0': + resolution: {integrity: sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -897,12 +901,12 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@8.12.2': - resolution: {integrity: sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==} + '@typescript-eslint/scope-manager@8.14.0': + resolution: {integrity: sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.12.2': - resolution: {integrity: sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==} + '@typescript-eslint/type-utils@8.14.0': + resolution: {integrity: sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -910,12 +914,12 @@ packages: typescript: optional: true - '@typescript-eslint/types@8.12.2': - resolution: {integrity: sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==} + '@typescript-eslint/types@8.14.0': + resolution: {integrity: sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.12.2': - resolution: {integrity: sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==} + '@typescript-eslint/typescript-estree@8.14.0': + resolution: {integrity: sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -923,14 +927,14 @@ packages: typescript: optional: true - '@typescript-eslint/utils@8.12.2': - resolution: {integrity: sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==} + '@typescript-eslint/utils@8.14.0': + resolution: {integrity: sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - '@typescript-eslint/visitor-keys@8.12.2': - resolution: {integrity: sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==} + '@typescript-eslint/visitor-keys@8.14.0': + resolution: {integrity: sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@vitejs/plugin-react@4.3.3': @@ -1069,8 +1073,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001675: - resolution: {integrity: sha512-/wV1bQwPrkLiQMjaJF5yUMVM/VdRPOCU8QZ+PmG6uW6DvYSrNY1bpwHI/3mOcUosLaJCzYDi5o91IQB51ft6cg==} + caniuse-lite@1.0.30001680: + resolution: {integrity: sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1109,8 +1113,8 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concurrently@9.0.1: - resolution: {integrity: sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg==} + concurrently@9.1.0: + resolution: {integrity: sha512-VxkzwMAn4LP7WyMnJNbHN5mKV9L2IbyDjpzemKr99sXNR3GqRNMMHdm7prV1ws9wg7ETj6WUkNOigZVsptwbgg==} engines: {node: '>=18'} hasBin: true @@ -1135,8 +1139,8 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} csstype@3.1.3: @@ -1220,8 +1224,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.49: - resolution: {integrity: sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A==} + electron-to-chromium@1.5.62: + resolution: {integrity: sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1241,8 +1245,8 @@ packages: resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} - es-abstract@1.23.3: - resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + es-abstract@1.23.5: + resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==} engines: {node: '>= 0.4'} es-define-property@1.0.0: @@ -1374,8 +1378,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.13.0: - resolution: {integrity: sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==} + eslint@9.15.0: + resolution: {integrity: sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1434,6 +1438,14 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fdir@6.4.2: + resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1558,8 +1570,8 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@15.11.0: - resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} + globals@15.12.0: + resolution: {integrity: sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==} engines: {node: '>=18'} globalthis@1.0.4: @@ -1749,8 +1761,8 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-schema-to-typescript@15.0.2: - resolution: {integrity: sha512-+cRBw+bBJ3k783mZroDIgz1pLNPB4hvj6nnbHTWwEVl0dkW8qdZ+M9jWhBb+Y0FAdHvNsXACga3lewGO8lktrw==} + json-schema-to-typescript@15.0.3: + resolution: {integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==} engines: {node: '>=16.0.0'} hasBin: true @@ -1884,8 +1896,8 @@ packages: engines: {node: '>=10'} hasBin: true - mp4box@0.5.2: - resolution: {integrity: sha512-zRmGlvxy+YdW3Dmt+TR4xPHynbxwXtAQDTN/Fo9N3LMxaUlB2C5KmZpzYyGKy4c7k4Jf3RCR0A2pm9SZELOLXw==} + mp4box@0.5.3: + resolution: {integrity: sha512-RIvyFZdPDIg3+mL6vUdPBSyQRrEfKO3ryAeJ4xJJV7HBHQUH3KfLlZRzfSpBHCd/HqR63HfbrWQI/CwXDvYENQ==} ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -1921,8 +1933,8 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - object-inspect@1.13.2: - resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} engines: {node: '>= 0.4'} object-keys@1.1.1: @@ -2019,8 +2031,8 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - postcss@8.4.47: - resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -2129,8 +2141,8 @@ packages: rollup: ^3.29.4 || ^4 typescript: ^4.5 || ^5.0 - rollup@4.24.3: - resolution: {integrity: sha512-HBW896xR5HGmoksbi3JBDtmVzWiPAYqp7wip50hjQ67JbDz61nyoMPdqu1DvVW9asYb2M65Z20ZHsyJCMqMyDg==} + rollup@4.27.2: + resolution: {integrity: sha512-KreA+PzWmk2yaFmZVwe6GB2uBD86nXl86OsDkt1bJS9p3vqWuEQ6HnJJ+j/mZi/q0920P99/MVRlB4L3crpF5w==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2285,8 +2297,9 @@ packages: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} engines: {node: '>=18'} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + tinyglobby@0.2.10: + resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} + engines: {node: '>=12.0.0'} to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} @@ -2303,8 +2316,8 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + ts-api-utils@1.4.0: + resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' @@ -2329,8 +2342,8 @@ packages: tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.8.0: - resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -2356,8 +2369,8 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - typescript-eslint@8.12.2: - resolution: {integrity: sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==} + typescript-eslint@8.14.0: + resolution: {integrity: sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -2423,8 +2436,8 @@ packages: peerDependencies: vite: ^5.0.0 - vite@5.4.10: - resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} + vite@5.4.11: + resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -2746,14 +2759,14 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.13.0)': + '@eslint-community/eslint-utils@4.4.1(eslint@9.15.0)': dependencies: - eslint: 9.13.0 + eslint: 9.15.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/config-array@0.18.0': + '@eslint/config-array@0.19.0': dependencies: '@eslint/object-schema': 2.1.4 debug: 4.3.7 @@ -2761,9 +2774,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/core@0.7.0': {} + '@eslint/core@0.9.0': {} - '@eslint/eslintrc@3.1.0': + '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 debug: 4.3.7 @@ -2777,11 +2790,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.13.0': {} + '@eslint/js@9.15.0': {} '@eslint/object-schema@2.1.4': {} - '@eslint/plugin-kit@0.2.2': + '@eslint/plugin-kit@0.2.3': dependencies: levn: 0.4.1 @@ -2796,6 +2809,8 @@ snapshots: '@humanwhocodes/retry@0.3.1': {} + '@humanwhocodes/retry@0.4.1': {} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -2852,75 +2867,75 @@ snapshots: '@pkgr/core@0.1.1': {} - '@rollup/plugin-typescript@11.1.6(rollup@4.24.3)(tslib@2.8.0)(typescript@5.5.3)': + '@rollup/plugin-typescript@11.1.6(rollup@4.27.2)(tslib@2.8.1)(typescript@5.5.3)': dependencies: - '@rollup/pluginutils': 5.1.3(rollup@4.24.3) + '@rollup/pluginutils': 5.1.3(rollup@4.27.2) resolve: 1.22.8 typescript: 5.5.3 optionalDependencies: - rollup: 4.24.3 - tslib: 2.8.0 + rollup: 4.27.2 + tslib: 2.8.1 - '@rollup/pluginutils@5.1.3(rollup@4.24.3)': + '@rollup/pluginutils@5.1.3(rollup@4.27.2)': dependencies: '@types/estree': 1.0.6 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: - rollup: 4.24.3 + rollup: 4.27.2 - '@rollup/rollup-android-arm-eabi@4.24.3': + '@rollup/rollup-android-arm-eabi@4.27.2': optional: true - '@rollup/rollup-android-arm64@4.24.3': + '@rollup/rollup-android-arm64@4.27.2': optional: true - '@rollup/rollup-darwin-arm64@4.24.3': + '@rollup/rollup-darwin-arm64@4.27.2': optional: true - '@rollup/rollup-darwin-x64@4.24.3': + '@rollup/rollup-darwin-x64@4.27.2': optional: true - '@rollup/rollup-freebsd-arm64@4.24.3': + '@rollup/rollup-freebsd-arm64@4.27.2': optional: true - '@rollup/rollup-freebsd-x64@4.24.3': + '@rollup/rollup-freebsd-x64@4.27.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.24.3': + '@rollup/rollup-linux-arm-gnueabihf@4.27.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.24.3': + '@rollup/rollup-linux-arm-musleabihf@4.27.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.24.3': + '@rollup/rollup-linux-arm64-gnu@4.27.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.24.3': + '@rollup/rollup-linux-arm64-musl@4.27.2': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.24.3': + '@rollup/rollup-linux-powerpc64le-gnu@4.27.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.24.3': + '@rollup/rollup-linux-riscv64-gnu@4.27.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.24.3': + '@rollup/rollup-linux-s390x-gnu@4.27.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.24.3': + '@rollup/rollup-linux-x64-gnu@4.27.2': optional: true - '@rollup/rollup-linux-x64-musl@4.24.3': + '@rollup/rollup-linux-x64-musl@4.27.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.24.3': + '@rollup/rollup-win32-arm64-msvc@4.27.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.24.3': + '@rollup/rollup-win32-ia32-msvc@4.27.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.24.3': + '@rollup/rollup-win32-x64-msvc@4.27.2': optional: true '@rtsao/scc@1.1.0': {} @@ -2957,18 +2972,18 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 20.17.3 + '@types/node': 20.17.6 '@types/connect@3.4.38': dependencies: - '@types/node': 20.17.3 + '@types/node': 20.17.6 '@types/estree@1.0.6': {} '@types/express-serve-static-core@4.19.6': dependencies: - '@types/node': 20.17.3 - '@types/qs': 6.9.16 + '@types/node': 20.17.6 + '@types/qs': 6.9.17 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -2976,22 +2991,22 @@ snapshots: dependencies: '@types/body-parser': 1.19.5 '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.16 + '@types/qs': 6.9.17 '@types/serve-static': 1.15.7 '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.17.3 + '@types/node': 20.17.6 '@types/fs-extra@8.1.5': dependencies: - '@types/node': 20.17.3 + '@types/node': 20.17.6 '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.17.3 + '@types/node': 20.17.6 '@types/http-errors@2.0.4': {} @@ -3001,7 +3016,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.17.3 + '@types/node': 20.17.6 '@types/lodash@4.17.13': {} @@ -3009,23 +3024,23 @@ snapshots: '@types/minimatch@5.1.2': {} - '@types/node-fetch@2.6.11': + '@types/node-fetch@2.6.12': dependencies: - '@types/node': 20.17.3 + '@types/node': 20.17.6 form-data: 4.0.1 - '@types/node@20.17.3': + '@types/node@20.17.6': dependencies: undici-types: 6.19.8 '@types/prompts@2.4.9': dependencies: - '@types/node': 20.17.3 + '@types/node': 20.17.6 kleur: 3.0.3 '@types/prop-types@15.7.13': {} - '@types/qs@6.9.16': {} + '@types/qs@6.9.17': {} '@types/range-parser@1.2.7': {} @@ -3045,109 +3060,109 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 20.17.3 + '@types/node': 20.17.6 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.17.3 + '@types/node': 20.17.6 '@types/send': 0.17.4 '@types/uuid@10.0.0': {} - '@types/ws@8.5.12': + '@types/ws@8.5.13': dependencies: - '@types/node': 20.17.3 + '@types/node': 20.17.6 - '@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint@9.13.0)(typescript@5.5.3)': + '@typescript-eslint/eslint-plugin@8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint@9.15.0)(typescript@5.5.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.5.3) - '@typescript-eslint/scope-manager': 8.12.2 - '@typescript-eslint/type-utils': 8.12.2(eslint@9.13.0)(typescript@5.5.3) - '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.5.3) - '@typescript-eslint/visitor-keys': 8.12.2 - eslint: 9.13.0 + '@typescript-eslint/parser': 8.14.0(eslint@9.15.0)(typescript@5.5.3) + '@typescript-eslint/scope-manager': 8.14.0 + '@typescript-eslint/type-utils': 8.14.0(eslint@9.15.0)(typescript@5.5.3) + '@typescript-eslint/utils': 8.14.0(eslint@9.15.0)(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 8.14.0 + eslint: 9.15.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.5.3) + ts-api-utils: 1.4.0(typescript@5.5.3) optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3)': + '@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3)': dependencies: - '@typescript-eslint/scope-manager': 8.12.2 - '@typescript-eslint/types': 8.12.2 - '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.5.3) - '@typescript-eslint/visitor-keys': 8.12.2 + '@typescript-eslint/scope-manager': 8.14.0 + '@typescript-eslint/types': 8.14.0 + '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 8.14.0 debug: 4.3.7 - eslint: 9.13.0 + eslint: 9.15.0 optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.12.2': + '@typescript-eslint/scope-manager@8.14.0': dependencies: - '@typescript-eslint/types': 8.12.2 - '@typescript-eslint/visitor-keys': 8.12.2 + '@typescript-eslint/types': 8.14.0 + '@typescript-eslint/visitor-keys': 8.14.0 - '@typescript-eslint/type-utils@8.12.2(eslint@9.13.0)(typescript@5.5.3)': + '@typescript-eslint/type-utils@8.14.0(eslint@9.15.0)(typescript@5.5.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.5.3) - '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.5.3) + '@typescript-eslint/utils': 8.14.0(eslint@9.15.0)(typescript@5.5.3) debug: 4.3.7 - ts-api-utils: 1.3.0(typescript@5.5.3) + ts-api-utils: 1.4.0(typescript@5.5.3) optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - eslint - supports-color - '@typescript-eslint/types@8.12.2': {} + '@typescript-eslint/types@8.14.0': {} - '@typescript-eslint/typescript-estree@8.12.2(typescript@5.5.3)': + '@typescript-eslint/typescript-estree@8.14.0(typescript@5.5.3)': dependencies: - '@typescript-eslint/types': 8.12.2 - '@typescript-eslint/visitor-keys': 8.12.2 + '@typescript-eslint/types': 8.14.0 + '@typescript-eslint/visitor-keys': 8.14.0 debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.5.3) + ts-api-utils: 1.4.0(typescript@5.5.3) optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.12.2(eslint@9.13.0)(typescript@5.5.3)': + '@typescript-eslint/utils@8.14.0(eslint@9.15.0)(typescript@5.5.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0) - '@typescript-eslint/scope-manager': 8.12.2 - '@typescript-eslint/types': 8.12.2 - '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.5.3) - eslint: 9.13.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.15.0) + '@typescript-eslint/scope-manager': 8.14.0 + '@typescript-eslint/types': 8.14.0 + '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.5.3) + eslint: 9.15.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/visitor-keys@8.12.2': + '@typescript-eslint/visitor-keys@8.14.0': dependencies: - '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/types': 8.14.0 eslint-visitor-keys: 3.4.3 - '@vitejs/plugin-react@4.3.3(vite@5.4.10(@types/node@20.17.3))': + '@vitejs/plugin-react@4.3.3(vite@5.4.11(@types/node@20.17.6))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.10(@types/node@20.17.3) + vite: 5.4.11(@types/node@20.17.6) transitivePeerDependencies: - supports-color @@ -3203,7 +3218,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 is-string: 1.0.7 @@ -3214,7 +3229,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 @@ -3223,14 +3238,14 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-shim-unscopables: 1.0.2 array.prototype.flatmap@1.3.2: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-shim-unscopables: 1.0.2 arraybuffer.prototype.slice@1.0.3: @@ -3238,7 +3253,7 @@ snapshots: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-errors: 1.3.0 get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 @@ -3300,8 +3315,8 @@ snapshots: browserslist@4.24.2: dependencies: - caniuse-lite: 1.0.30001675 - electron-to-chromium: 1.5.49 + caniuse-lite: 1.0.30001680 + electron-to-chromium: 1.5.62 node-releases: 2.0.18 update-browserslist-db: 1.1.1(browserslist@4.24.2) @@ -3317,7 +3332,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001675: {} + caniuse-lite@1.0.30001680: {} chalk@4.1.2: dependencies: @@ -3360,7 +3375,7 @@ snapshots: concat-map@0.0.1: {} - concurrently@9.0.1: + concurrently@9.1.0: dependencies: chalk: 4.1.2 lodash: 4.17.21 @@ -3384,7 +3399,7 @@ snapshots: create-require@1.1.1: {} - cross-spawn@7.0.3: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -3456,7 +3471,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.49: {} + electron-to-chromium@1.5.62: {} emoji-regex@8.0.0: {} @@ -3471,7 +3486,7 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.2.1 - es-abstract@1.23.3: + es-abstract@1.23.5: dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 @@ -3504,7 +3519,7 @@ snapshots: is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.13.2 + object-inspect: 1.13.3 object-keys: 1.1.1 object.assign: 4.1.5 regexp.prototype.flags: 1.5.3 @@ -3578,9 +3593,9 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@9.1.0(eslint@9.13.0): + eslint-config-prettier@9.1.0(eslint@9.15.0): dependencies: - eslint: 9.13.0 + eslint: 9.15.0 eslint-import-resolver-node@0.3.9: dependencies: @@ -3590,37 +3605,37 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.15.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7 enhanced-resolve: 5.17.1 - eslint: 9.13.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0))(eslint@9.13.0) + eslint: 9.15.0 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.15.0))(eslint@9.15.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.15.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0))(eslint@9.13.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.15.0))(eslint@9.15.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.5.3) - eslint: 9.13.0 + '@typescript-eslint/parser': 8.14.0(eslint@9.15.0)(typescript@5.5.3) + eslint: 9.15.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.15.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.15.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -3629,9 +3644,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.13.0 + eslint: 9.15.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.13.0))(eslint@9.13.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint-plugin-import@2.31.0)(eslint@9.15.0))(eslint@9.15.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -3643,28 +3658,28 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/parser': 8.14.0(eslint@9.15.0)(typescript@5.5.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.13.0))(eslint@9.13.0)(prettier@3.3.3): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.15.0))(eslint@9.15.0)(prettier@3.3.3): dependencies: - eslint: 9.13.0 + eslint: 9.15.0 prettier: 3.3.3 prettier-linter-helpers: 1.0.0 synckit: 0.9.2 optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@9.13.0) + eslint-config-prettier: 9.1.0(eslint@9.15.0) - eslint-plugin-react-hooks@5.0.0(eslint@9.13.0): + eslint-plugin-react-hooks@5.0.0(eslint@9.15.0): dependencies: - eslint: 9.13.0 + eslint: 9.15.0 - eslint-plugin-react-refresh@0.4.14(eslint@9.13.0): + eslint-plugin-react-refresh@0.4.14(eslint@9.15.0): dependencies: - eslint: 9.13.0 + eslint: 9.15.0 eslint-scope@8.2.0: dependencies: @@ -3675,23 +3690,23 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.13.0: + eslint@9.15.0: dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.15.0) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.18.0 - '@eslint/core': 0.7.0 - '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.13.0 - '@eslint/plugin-kit': 0.2.2 + '@eslint/config-array': 0.19.0 + '@eslint/core': 0.9.0 + '@eslint/eslintrc': 3.2.0 + '@eslint/js': 9.15.0 + '@eslint/plugin-kit': 0.2.3 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.3.1 + '@humanwhocodes/retry': 0.4.1 '@types/estree': 1.0.6 '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 debug: 4.3.7 escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 @@ -3711,7 +3726,6 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - text-table: 0.2.0 transitivePeerDependencies: - supports-color @@ -3793,6 +3807,10 @@ snapshots: dependencies: reusify: 1.0.4 + fdir@6.4.2(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -3833,7 +3851,7 @@ snapshots: foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 form-data@4.0.1: @@ -3873,7 +3891,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 functions-have-names: 1.2.3 functions-have-names@1.2.3: {} @@ -3930,7 +3948,7 @@ snapshots: globals@14.0.0: {} - globals@15.11.0: {} + globals@15.12.0: {} globalthis@1.0.4: dependencies: @@ -4111,17 +4129,17 @@ snapshots: json-buffer@3.0.1: {} - json-schema-to-typescript@15.0.2: + json-schema-to-typescript@15.0.3: dependencies: '@apidevtools/json-schema-ref-parser': 11.7.2 '@types/json-schema': 7.0.15 '@types/lodash': 4.17.13 - glob: 10.4.5 is-glob: 4.0.3 js-yaml: 4.1.0 lodash: 4.17.21 minimist: 1.2.8 prettier: 3.3.3 + tinyglobby: 0.2.10 json-schema-traverse@0.4.1: {} @@ -4231,7 +4249,7 @@ snapshots: mkdirp@3.0.1: {} - mp4box@0.5.2: {} + mp4box@0.5.3: {} ms@2.0.0: {} @@ -4251,7 +4269,7 @@ snapshots: normalize-path@3.0.0: {} - object-inspect@1.13.2: {} + object-inspect@1.13.3: {} object-keys@1.1.1: {} @@ -4266,14 +4284,14 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-object-atoms: 1.0.0 object.groupby@1.0.3: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 object.values@1.2.0: dependencies: @@ -4344,7 +4362,7 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss@8.4.47: + postcss@8.4.49: dependencies: nanoid: 3.3.7 picocolors: 1.1.1 @@ -4444,36 +4462,36 @@ snapshots: globby: 10.0.1 is-plain-object: 3.0.1 - rollup-plugin-dts@6.1.1(rollup@4.24.3)(typescript@5.5.3): + rollup-plugin-dts@6.1.1(rollup@4.27.2)(typescript@5.5.3): dependencies: magic-string: 0.30.12 - rollup: 4.24.3 + rollup: 4.27.2 typescript: 5.5.3 optionalDependencies: '@babel/code-frame': 7.26.2 - rollup@4.24.3: + rollup@4.27.2: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.24.3 - '@rollup/rollup-android-arm64': 4.24.3 - '@rollup/rollup-darwin-arm64': 4.24.3 - '@rollup/rollup-darwin-x64': 4.24.3 - '@rollup/rollup-freebsd-arm64': 4.24.3 - '@rollup/rollup-freebsd-x64': 4.24.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.24.3 - '@rollup/rollup-linux-arm-musleabihf': 4.24.3 - '@rollup/rollup-linux-arm64-gnu': 4.24.3 - '@rollup/rollup-linux-arm64-musl': 4.24.3 - '@rollup/rollup-linux-powerpc64le-gnu': 4.24.3 - '@rollup/rollup-linux-riscv64-gnu': 4.24.3 - '@rollup/rollup-linux-s390x-gnu': 4.24.3 - '@rollup/rollup-linux-x64-gnu': 4.24.3 - '@rollup/rollup-linux-x64-musl': 4.24.3 - '@rollup/rollup-win32-arm64-msvc': 4.24.3 - '@rollup/rollup-win32-ia32-msvc': 4.24.3 - '@rollup/rollup-win32-x64-msvc': 4.24.3 + '@rollup/rollup-android-arm-eabi': 4.27.2 + '@rollup/rollup-android-arm64': 4.27.2 + '@rollup/rollup-darwin-arm64': 4.27.2 + '@rollup/rollup-darwin-x64': 4.27.2 + '@rollup/rollup-freebsd-arm64': 4.27.2 + '@rollup/rollup-freebsd-x64': 4.27.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.27.2 + '@rollup/rollup-linux-arm-musleabihf': 4.27.2 + '@rollup/rollup-linux-arm64-gnu': 4.27.2 + '@rollup/rollup-linux-arm64-musl': 4.27.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.27.2 + '@rollup/rollup-linux-riscv64-gnu': 4.27.2 + '@rollup/rollup-linux-s390x-gnu': 4.27.2 + '@rollup/rollup-linux-x64-gnu': 4.27.2 + '@rollup/rollup-linux-x64-musl': 4.27.2 + '@rollup/rollup-win32-arm64-msvc': 4.27.2 + '@rollup/rollup-win32-ia32-msvc': 4.27.2 + '@rollup/rollup-win32-x64-msvc': 4.27.2 fsevents: 2.3.3 run-parallel@1.2.0: @@ -4482,7 +4500,7 @@ snapshots: rxjs@7.8.1: dependencies: - tslib: 2.8.0 + tslib: 2.8.1 safe-array-concat@1.1.2: dependencies: @@ -4569,7 +4587,7 @@ snapshots: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - object-inspect: 1.13.2 + object-inspect: 1.13.3 signal-exit@4.1.0: {} @@ -4597,7 +4615,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-object-atoms: 1.0.0 string.prototype.trimend@1.0.8: @@ -4637,7 +4655,7 @@ snapshots: synckit@0.9.2: dependencies: '@pkgr/core': 0.1.1 - tslib: 2.8.0 + tslib: 2.8.1 tapable@2.2.1: {} @@ -4659,7 +4677,10 @@ snapshots: mkdirp: 3.0.1 yallist: 5.0.0 - text-table@0.2.0: {} + tinyglobby@0.2.10: + dependencies: + fdir: 6.4.2(picomatch@4.0.2) + picomatch: 4.0.2 to-regex-range@5.0.1: dependencies: @@ -4671,18 +4692,18 @@ snapshots: tree-kill@1.2.2: {} - ts-api-utils@1.3.0(typescript@5.5.3): + ts-api-utils@1.4.0(typescript@5.5.3): dependencies: typescript: 5.5.3 - ts-node@10.9.2(@types/node@20.17.3)(typescript@5.5.3): + ts-node@10.9.2(@types/node@20.17.6)(typescript@5.5.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.3 + '@types/node': 20.17.6 acorn: 8.14.0 acorn-walk: 8.3.4 arg: 4.1.3 @@ -4702,7 +4723,7 @@ snapshots: tslib@1.14.1: {} - tslib@2.8.0: {} + tslib@2.8.1: {} type-check@0.4.0: dependencies: @@ -4745,11 +4766,11 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - typescript-eslint@8.12.2(eslint@9.13.0)(typescript@5.5.3): + typescript-eslint@8.14.0(eslint@9.15.0)(typescript@5.5.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.5.3))(eslint@9.13.0)(typescript@5.5.3) - '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.5.3) - '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.5.3) + '@typescript-eslint/eslint-plugin': 8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.5.3))(eslint@9.15.0)(typescript@5.5.3) + '@typescript-eslint/parser': 8.14.0(eslint@9.15.0)(typescript@5.5.3) + '@typescript-eslint/utils': 8.14.0(eslint@9.15.0)(typescript@5.5.3) optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: @@ -4795,21 +4816,21 @@ snapshots: vary@1.1.2: {} - vite-plugin-static-copy@1.0.6(vite@5.4.10(@types/node@20.17.3)): + vite-plugin-static-copy@1.0.6(vite@5.4.11(@types/node@20.17.6)): dependencies: chokidar: 3.6.0 fast-glob: 3.3.2 fs-extra: 11.2.0 picocolors: 1.1.1 - vite: 5.4.10(@types/node@20.17.3) + vite: 5.4.11(@types/node@20.17.6) - vite@5.4.10(@types/node@20.17.3): + vite@5.4.11(@types/node@20.17.6): dependencies: esbuild: 0.21.5 - postcss: 8.4.47 - rollup: 4.24.3 + postcss: 8.4.49 + rollup: 4.27.2 optionalDependencies: - '@types/node': 20.17.3 + '@types/node': 20.17.6 fsevents: 2.3.3 wasm-pack@0.13.1: From 3eb9e41d18b9eaa1d0be077add70a769be657d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Kraso=C5=84?= <45288762+BrtqKr@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:45:11 +0100 Subject: [PATCH 35/51] [ts-sdk] Modify remaining interfaces (#868) --- ts/examples/node-examples/src/audio.tsx | 10 ++-- ts/live-compositor/README.md | 6 +-- .../src/components/InputStream.ts | 8 +-- ts/live-compositor/src/components/Rescaler.ts | 53 +++++++++++-------- ts/live-compositor/src/components/Tiles.ts | 42 +++++++++------ ts/live-compositor/src/hooks.ts | 2 +- 6 files changed, 71 insertions(+), 50 deletions(-) diff --git a/ts/examples/node-examples/src/audio.tsx b/ts/examples/node-examples/src/audio.tsx index b1ca61a24..8234739aa 100644 --- a/ts/examples/node-examples/src/audio.tsx +++ b/ts/examples/node-examples/src/audio.tsx @@ -15,13 +15,13 @@ function ExampleApp() { return ( - - + + ); } -function InputTile({ inputId, mute }: { inputId: string; mute: boolean }) { +function InputTile({ inputId, muted }: { inputId: string; muted: boolean }) { const [volume, setVolume] = useState(1.0); useEffect(() => { @@ -38,11 +38,11 @@ function InputTile({ inputId, mute }: { inputId: string; mute: boolean }) { return ( - + - Input ID: {inputId}, volume: {volume.toFixed(2)} {mute ? 'muted' : 'live'} + Input ID: {inputId}, volume: {volume.toFixed(2)} {muted ? 'muted' : 'live'} diff --git a/ts/live-compositor/README.md b/ts/live-compositor/README.md index 65db3189c..237dc9cf9 100644 --- a/ts/live-compositor/README.md +++ b/ts/live-compositor/README.md @@ -15,12 +15,12 @@ npm create live-compositor ## Usage ```tsx -import { View, Text, InputStream, Rescaler } from "live-compositor"; +import { View, Text, InputStream, Rescaler } from 'live-compositor'; function ExampleApp() { return ( - - + + Example label diff --git a/ts/live-compositor/src/components/InputStream.ts b/ts/live-compositor/src/components/InputStream.ts index 59074cd0c..833b6c0ef 100644 --- a/ts/live-compositor/src/components/InputStream.ts +++ b/ts/live-compositor/src/components/InputStream.ts @@ -22,18 +22,18 @@ export type InputStreamProps = { /** * Mute audio. */ - mute?: boolean; + muted?: boolean; }; -type AudioPropNames = 'mute' | 'volume' | 'disableAudioControl'; +type AudioPropNames = 'muted' | 'volume' | 'disableAudioControl'; const InnerInputStream = createCompositorComponent>(sceneBuilder); function InputStream(props: InputStreamProps) { - const { mute, volume, ...otherProps } = props; + const { muted, volume, ...otherProps } = props; useAudioInput(props.inputId, { - volume: mute ? 0 : (volume ?? 1), + volume: muted ? 0 : (volume ?? 1), }); return createElement(InnerInputStream, otherProps); } diff --git a/ts/live-compositor/src/components/Rescaler.ts b/ts/live-compositor/src/components/Rescaler.ts index c80278ced..d749d15a9 100644 --- a/ts/live-compositor/src/components/Rescaler.ts +++ b/ts/live-compositor/src/components/Rescaler.ts @@ -5,17 +5,11 @@ import { intoApiTransition } from './common.js'; import type { SceneComponent } from '../component.js'; import { createCompositorComponent, sceneComponentIntoApi } from '../component.js'; -export type RescalerProps = { - children: React.ReactElement | string | number; - - /** - * Id of a component. - */ - id?: Api.ComponentId; +export type RescalerStyle = { /** * (**default=`"fit"`**) Resize mode: */ - mode?: Api.RescaleMode; + resizeMode?: Api.RescaleMode; /** * (**default=`"center"`**) Horizontal alignment. */ @@ -68,6 +62,19 @@ export type RescalerProps = { * absolutely positioned, instead of being laid out by its parent. */ rotation?: number; +}; + +export type RescalerProps = { + children: React.ReactElement | string | number; + + /** + * Id of a component. + */ + id?: Api.ComponentId; + /** + * Rescaler styling properties + */ + style?: RescalerStyle; /** * Defines how this component will behave during a scene update. This will only have an * effect if the previous scene already contained a `Rescaler` component with the same id. @@ -77,25 +84,29 @@ export type RescalerProps = { const Rescaler = createCompositorComponent(sceneBuilder); -function sceneBuilder(props: RescalerProps, children: SceneComponent[]): Api.Component { +function sceneBuilder( + { id, style, transition }: RescalerProps, + children: SceneComponent[] +): Api.Component { if (children?.length !== 1) { throw new Error('Exactly one child is required for Rescaler component'); } + return { type: 'rescaler', - id: props.id, + id: id, child: sceneComponentIntoApi(children[0]), - mode: props.mode, - horizontal_align: props.horizontalAlign, - vertical_align: props.verticalAlign, - width: props.width, - height: props.height, - top: props.top, - bottom: props.bottom, - left: props.left, - right: props.right, - rotation: props.rotation, - transition: props.transition && intoApiTransition(props.transition), + mode: style?.resizeMode, + horizontal_align: style?.horizontalAlign, + vertical_align: style?.verticalAlign, + width: style?.width, + height: style?.height, + top: style?.top, + bottom: style?.bottom, + left: style?.left, + right: style?.right, + rotation: style?.rotation, + transition: transition && intoApiTransition(transition), }; } diff --git a/ts/live-compositor/src/components/Tiles.ts b/ts/live-compositor/src/components/Tiles.ts index 927f9866e..de098c4ea 100644 --- a/ts/live-compositor/src/components/Tiles.ts +++ b/ts/live-compositor/src/components/Tiles.ts @@ -4,11 +4,7 @@ import { intoApiRgbaColor, intoApiTransition } from './common.js'; import type { SceneComponent } from '../component.js'; import { createCompositorComponent, sceneComponentIntoApi } from '../component.js'; -export type TilesProps = { - /** - * Id of a component. - */ - id?: Api.ComponentId; +export type TilesStyle = { /** * Width of a component in pixels. Exact behavior might be different based on the parent * component: @@ -49,6 +45,17 @@ export type TilesProps = { * (**default=`"center"`**) Vertical alignment of tiles. */ verticalAlign?: Api.VerticalAlign; +}; + +export type TilesProps = { + /** + * Id of a component. + */ + id?: Api.ComponentId; + /** + * Tiles styling properties + */ + style?: TilesStyle; /** * Defines how this component will behave during a scene update. This will only have an * effect if the previous scene already contained a `Tiles` component with the same id. @@ -58,20 +65,23 @@ export type TilesProps = { const Tiles = createCompositorComponent(sceneBuilder); -function sceneBuilder(props: TilesProps, children: SceneComponent[]): Api.Component { +function sceneBuilder( + { id, style, transition }: TilesProps, + children: SceneComponent[] +): Api.Component { return { type: 'tiles', - id: props.id, + id: id, children: children.map(sceneComponentIntoApi), - width: props.width, - height: props.height, - background_color_rgba: props.backgroundColor && intoApiRgbaColor(props.backgroundColor), - tile_aspect_ratio: props.tileAspectRatio, - margin: props.margin, - padding: props.padding, - horizontal_align: props.horizontalAlign, - vertical_align: props.verticalAlign, - transition: props.transition && intoApiTransition(props.transition), + width: style?.width, + height: style?.height, + background_color_rgba: style?.backgroundColor && intoApiRgbaColor(style?.backgroundColor), + tile_aspect_ratio: style?.tileAspectRatio, + margin: style?.margin, + padding: style?.padding, + horizontal_align: style?.horizontalAlign, + vertical_align: style?.verticalAlign, + transition: transition && intoApiTransition(transition), }; } diff --git a/ts/live-compositor/src/hooks.ts b/ts/live-compositor/src/hooks.ts index 828e90329..49bff0df5 100644 --- a/ts/live-compositor/src/hooks.ts +++ b/ts/live-compositor/src/hooks.ts @@ -19,7 +19,7 @@ export type AudioOptions = { /** * Hook used to control audio configuration. If you already placing InputStream component - * you can use `mute` and `volume` props instead. + * you can use `muted` and `volume` props instead. */ export function useAudioInput(inputId: Api.InputId, audioOptions: AudioOptions) { const ctx = useContext(LiveCompositorContext); From 78ea273ba314e912ab7c0f111a289c8943c0b3d7 Mon Sep 17 00:00:00 2001 From: Wojciech Kozyra Date: Tue, 19 Nov 2024 13:18:48 +0100 Subject: [PATCH 36/51] [ts-sdk] Fix WASM types generation (#870) --- .github/workflows/ts_sdk_check.yml | 5 +++++ compositor_web/Cargo.toml | 2 +- ts/package.json | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ts_sdk_check.yml b/.github/workflows/ts_sdk_check.yml index 9b1e0358b..ee47a9e26 100644 --- a/.github/workflows/ts_sdk_check.yml +++ b/.github/workflows/ts_sdk_check.yml @@ -19,6 +19,11 @@ jobs: - name: Checkout repo uses: actions/checkout@v2 + - name: ๐Ÿ”ง Install the rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81.0 + - name: Install pnpm uses: pnpm/action-setup@v4 with: diff --git a/compositor_web/Cargo.toml b/compositor_web/Cargo.toml index 1ae49f2f9..88b41e0ff 100644 --- a/compositor_web/Cargo.toml +++ b/compositor_web/Cargo.toml @@ -17,7 +17,7 @@ tracing-subscriber = "0.2.19" log = { workspace = true } wasm-log = "0.3.1" js-sys = "0.3.69" -wasm-bindgen = "0.2.92" +wasm-bindgen = "0.2.95" wasm-bindgen-futures = "0.4.42" web-sys = { version = "0.3.69", features = [ "Document", diff --git a/ts/package.json b/ts/package.json index 00622df23..f4aeb0e78 100644 --- a/ts/package.json +++ b/ts/package.json @@ -9,7 +9,7 @@ "build": "pnpm -r run build", "build:sdk": "pnpm -C @live-compositor/core run build && pnpm -C @live-compositor/node run build && pnpm -C @live-compositor/web-wasm run build && pnpm -C live-compositor run build", "build:all": "pnpm -C @live-compositor/browser-render run build-wasm && pnpm -r run build", - "typecheck": "pnpm -r --filter '!@live-compositor/browser-render' run typecheck", + "typecheck": "pnpm -r run typecheck", "clean": "pnpm -r run clean", "watch": "pnpm -r --parallel --stream run watch", "generate-types": "node ./scripts/generateTypes.mjs" From 8de27b42714ad68f3ca148e2ec37976c0b7a6e1c Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Wed, 20 Nov 2024 13:19:59 +0100 Subject: [PATCH 37/51] fixes --- compositor_pipeline/src/error.rs | 6 ++--- compositor_pipeline/src/pipeline/output.rs | 5 ++-- .../src/pipeline/output/whip.rs | 7 ++++-- .../output/whip/establish_peer_connection.rs | 25 ++++++++++++++++--- .../output/whip/init_peer_connection.rs | 22 ++++++++++------ 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/compositor_pipeline/src/error.rs b/compositor_pipeline/src/error.rs index 3a5c8d992..3f8d95c7a 100644 --- a/compositor_pipeline/src/error.rs +++ b/compositor_pipeline/src/error.rs @@ -94,14 +94,14 @@ pub enum OutputInitError { #[error("Failed to register output. FFmpeg error: {0}.")] FfmpegMp4Error(ffmpeg_next::Error), - #[error("Unkown Whip output error, channel unexpectedly closed")] + #[error("Unkown Whip output error.")] UnknownWhipError, #[error("Whip init timeout exceeded")] WhipInitTimeout, - #[error("Failed to init whip output: {0}")] - WhipInitError(Box), + #[error("Failed to init whip output")] + WhipInitError(#[source] Box), } #[derive(Debug, thiserror::Error)] diff --git a/compositor_pipeline/src/pipeline/output.rs b/compositor_pipeline/src/pipeline/output.rs index 2e97d3514..423870c85 100644 --- a/compositor_pipeline/src/pipeline/output.rs +++ b/compositor_pipeline/src/pipeline/output.rs @@ -230,14 +230,15 @@ impl Output { Output::RawData { .. } => return Err(RequestKeyframeError::RawOutput(output_id)), }; - if let Err(err) = encoder + if encoder .video .as_ref() .ok_or(RequestKeyframeError::NoVideoOutput(output_id))? .keyframe_request_sender() .send(()) + .is_err() { - debug!(%err, "Failed to send keyframe request to the encoder."); + debug!("Failed to send keyframe request to the encoder. Channel closed."); }; Ok(()) diff --git a/compositor_pipeline/src/pipeline/output/whip.rs b/compositor_pipeline/src/pipeline/output/whip.rs index e43988a29..98d3e07f1 100644 --- a/compositor_pipeline/src/pipeline/output/whip.rs +++ b/compositor_pipeline/src/pipeline/output/whip.rs @@ -40,6 +40,7 @@ pub struct WhipSenderOptions { pub audio: Option, } +#[derive(Debug, Clone)] pub struct WhipCtx { options: WhipSenderOptions, output_id: OutputId, @@ -196,7 +197,7 @@ async fn run_whip_sender_task( }; let output_id_clone = whip_ctx.output_id.clone(); let should_close_clone = whip_ctx.should_close.clone(); - let whip_session_url = match connect(peer_connection, client.clone(), whip_ctx).await { + let whip_session_url = match connect(peer_connection, client.clone(), &whip_ctx).await { Ok(val) => val, Err(err) => { init_confirmation_sender.send(Err(err)).unwrap(); @@ -240,7 +241,9 @@ async fn run_whip_sender_task( }, } } - let _ = client.delete(whip_session_url).send().await; + if let Err(err) = client.delete(whip_session_url).send().await { + error!("Error while sending delete whip session request: {}", err); + } event_emitter.emit(Event::OutputDone(output_id_clone)); debug!("Closing WHIP sender thread.") } diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs index 3a1ff0414..f5597892b 100644 --- a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -1,4 +1,5 @@ use super::{WhipCtx, WhipError}; +use compositor_render::error::ErrorStack; use reqwest::{ header::{HeaderMap, HeaderValue}, Client, Method, StatusCode, Url, @@ -17,8 +18,9 @@ use webrtc::{ pub async fn connect( peer_connection: Arc, client: Arc, - whip_ctx: WhipCtx, + whip_ctx: &WhipCtx, ) -> Result { + let whip_ctx = whip_ctx.clone(); peer_connection.on_ice_connection_state_change(Box::new( move |connection_state: RTCIceConnectionState| { debug!("Connection State has changed {connection_state}."); @@ -74,7 +76,14 @@ pub async fn connect( header_map.append("Content-Type", HeaderValue::from_static("application/sdp")); if let Some(token) = &whip_ctx.options.bearer_token { - header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); + let header_value_str: HeaderValue = match format!("Bearer {token}").parse() { + Ok(val) => val, + Err(err) => { + error!("Ivalid header token, couldn't parse: {}", err); + HeaderValue::from_static("Bearer") + } + }; + header_map.append("Authorization", header_value_str); } let response = client @@ -99,6 +108,7 @@ pub async fn connect( .get("location") .and_then(|url| url.to_str().ok()) .ok_or_else(|| WhipError::MissingLocationHeader)?; + error!("location header: {location_url_path}"); let scheme = endpoint_url.scheme(); let host = endpoint_url @@ -154,7 +164,7 @@ pub async fn connect( info!("Entity tags not supported by WHIP output"); should_stop_clone.store(true, Ordering::Relaxed); } - _ => error!("{err}"), + _ => error!("{}", ErrorStack::new(&err).into_string()), } } } @@ -181,7 +191,14 @@ async fn handle_candidate( ); if let Some(token) = bearer_token { - header_map.append("Authorization", format!("Bearer {token}").parse().unwrap()); + let header_value_str: HeaderValue = match format!("Bearer {token}").parse() { + Ok(val) => val, + Err(err) => { + error!("Ivalid header token, couldn't parse: {}", err); + HeaderValue::from_static("Bearer") + } + }; + header_map.append("Authorization", header_value_str); } let response = client diff --git a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs index 2cd9cc2a3..e4e979550 100644 --- a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs @@ -30,9 +30,9 @@ pub async fn init_peer_connection() -> Result< ), WhipError, > { - let mut m = MediaEngine::default(); - m.register_default_codecs()?; - m.register_codec( + let mut media_engine = MediaEngine::default(); + media_engine.register_default_codecs()?; + media_engine.register_codec( RTCRtpCodecParameters { capability: RTCRtpCodecCapability { mime_type: MIME_TYPE_H264.to_owned(), @@ -46,7 +46,7 @@ pub async fn init_peer_connection() -> Result< }, RTPCodecType::Video, )?; - m.register_codec( + media_engine.register_codec( RTCRtpCodecParameters { capability: RTCRtpCodecCapability { mime_type: MIME_TYPE_OPUS.to_owned(), @@ -61,9 +61,9 @@ pub async fn init_peer_connection() -> Result< RTPCodecType::Audio, )?; let mut registry = Registry::new(); - registry = register_default_interceptors(registry, &mut m)?; + registry = register_default_interceptors(registry, &mut media_engine)?; let api = APIBuilder::new() - .with_media_engine(m) + .with_media_engine(media_engine) .with_interceptor_registry(registry) .build(); @@ -109,8 +109,14 @@ pub async fn init_peer_connection() -> Result< "audio".to_owned(), "webrtc-rs".to_owned(), )); - let _ = peer_connection.add_track(video_track.clone()).await; - let _ = peer_connection.add_track(audio_track.clone()).await; + peer_connection + .add_track(video_track.clone()) + .await + .map_err(WhipError::PeerConnectionInitError)?; + peer_connection + .add_track(audio_track.clone()) + .await + .map_err(WhipError::PeerConnectionInitError)?; let transceivers = peer_connection.get_transceivers().await; for transceiver in transceivers { transceiver From bc5675c821801ca0257172111bbf51eb45df43e9 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Wed, 20 Nov 2024 17:07:10 +0100 Subject: [PATCH 38/51] handle variable url --- .../output/whip/establish_peer_connection.rs | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs index f5597892b..9b074bac0 100644 --- a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -2,13 +2,14 @@ use super::{WhipCtx, WhipError}; use compositor_render::error::ErrorStack; use reqwest::{ header::{HeaderMap, HeaderValue}, - Client, Method, StatusCode, Url, + Client, Method, StatusCode, }; use std::sync::{ atomic::{AtomicBool, Ordering}, Arc, }; use tracing::{debug, error, info}; +use url::{ParseError, Url}; use webrtc::{ ice_transport::{ice_candidate::RTCIceCandidate, ice_connection_state::RTCIceConnectionState}, peer_connection::{sdp::session_description::RTCSessionDescription, RTCPeerConnection}, @@ -103,24 +104,32 @@ pub async fn connect( return Err(WhipError::BadStatus(status, answer.to_string())); }; - let location_url_path = response + let location_url_str = response .headers() .get("location") .and_then(|url| url.to_str().ok()) .ok_or_else(|| WhipError::MissingLocationHeader)?; - error!("location header: {location_url_path}"); - - let scheme = endpoint_url.scheme(); - let host = endpoint_url - .host_str() - .ok_or_else(|| WhipError::MissingHost)?; let port = endpoint_url.port().ok_or_else(|| WhipError::MissingPort)?; - - let formatted_url = format!("{}://{}:{}{}", scheme, host, port, location_url_path); - - let location_url = Url::try_from(formatted_url.as_str()) - .map_err(|e| WhipError::InvalidEndpointUrl(e, formatted_url))?; + let location_url = match Url::parse(location_url_str) { + Ok(url) => Ok(url), + Err(err) => match err { + ParseError::RelativeUrlWithoutBase => { + let scheme = endpoint_url.scheme(); + let host = endpoint_url + .host_str() + .ok_or_else(|| WhipError::MissingHost)?; + let formatted_url = format!("{}://{}:{}{}", scheme, host, port, location_url_str); + let location_url = Url::try_from(formatted_url.as_str()) + .map_err(|e| WhipError::InvalidEndpointUrl(e, formatted_url))?; + Ok(location_url) + } + _ => Err(WhipError::InvalidEndpointUrl( + err, + location_url_str.to_string(), + )), + }, + }?; peer_connection .set_local_description(offer) From e432cca5bef265e1b8c13739a145177e7e8992fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:19:02 +0100 Subject: [PATCH 39/51] Bump cross-spawn from 7.0.3 to 7.0.6 in /demos (#872) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- demos/pnpm-lock.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/demos/pnpm-lock.yaml b/demos/pnpm-lock.yaml index 9978fb598..dce458260 100644 --- a/demos/pnpm-lock.yaml +++ b/demos/pnpm-lock.yaml @@ -501,8 +501,8 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} csstype@3.1.3: @@ -2122,7 +2122,7 @@ snapshots: create-require@1.1.1: {} - cross-spawn@7.0.3: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -2326,7 +2326,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 9.12.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@9.12.0))(eslint@9.12.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -2339,7 +2339,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@9.12.0))(eslint@9.12.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -2361,7 +2361,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.12.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.12.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.9.0(eslint@9.12.0)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@9.12.0))(eslint@9.12.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -2417,7 +2417,7 @@ snapshots: '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 debug: 4.3.7 escape-string-regexp: 4.0.0 eslint-scope: 8.1.0 @@ -2539,7 +2539,7 @@ snapshots: foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 form-data@4.0.1: From 061287d87cc819b718a14be05cc74274ef8cd6f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:19:31 +0100 Subject: [PATCH 40/51] Bump @eslint/plugin-kit from 0.2.0 to 0.2.3 in /demos (#863) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- demos/pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demos/pnpm-lock.yaml b/demos/pnpm-lock.yaml index dce458260..056629cca 100644 --- a/demos/pnpm-lock.yaml +++ b/demos/pnpm-lock.yaml @@ -125,8 +125,8 @@ packages: resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.0': - resolution: {integrity: sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==} + '@eslint/plugin-kit@0.2.3': + resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@humanfs/core@0.19.0': @@ -1670,7 +1670,7 @@ snapshots: '@eslint/object-schema@2.1.4': {} - '@eslint/plugin-kit@0.2.0': + '@eslint/plugin-kit@0.2.3': dependencies: levn: 0.4.1 @@ -2409,7 +2409,7 @@ snapshots: '@eslint/core': 0.6.0 '@eslint/eslintrc': 3.1.0 '@eslint/js': 9.12.0 - '@eslint/plugin-kit': 0.2.0 + '@eslint/plugin-kit': 0.2.3 '@humanfs/node': 0.16.5 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.3.1 From cc42a9f7b96a6866769783d459e36c218392e432 Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:13:25 +0100 Subject: [PATCH 41/51] New architecture for vk-video initialization. (#857) --- Cargo.lock | 924 +++++++++++++++++- compositor_pipeline/src/pipeline.rs | 3 +- .../pipeline/decoder/video/vulkan_video.rs | 10 +- .../src/pipeline/graphics_context.rs | 55 +- compositor_render/src/lib.rs | 2 +- compositor_render/src/wgpu.rs | 2 +- compositor_render/src/wgpu/ctx.rs | 23 +- .../manual_graphics_initialization.rs | 27 +- .../examples/raw_channel_input.rs | 2 +- .../examples/raw_channel_output.rs | 2 +- integration_tests/examples/vulkan.rs | 4 +- src/snapshot_tests/utils.rs | 23 +- vk-video/Cargo.toml | 3 + vk-video/examples/basic.rs | 14 +- vk-video/examples/player/main.rs | 14 + vk-video/examples/player/player.rs | 64 ++ vk-video/examples/player/player/decoder.rs | 43 + vk-video/examples/player/player/renderer.rs | 353 +++++++ vk-video/examples/player/player/shader.wgsl | 37 + vk-video/examples/wgpu.rs | 18 +- vk-video/src/lib.rs | 28 +- vk-video/src/vulkan_decoder.rs | 58 +- .../src/vulkan_decoder/session_resources.rs | 8 +- .../session_resources/images.rs | 6 +- .../session_resources/parameters.rs | 4 +- vk-video/src/vulkan_decoder/vulkan_ctx.rs | 319 +++--- vk-video/src/vulkan_decoder/wrappers/video.rs | 4 +- 27 files changed, 1777 insertions(+), 273 deletions(-) create mode 100644 vk-video/examples/player/main.rs create mode 100644 vk-video/examples/player/player.rs create mode 100644 vk-video/examples/player/player/decoder.rs create mode 100644 vk-video/examples/player/player/renderer.rs create mode 100644 vk-video/examples/player/player/shader.wgsl diff --git a/Cargo.lock b/Cargo.lock index 6838ec633..07a98612b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,22 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ab_glyph" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + [[package]] name = "addr2line" version = "0.20.0" @@ -24,6 +40,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -44,6 +61,33 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "android-activity" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +dependencies = [ + "android-properties", + "bitflags 2.6.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -68,6 +112,55 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + [[package]] name = "anyhow" version = "1.0.72" @@ -95,6 +188,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + [[package]] name = "ascii" version = "1.1.0" @@ -324,6 +423,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys", + "objc2", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -362,6 +480,32 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "calloop" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +dependencies = [ + "bitflags 2.6.0", + "log", + "polling", + "rustix", + "slab", + "thiserror", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", +] + [[package]] name = "cc" version = "1.1.10" @@ -372,6 +516,12 @@ dependencies = [ "libc", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.6.0" @@ -439,6 +589,46 @@ dependencies = [ "libloading 0.7.4", ] +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "cmake" version = "0.1.50" @@ -464,6 +654,22 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "compositor_api" version = "0.1.0" @@ -566,6 +772,15 @@ dependencies = [ "wgpu", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -592,6 +807,19 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + [[package]] name = "core-graphics-types" version = "0.1.3" @@ -703,6 +931,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + [[package]] name = "cxx" version = "1.0.126" @@ -791,6 +1025,21 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.0", +] + [[package]] name = "document-features" version = "0.2.10" @@ -800,6 +1049,12 @@ dependencies = [ "litrs", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dyn-clone" version = "1.0.14" @@ -1163,6 +1418,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.1", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -1305,7 +1570,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.0.1", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -1349,12 +1614,30 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex-slice" version = "0.1.4" @@ -1510,6 +1793,17 @@ dependencies = [ "cc", ] +[[package]] +name = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2", + "dispatch", + "objc2", +] + [[package]] name = "idna" version = "0.4.0" @@ -1558,12 +1852,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad227c3af19d4914570ad36d30409928b75967c298feb9ea1969db3a610bb14e" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.15.0", ] [[package]] @@ -1606,6 +1900,12 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.12.1" @@ -1621,6 +1921,22 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -1730,6 +2046,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.5.7", +] + [[package]] name = "link-cplusplus" version = "1.0.9" @@ -1992,7 +2319,7 @@ dependencies = [ "cfg_aliases 0.1.1", "codespan-reporting", "hexf-parse", - "indexmap 2.0.1", + "indexmap 2.6.0", "log", "rustc-hash 1.1.0", "spirv", @@ -2056,6 +2383,27 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + [[package]] name = "ndk-sys" version = "0.5.0+25.2.9519653" @@ -2169,10 +2517,31 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.2", "libc", ] +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.75", +] + [[package]] name = "objc" version = "0.2.7" @@ -2182,6 +2551,28 @@ dependencies = [ "malloc_buf", ] +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + [[package]] name = "object" version = "0.31.1" @@ -2251,6 +2642,15 @@ dependencies = [ "libc", ] +[[package]] +name = "orbclient" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +dependencies = [ + "libredox", +] + [[package]] name = "overload" version = "0.1.1" @@ -2258,8 +2658,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -name = "parking_lot" -version = "0.12.1" +name = "owned_ttf_parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +dependencies = [ + "ttf-parser 0.25.0", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ @@ -2275,7 +2684,7 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", "windows-targets 0.48.1", ] @@ -2364,6 +2773,21 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "3.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "pollster" version = "0.3.0" @@ -2401,6 +2825,15 @@ dependencies = [ "num-integer", ] +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -2425,6 +2858,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "quick-xml" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.36" @@ -2544,6 +2986,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "regex" version = "1.10.6" @@ -2651,7 +3102,7 @@ dependencies = [ "png", "rgb", "svgtypes", - "tiny-skia", + "tiny-skia 0.10.0", "usvg", ] @@ -2874,6 +3325,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.22" @@ -2906,6 +3366,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -2918,6 +3384,19 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" +[[package]] +name = "sctk-adwaita" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" +dependencies = [ + "ab_glyph", + "log", + "memmap2 0.9.4", + "smithay-client-toolkit", + "tiny-skia 0.11.4", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -2995,7 +3474,7 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ - "indexmap 2.0.1", + "indexmap 2.6.0", "itoa", "ryu", "serde", @@ -3149,6 +3628,40 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smithay-client-toolkit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" +dependencies = [ + "bitflags 2.6.0", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2 0.9.4", + "rustix", + "thiserror", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + [[package]] name = "socket2" version = "0.5.7" @@ -3198,6 +3711,12 @@ dependencies = [ "float-cmp", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -3306,7 +3825,7 @@ checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", "windows-sys 0.48.0", ] @@ -3373,7 +3892,21 @@ dependencies = [ "cfg-if", "log", "png", - "tiny-skia-path", + "tiny-skia-path 0.10.0", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path 0.11.4", ] [[package]] @@ -3387,6 +3920,17 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tiny_http" version = "0.12.0" @@ -3491,6 +4035,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.6.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -3678,6 +4239,12 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" +[[package]] +name = "ttf-parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" + [[package]] name = "tungstenite" version = "0.21.0" @@ -3871,7 +4438,7 @@ dependencies = [ "rctree", "strict-num", "svgtypes", - "tiny-skia-path", + "tiny-skia-path 0.10.0", ] [[package]] @@ -3880,6 +4447,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "valuable" version = "0.1.0" @@ -3914,8 +4487,10 @@ name = "vk-video" version = "0.1.0" dependencies = [ "ash", + "bytemuck", "bytes", "cfg_aliases 0.2.1", + "clap", "derivative", "h264-reader", "thiserror", @@ -3923,6 +4498,17 @@ dependencies = [ "tracing-subscriber 0.3.18", "vk-mem", "wgpu", + "winit", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", ] [[package]] @@ -4018,6 +4604,115 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wayland-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +dependencies = [ + "bitflags 2.6.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.6.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" +dependencies = [ + "rustix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.72" @@ -4028,6 +4723,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webrtc-util" version = "0.8.1" @@ -4090,7 +4795,7 @@ dependencies = [ "bitflags 2.6.0", "cfg_aliases 0.1.1", "document-features", - "indexmap 2.0.1", + "indexmap 2.6.0", "log", "naga", "once_cell", @@ -4324,6 +5029,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -4342,6 +5056,30 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.1" @@ -4373,6 +5111,12 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" @@ -4391,6 +5135,12 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.0" @@ -4409,6 +5159,12 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.0" @@ -4433,6 +5189,12 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.0" @@ -4451,6 +5213,12 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.0" @@ -4463,6 +5231,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" @@ -4481,6 +5255,12 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.0" @@ -4493,6 +5273,120 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winit" +version = "0.29.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.6.0", + "bytemuck", + "calloop", + "cfg_aliases 0.1.1", + "core-foundation", + "core-graphics", + "cursor-icon", + "icrate", + "js-sys", + "libc", + "log", + "memmap2 0.9.4", + "ndk", + "ndk-sys", + "objc2", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.5", + "rustix", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.48.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading 0.8.0", + "once_cell", + "rustix", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + +[[package]] +name = "xcursor" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.6.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + [[package]] name = "xml-rs" version = "0.8.21" diff --git a/compositor_pipeline/src/pipeline.rs b/compositor_pipeline/src/pipeline.rs index 465f4b641..cbadbd247 100644 --- a/compositor_pipeline/src/pipeline.rs +++ b/compositor_pipeline/src/pipeline.rs @@ -133,7 +133,7 @@ pub struct PipelineCtx { pub download_dir: Arc, pub event_emitter: Arc, #[cfg(feature = "vk-video")] - pub vulkan_ctx: Option>, + pub vulkan_ctx: Option, } impl std::fmt::Debug for PipelineCtx { @@ -156,6 +156,7 @@ impl Pipeline { opts.force_gpu, opts.wgpu_features, Default::default(), + None, )?), #[cfg(not(feature = "vk-video"))] None => None, diff --git a/compositor_pipeline/src/pipeline/decoder/video/vulkan_video.rs b/compositor_pipeline/src/pipeline/decoder/video/vulkan_video.rs index 149723124..10340e777 100644 --- a/compositor_pipeline/src/pipeline/decoder/video/vulkan_video.rs +++ b/compositor_pipeline/src/pipeline/decoder/video/vulkan_video.rs @@ -3,7 +3,7 @@ use std::{sync::Arc, time::Duration}; use compositor_render::{Frame, FrameData, InputId, Resolution}; use crossbeam_channel::{Receiver, Sender}; use tracing::{debug, error, span, trace, warn, Level}; -use vk_video::{VulkanCtx, WgpuTexturesDeocder}; +use vk_video::VulkanDevice; use crate::{ error::InputInitError, @@ -17,7 +17,7 @@ pub fn start_vulkan_video_decoder_thread( frame_sender: Sender>, input_id: InputId, ) -> Result<(), InputInitError> { - let Some(vulkan_ctx) = pipeline_ctx.vulkan_ctx.as_ref().map(|ctx| ctx.clone()) else { + let Some(vulkan_ctx) = pipeline_ctx.vulkan_ctx.clone() else { return Err(InputInitError::VulkanContextRequiredForVulkanDecoder); }; @@ -33,7 +33,7 @@ pub fn start_vulkan_video_decoder_thread( ) .entered(); run_decoder_thread( - vulkan_ctx, + vulkan_ctx.device, init_result_sender, chunks_receiver, frame_sender, @@ -47,12 +47,12 @@ pub fn start_vulkan_video_decoder_thread( } fn run_decoder_thread( - vulkan_ctx: Arc, + vulkan_device: Arc, init_result_sender: Sender>, chunks_receiver: Receiver>, frame_sender: Sender>, ) { - let mut decoder = match WgpuTexturesDeocder::new(vulkan_ctx) { + let mut decoder = match vulkan_device.create_wgpu_textures_decoder() { Ok(decoder) => { init_result_sender.send(Ok(())).unwrap(); decoder diff --git a/compositor_pipeline/src/pipeline/graphics_context.rs b/compositor_pipeline/src/pipeline/graphics_context.rs index d0bc15d0c..ea30eb26f 100644 --- a/compositor_pipeline/src/pipeline/graphics_context.rs +++ b/compositor_pipeline/src/pipeline/graphics_context.rs @@ -1,14 +1,23 @@ use crate::error::InitPipelineError; -use compositor_render::{create_wgpu_ctx, error::InitRendererEngineError}; +use compositor_render::{create_wgpu_ctx, error::InitRendererEngineError, WgpuComponents}; use std::sync::Arc; +#[cfg(feature = "vk-video")] +#[derive(Debug, Clone)] +pub struct VulkanCtx { + pub device: Arc, + pub instance: Arc, +} + #[derive(Debug)] pub struct GraphicsContext { pub device: Arc, pub queue: Arc, + pub adapter: Arc, + pub instance: Arc, #[cfg(feature = "vk-video")] - pub vulkan_ctx: Option>, + pub vulkan_ctx: Option, } impl GraphicsContext { @@ -17,6 +26,7 @@ impl GraphicsContext { force_gpu: bool, features: wgpu::Features, limits: wgpu::Limits, + mut compatible_surface: Option<&mut wgpu::Surface<'_>>, ) -> Result { use compositor_render::{required_wgpu_features, set_required_wgpu_limits}; use tracing::warn; @@ -26,22 +36,36 @@ impl GraphicsContext { let limits = set_required_wgpu_limits(limits); - match vk_video::VulkanCtx::new(vulkan_features, limits.clone()) { - Ok(ctx) => Ok(GraphicsContext { - device: ctx.wgpu_ctx.device.clone(), - queue: ctx.wgpu_ctx.queue.clone(), - vulkan_ctx: Some(ctx.into()), + match vk_video::VulkanInstance::new().and_then(|instance| { + let device = + instance.create_device(vulkan_features, limits.clone(), &mut compatible_surface)?; + + Ok((instance, device)) + }) { + Ok((instance, device)) => Ok(GraphicsContext { + device: device.wgpu_device.clone(), + queue: device.wgpu_queue.clone(), + adapter: device.wgpu_adapter.clone(), + instance: instance.wgpu_instance.clone(), + vulkan_ctx: Some(VulkanCtx { instance, device }), }), Err(err) => { warn!("Cannot initialize vulkan video decoding context. Reason: {err}. Initializing without vulkan video support."); - let (device, queue) = create_wgpu_ctx(force_gpu, features, limits) + let WgpuComponents { + instance, + adapter, + device, + queue, + } = create_wgpu_ctx(force_gpu, features, limits, compatible_surface.as_deref()) .map_err(InitRendererEngineError::FailedToInitWgpuCtx)?; Ok(GraphicsContext { device, queue, + adapter, + instance, vulkan_ctx: None, }) } @@ -53,10 +77,21 @@ impl GraphicsContext { force_gpu: bool, features: wgpu::Features, limits: wgpu::Limits, + compatible_surface: Option<&mut wgpu::Surface<'_>>, ) -> Result { - let (device, queue) = create_wgpu_ctx(force_gpu, features, limits) + let WgpuComponents { + instance, + adapter, + device, + queue, + } = create_wgpu_ctx(force_gpu, features, limits, compatible_surface.as_deref()) .map_err(InitRendererEngineError::FailedToInitWgpuCtx)?; - Ok(GraphicsContext { device, queue }) + Ok(GraphicsContext { + device, + queue, + adapter, + instance, + }) } } diff --git a/compositor_render/src/lib.rs b/compositor_render/src/lib.rs index 5d598473f..3e3a4e3ea 100644 --- a/compositor_render/src/lib.rs +++ b/compositor_render/src/lib.rs @@ -20,7 +20,7 @@ pub use state::RendererOptions; pub use state::RendererSpec; pub use wgpu::WgpuFeatures; -pub use wgpu::{create_wgpu_ctx, required_wgpu_features, set_required_wgpu_limits}; +pub use wgpu::{create_wgpu_ctx, required_wgpu_features, set_required_wgpu_limits, WgpuComponents}; pub mod image { pub use crate::transformations::image_renderer::{ImageSource, ImageSpec, ImageType}; diff --git a/compositor_render/src/wgpu.rs b/compositor_render/src/wgpu.rs index ff9921a65..e3e7196da 100644 --- a/compositor_render/src/wgpu.rs +++ b/compositor_render/src/wgpu.rs @@ -7,7 +7,7 @@ pub(crate) mod texture; pub(crate) mod utils; pub(crate) use ctx::WgpuCtx; -pub use ctx::{create_wgpu_ctx, required_wgpu_features, set_required_wgpu_limits}; +pub use ctx::{create_wgpu_ctx, required_wgpu_features, set_required_wgpu_limits, WgpuComponents}; pub use wgpu::Features as WgpuFeatures; #[must_use] diff --git a/compositor_render/src/wgpu/ctx.rs b/compositor_render/src/wgpu/ctx.rs index 4bf23706f..96aab0f06 100644 --- a/compositor_render/src/wgpu/ctx.rs +++ b/compositor_render/src/wgpu/ctx.rs @@ -34,7 +34,8 @@ impl WgpuCtx { Self::new_from_device_queue(device, queue)? } None => { - let (device, queue) = create_wgpu_ctx(force_gpu, features, Default::default())?; + let WgpuComponents { device, queue, .. } = + create_wgpu_ctx(force_gpu, features, Default::default(), None)?; Self::new_from_device_queue(device, queue)? } }; @@ -101,11 +102,20 @@ pub fn set_required_wgpu_limits(limits: wgpu::Limits) -> wgpu::Limits { } } +#[derive(Clone)] +pub struct WgpuComponents { + pub device: Arc, + pub queue: Arc, + pub adapter: Arc, + pub instance: Arc, +} + pub fn create_wgpu_ctx( force_gpu: bool, features: wgpu::Features, limits: wgpu::Limits, -) -> Result<(Arc, Arc), CreateWgpuCtxError> { + compatible_surface: Option<&wgpu::Surface<'_>>, +) -> Result { let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { backends: wgpu::Backends::all(), ..Default::default() @@ -117,7 +127,7 @@ pub fn create_wgpu_ctx( let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptionsBase { power_preference: wgpu::PowerPreference::HighPerformance, force_fallback_adapter: false, - compatible_surface: None, + compatible_surface, })) .ok_or(CreateWgpuCtxError::NoAdapter)?; @@ -148,7 +158,12 @@ pub fn create_wgpu_ctx( }, None, ))?; - Ok((device.into(), queue.into())) + Ok(WgpuComponents { + instance: instance.into(), + adapter: adapter.into(), + device: device.into(), + queue: queue.into(), + }) } fn uniform_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { diff --git a/integration_tests/examples/manual_graphics_initialization.rs b/integration_tests/examples/manual_graphics_initialization.rs index 236edd7f9..2ae7e096f 100644 --- a/integration_tests/examples/manual_graphics_initialization.rs +++ b/integration_tests/examples/manual_graphics_initialization.rs @@ -9,27 +9,18 @@ fn main() { }; use live_compositor::config::read_config; - let graphics_context = - GraphicsContext::new(false, wgpu::Features::default(), wgpu::Limits::default()).unwrap(); + let graphics_context = GraphicsContext::new( + false, + wgpu::Features::default(), + wgpu::Limits::default(), + None, + ) + .unwrap(); let _device = graphics_context.device.clone(); let _queue = graphics_context.queue.clone(); - - let _adapter = graphics_context - .vulkan_ctx - .as_ref() - .unwrap() - .wgpu_ctx - .adapter - .clone(); - - let _instance = graphics_context - .vulkan_ctx - .as_ref() - .unwrap() - .wgpu_ctx - .instance - .clone(); + let _adapter = graphics_context.adapter.clone(); + let _instance = graphics_context.instance.clone(); let config = read_config(); diff --git a/integration_tests/examples/raw_channel_input.rs b/integration_tests/examples/raw_channel_input.rs index 06fb7d50e..90b0ec577 100644 --- a/integration_tests/examples/raw_channel_input.rs +++ b/integration_tests/examples/raw_channel_input.rs @@ -40,7 +40,7 @@ fn main() { ffmpeg_next::format::network::init(); let config = read_config(); logger::init_logger(config.logger); - let ctx = GraphicsContext::new(false, Default::default(), Default::default()).unwrap(); + let ctx = GraphicsContext::new(false, Default::default(), Default::default(), None).unwrap(); let (wgpu_device, wgpu_queue) = (ctx.device.clone(), ctx.queue.clone()); // no chromium support, so we can ignore _event_loop let (pipeline, _event_loop) = Pipeline::new(Options { diff --git a/integration_tests/examples/raw_channel_output.rs b/integration_tests/examples/raw_channel_output.rs index 4f7143a47..3b21da594 100644 --- a/integration_tests/examples/raw_channel_output.rs +++ b/integration_tests/examples/raw_channel_output.rs @@ -53,7 +53,7 @@ fn main() { logger::init_logger(read_config().logger); let mut config = read_config(); config.queue_options.ahead_of_time_processing = true; - let ctx = GraphicsContext::new(false, Default::default(), Default::default()).unwrap(); + let ctx = GraphicsContext::new(false, Default::default(), Default::default(), None).unwrap(); let (wgpu_device, wgpu_queue) = (ctx.device.clone(), ctx.queue.clone()); // no chromium support, so we can ignore _event_loop let (pipeline, _event_loop) = Pipeline::new(Options { diff --git a/integration_tests/examples/vulkan.rs b/integration_tests/examples/vulkan.rs index dc7fd4e7f..46e8e14e7 100644 --- a/integration_tests/examples/vulkan.rs +++ b/integration_tests/examples/vulkan.rs @@ -73,7 +73,7 @@ fn client_code() -> Result<()> { const INPUT_PORT: u16 = 8006; const OUTPUT_PORT: u16 = 8004; - const VIDEOS: u16 = 1; + const VIDEOS: u16 = 6; start_ffmpeg_receive(Some(OUTPUT_PORT), None)?; let config = read_config(); @@ -176,7 +176,7 @@ fn client_code() -> Result<()> { Pipeline::start(&pipeline); for i in 0..VIDEOS { - start_ffmpeg_send(IP, Some(INPUT_PORT + 2 * i), None, TestSample::Sample)?; + start_ffmpeg_send(IP, Some(INPUT_PORT + 2 * i), None, TestSample::BigBuckBunny)?; } let event_loop_fallback = || { diff --git a/src/snapshot_tests/utils.rs b/src/snapshot_tests/utils.rs index 6de77f988..a9ff71455 100644 --- a/src/snapshot_tests/utils.rs +++ b/src/snapshot_tests/utils.rs @@ -1,14 +1,10 @@ use core::panic; -use std::{ - io::Write, - sync::{Arc, OnceLock}, - time::Duration, -}; +use std::{io::Write, sync::OnceLock, time::Duration}; use bytes::BufMut; use compositor_render::{ create_wgpu_ctx, web_renderer, Frame, FrameData, Framerate, Renderer, RendererOptions, - WgpuFeatures, YuvPlanes, + WgpuComponents, WgpuFeatures, YuvPlanes, }; use crossbeam_channel::bounded; use tracing::error; @@ -57,13 +53,16 @@ pub(super) fn yuv_frame_to_rgba(frame: &Frame, planes: &YuvPlanes) -> Vec { rgba_data } -fn get_wgpu_ctx() -> (Arc, Arc) { - static CTX: OnceLock<(Arc, Arc)> = OnceLock::new(); - CTX.get_or_init(|| create_wgpu_ctx(false, Default::default(), Default::default()).unwrap()) - .clone() +fn get_wgpu_ctx() -> WgpuComponents { + static CTX: OnceLock = OnceLock::new(); + CTX.get_or_init(|| { + create_wgpu_ctx(false, Default::default(), Default::default(), None).unwrap() + }) + .clone() } pub(super) fn create_renderer() -> Renderer { + let wgpu_ctx = get_wgpu_ctx(); let (renderer, _event_loop) = Renderer::new(RendererOptions { web_renderer: web_renderer::WebRendererInitOptions { enable: false, @@ -73,7 +72,7 @@ pub(super) fn create_renderer() -> Renderer { framerate: Framerate { num: 30, den: 1 }, stream_fallback_timeout: Duration::from_secs(3), wgpu_features: WgpuFeatures::default(), - wgpu_ctx: Some(get_wgpu_ctx()), + wgpu_ctx: Some((wgpu_ctx.device.clone(), wgpu_ctx.queue.clone())), load_system_fonts: false, }) .unwrap(); @@ -81,7 +80,7 @@ pub(super) fn create_renderer() -> Renderer { } fn read_rgba_texture(texture: &wgpu::Texture) -> bytes::Bytes { - let (device, queue) = get_wgpu_ctx(); + let WgpuComponents { device, queue, .. } = get_wgpu_ctx(); let buffer = new_download_buffer(&device, texture); let mut encoder = device.create_command_encoder(&Default::default()); diff --git a/vk-video/Cargo.toml b/vk-video/Cargo.toml index ea60ae5fc..a31f2ff0d 100644 --- a/vk-video/Cargo.toml +++ b/vk-video/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/software-mansion/live-compositor" [dependencies] ash = "0.38.0" +bytemuck = { version = "1.19.0", features = ["derive"] } bytes = "1" derivative = "2.2.0" h264-reader = { git = "https://github.com/membraneframework-labs/h264-reader.git", branch = "live-compositor" } @@ -21,6 +22,8 @@ wgpu = "23.0.0" [dev-dependencies] tracing-subscriber = "0.3.18" +winit = "0.29" +clap = { version = "4.5.20", features = ["derive"] } [build-dependencies] cfg_aliases = "0.2.1" diff --git a/vk-video/examples/basic.rs b/vk-video/examples/basic.rs index 17eaaf4ad..a39fc93d5 100644 --- a/vk-video/examples/basic.rs +++ b/vk-video/examples/basic.rs @@ -2,7 +2,7 @@ fn main() { use std::io::Write; - use vk_video::Frame; + use vk_video::{Frame, VulkanInstance}; let subscriber = tracing_subscriber::FmtSubscriber::builder() .with_max_level(tracing::Level::INFO) @@ -18,17 +18,19 @@ fn main() { let h264_bytestream = std::fs::read(&args[1]).unwrap_or_else(|_| panic!("read {}", args[1])); - let vulkan_ctx = std::sync::Arc::new( - vk_video::VulkanCtx::new( + let vulkan_instance = VulkanInstance::new().unwrap(); + let vulkan_device = vulkan_instance + .create_device( wgpu::Features::empty(), wgpu::Limits { max_push_constant_size: 128, ..Default::default() }, + &mut None, ) - .unwrap(), - ); - let mut decoder = vk_video::BytesDecoder::new(vulkan_ctx).unwrap(); + .unwrap(); + + let mut decoder = vulkan_device.create_bytes_decoder().unwrap(); let mut output_file = std::fs::File::create("output.nv12").unwrap(); diff --git a/vk-video/examples/player/main.rs b/vk-video/examples/player/main.rs new file mode 100644 index 000000000..c10caef60 --- /dev/null +++ b/vk-video/examples/player/main.rs @@ -0,0 +1,14 @@ +#[cfg(vulkan)] +mod player; + +#[cfg(vulkan)] +fn main() { + player::run() +} + +#[cfg(not(vulkan))] +fn main() { + println!( + "This crate doesn't work on your operating system, because it does not support vulkan" + ); +} diff --git a/vk-video/examples/player/player.rs b/vk-video/examples/player/player.rs new file mode 100644 index 000000000..4fd14ddda --- /dev/null +++ b/vk-video/examples/player/player.rs @@ -0,0 +1,64 @@ +use std::{path::PathBuf, sync::mpsc, time::Duration}; + +use clap::Parser; +use vk_video::VulkanInstance; +use winit::{event_loop::EventLoop, window::WindowBuilder}; + +mod decoder; +mod renderer; + +const FRAMES_BUFFER_LEN: usize = 3; + +#[derive(Parser)] +#[command(version, about, long_about=None)] +struct Args { + /// an .h264 file to play + filename: PathBuf, + + /// framerate to play the video at + framerate: u64, +} + +struct FrameWithPts { + frame: wgpu::Texture, + /// Presentation timestamp + pts: Duration, +} + +pub fn run() { + let args = Args::parse(); + let subscriber = tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .finish(); + + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let file = std::fs::File::open(&args.filename).expect("open file"); + + let event_loop = EventLoop::new().unwrap(); + let window = WindowBuilder::new().build(&event_loop).unwrap(); + + let vulkan_instance = VulkanInstance::new().unwrap(); + + let mut surface = vulkan_instance + .wgpu_instance + .create_surface(&window) + .unwrap(); + + let vulkan_device = vulkan_instance + .create_device( + wgpu::Features::empty(), + wgpu::Limits::default(), + &mut Some(&mut surface), + ) + .unwrap(); + + let (tx, rx) = mpsc::sync_channel(FRAMES_BUFFER_LEN); + let vulkan_device_clone = vulkan_device.clone(); + + std::thread::spawn(move || { + decoder::run_decoder(tx, args.framerate, vulkan_device_clone, file); + }); + + renderer::run_renderer(event_loop, &window, surface, &vulkan_device, rx); +} diff --git a/vk-video/examples/player/player/decoder.rs b/vk-video/examples/player/player/decoder.rs new file mode 100644 index 000000000..09ab0018e --- /dev/null +++ b/vk-video/examples/player/player/decoder.rs @@ -0,0 +1,43 @@ +use std::{ + io::Read, + sync::{mpsc::SyncSender, Arc}, + time::Duration, +}; + +use bytes::BytesMut; +use vk_video::VulkanDevice; + +use super::FrameWithPts; + +pub fn run_decoder( + tx: SyncSender, + framerate: u64, + vulkan_device: Arc, + mut bytestream_reader: impl Read, +) { + let mut decoder = vulkan_device.create_wgpu_textures_decoder().unwrap(); + let frame_interval = 1.0 / (framerate as f64); + let mut frame_number = 0u64; + let mut buffer = BytesMut::zeroed(4096); + + while let Ok(n) = bytestream_reader.read(&mut buffer) { + if n == 0 { + return; + } + + let decoded = decoder.decode(&buffer[..n], None).unwrap(); + + for f in decoded { + let result = FrameWithPts { + frame: f.frame, + pts: Duration::from_secs_f64(frame_number as f64 * frame_interval), + }; + + frame_number += 1; + + if tx.send(result).is_err() { + return; + } + } + } +} diff --git a/vk-video/examples/player/player/renderer.rs b/vk-video/examples/player/player/renderer.rs new file mode 100644 index 000000000..e68d625c2 --- /dev/null +++ b/vk-video/examples/player/player/renderer.rs @@ -0,0 +1,353 @@ +use std::sync::{mpsc::Receiver, Arc}; + +use vk_video::VulkanDevice; +use wgpu::util::DeviceExt; +use winit::{ + dpi::PhysicalSize, + event::{ElementState, Event, KeyEvent, WindowEvent}, + event_loop::EventLoop, + keyboard::{KeyCode, PhysicalKey}, + window::Window, +}; + +use super::FrameWithPts; + +pub fn run_renderer<'a>( + event_loop: EventLoop<()>, + window: &'a Window, + surface: wgpu::Surface<'a>, + vulkan_device: &VulkanDevice, + rx: Receiver, +) { + let mut current_frame = rx.recv().unwrap(); + let mut next_frame = None; + + window.set_title("vk-video example player"); + window.set_resizable(false); + let _ = window.request_inner_size(PhysicalSize::new( + current_frame.frame.size().width, + current_frame.frame.size().height, + )); + + let mut renderer = Renderer::new(surface, vulkan_device, window); + + let start_timestamp = std::time::Instant::now(); + event_loop + .run(move |event, cf| match event { + Event::WindowEvent { window_id, event } if window_id == window.id() => match event { + WindowEvent::KeyboardInput { + event: + KeyEvent { + state: ElementState::Pressed, + physical_key: PhysicalKey::Code(KeyCode::Escape), + .. + }, + .. + } + | WindowEvent::CloseRequested => cf.exit(), + + WindowEvent::RedrawRequested => { + window.request_redraw(); + if next_frame.is_none() { + if let Ok(f) = rx.try_recv() { + next_frame = Some(f); + } + } + + let current_pts = std::time::Instant::now() - start_timestamp; + if let Some(next_frame_pts) = next_frame.as_ref().map(|f| f.pts) { + if next_frame_pts < current_pts { + current_frame = next_frame.take().unwrap(); + } + } + + let _ = window.request_inner_size(PhysicalSize::new( + current_frame.frame.size().width, + current_frame.frame.size().height, + )); + + renderer.render(¤t_frame.frame, window).unwrap(); + } + + WindowEvent::Resized(new_size) => renderer.resize(new_size), + _ => {} + }, + _ => {} + }) + .unwrap(); +} + +#[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] +#[repr(C)] +struct Vertex { + position: [f32; 3], + texture_coords: [f32; 2], +} + +impl Vertex { + const ATTRIBUTES: &[wgpu::VertexAttribute] = + &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x2]; + const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + step_mode: wgpu::VertexStepMode::Vertex, + attributes: Self::ATTRIBUTES, + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + }; +} + +const VERTICES: &[Vertex] = &[ + Vertex { + position: [-1.0, 1.0, 0.0], + texture_coords: [0.0, 0.0], + }, + Vertex { + position: [-1.0, -1.0, 0.0], + texture_coords: [0.0, 1.0], + }, + Vertex { + position: [1.0, -1.0, 0.0], + texture_coords: [1.0, 1.0], + }, + Vertex { + position: [1.0, 1.0, 0.0], + texture_coords: [1.0, 0.0], + }, +]; + +const INDICES: &[u16] = &[0, 1, 3, 1, 2, 3]; + +struct Renderer<'a> { + surface: wgpu::Surface<'a>, + device: Arc, + queue: Arc, + surface_configuration: wgpu::SurfaceConfiguration, + sampler: wgpu::Sampler, + vertex_buffer: wgpu::Buffer, + index_buffer: wgpu::Buffer, + pipeline: wgpu::RenderPipeline, +} + +impl<'a> Renderer<'a> { + fn new(surface: wgpu::Surface<'a>, vulkan_device: &VulkanDevice, window: &Window) -> Self { + let device = vulkan_device.wgpu_device.clone(); + let queue = vulkan_device.wgpu_queue.clone(); + let size = window.inner_size(); + let surface_capabilities = surface.get_capabilities(&vulkan_device.wgpu_adapter); + let surface_texture_format = surface_capabilities + .formats + .iter() + .find(|f| f.is_srgb()) + .copied() + .unwrap_or(surface_capabilities.formats[0]); + + let surface_configuration = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + width: size.width, + height: size.height, + format: surface_texture_format, + view_formats: vec![ + surface_texture_format, + surface_texture_format.remove_srgb_suffix(), + ], + alpha_mode: surface_capabilities.alpha_modes[0], + present_mode: surface_capabilities.present_modes[0], + desired_maximum_frame_latency: 2, + }; + + surface.configure(&device, &surface_configuration); + + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("vertex buffer"), + usage: wgpu::BufferUsages::VERTEX, + contents: bytemuck::cast_slice(VERTICES), + }); + + let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("index buffer"), + usage: wgpu::BufferUsages::INDEX, + contents: bytemuck::cast_slice(INDICES), + }); + + let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("bgl"), + entries: &[ + wgpu::BindGroupLayoutEntry { + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + }, + wgpu::BindGroupLayoutEntry { + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + }, + wgpu::BindGroupLayoutEntry { + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + }, + ], + }); + + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("sampler"), + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Nearest, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("pipeline layout"), + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], + }); + + let shader_module_descriptor = wgpu::include_wgsl!("shader.wgsl"); + let shader_module = device.create_shader_module(shader_module_descriptor); + + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("render pipeline"), + layout: Some(&pipeline_layout), + cache: None, + vertex: wgpu::VertexState { + module: &shader_module, + buffers: &[Vertex::LAYOUT], + compilation_options: Default::default(), + entry_point: None, + }, + fragment: Some(wgpu::FragmentState { + module: &shader_module, + targets: &[Some(wgpu::ColorTargetState { + format: surface_configuration.format.remove_srgb_suffix(), + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + compilation_options: Default::default(), + entry_point: None, + }), + + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + cull_mode: Some(wgpu::Face::Back), + front_face: wgpu::FrontFace::Ccw, + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + unclipped_depth: false, + }, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + depth_stencil: None, + }); + + Self { + surface, + device, + queue, + surface_configuration, + sampler, + index_buffer, + vertex_buffer, + pipeline, + } + } + + fn resize(&mut self, size: PhysicalSize) { + if size.width > 0 && size.height > 0 { + self.surface_configuration.width = size.width; + self.surface_configuration.height = size.height; + self.surface + .configure(&self.device, &self.surface_configuration); + } + } + + fn render(&mut self, frame: &wgpu::Texture, window: &Window) -> Result<(), wgpu::SurfaceError> { + let device = &self.device; + let surface = self.surface.get_current_texture()?; + let surface_view = surface.texture.create_view(&wgpu::TextureViewDescriptor { + format: Some(surface.texture.format().remove_srgb_suffix()), + ..Default::default() + }); + let texture_view_y = frame.create_view(&wgpu::TextureViewDescriptor { + label: Some("y texture"), + format: Some(wgpu::TextureFormat::R8Unorm), + aspect: wgpu::TextureAspect::Plane0, + dimension: Some(wgpu::TextureViewDimension::D2), + ..Default::default() + }); + + let texture_view_uv = frame.create_view(&wgpu::TextureViewDescriptor { + label: Some("uv texture"), + format: Some(wgpu::TextureFormat::Rg8Unorm), + aspect: wgpu::TextureAspect::Plane1, + dimension: Some(wgpu::TextureViewDimension::D2), + ..Default::default() + }); + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("bind group"), + layout: &self.pipeline.get_bind_group_layout(0), + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture_view_y), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&texture_view_uv), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::Sampler(&self.sampler), + }, + ], + }); + + let mut command_encoder = device.create_command_encoder(&Default::default()); + + { + let mut render_pass = command_encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("render pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::WHITE), + store: wgpu::StoreOp::Store, + }, + })], + ..Default::default() + }); + + render_pass.set_pipeline(&self.pipeline); + render_pass.set_bind_group(0, &bind_group, &[]); + render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); + render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16); + render_pass.draw_indexed(0..INDICES.len() as u32, 0, 0..1); + } + + self.queue.submit(Some(command_encoder.finish())); + window.pre_present_notify(); + surface.present(); + + Ok(()) + } +} diff --git a/vk-video/examples/player/player/shader.wgsl b/vk-video/examples/player/player/shader.wgsl new file mode 100644 index 000000000..1aa05c41c --- /dev/null +++ b/vk-video/examples/player/player/shader.wgsl @@ -0,0 +1,37 @@ +struct VertexInput { + @location(0) position: vec3, + @location(1) tex_coords: vec2, +} + +struct VertexOutput { + @builtin(position) position: vec4, + @location(0) tex_coords: vec2, +} + +@vertex +fn vs_main(input: VertexInput) -> VertexOutput { + var output: VertexOutput; + + output.position = vec4(input.position, 1.0); + output.tex_coords = input.tex_coords; + + return output; +} + +@group(0) @binding(0) var y_texture: texture_2d; +@group(0) @binding(1) var uv_texture: texture_2d; +@group(0) @binding(2) var sampler_: sampler; + +@fragment +fn fs_main(input: VertexOutput) -> @location(0) vec4 { + var y = textureSample(y_texture, sampler_, input.tex_coords).x; + var uv = textureSample(uv_texture, sampler_, input.tex_coords); + var u = uv.x; + var v = uv.y; + + let r = y + 1.40200 * (v - 128.0 / 255.0); + let g = y - 0.34414 * (u - 128.0 / 255.0) - 0.71414 * (v - 128.0 / 255.0); + let b = y + 1.77200 * (u - 128.0 / 255.0); + + return vec4(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0), 1.0); +} diff --git a/vk-video/examples/wgpu.rs b/vk-video/examples/wgpu.rs index 95d56096a..6ef6346ad 100644 --- a/vk-video/examples/wgpu.rs +++ b/vk-video/examples/wgpu.rs @@ -2,7 +2,7 @@ fn main() { use std::io::Write; - use vk_video::Frame; + use vk_video::{Frame, VulkanInstance}; let subscriber = tracing_subscriber::FmtSubscriber::builder() .with_max_level(tracing::Level::INFO) @@ -17,25 +17,27 @@ fn main() { } let h264_bytestream = std::fs::read(&args[1]).unwrap_or_else(|_| panic!("read {}", args[1])); - let vulkan_ctx = std::sync::Arc::new( - vk_video::VulkanCtx::new( + let vulkan_instance = VulkanInstance::new().unwrap(); + let vulkan_device = vulkan_instance + .create_device( wgpu::Features::empty(), wgpu::Limits { max_push_constant_size: 128, ..Default::default() }, + &mut None, ) - .unwrap(), - ); - let mut decoder = vk_video::WgpuTexturesDeocder::new(vulkan_ctx.clone()).unwrap(); + .unwrap(); + + let mut decoder = vulkan_device.create_wgpu_textures_decoder().unwrap(); let mut output_file = std::fs::File::create("output.nv12").unwrap(); for chunk in h264_bytestream.chunks(256) { let frames = decoder.decode(chunk, None).unwrap(); - let device = &vulkan_ctx.wgpu_ctx.device; - let queue = &vulkan_ctx.wgpu_ctx.queue; + let device = &vulkan_device.wgpu_device; + let queue = &vulkan_device.wgpu_queue; for Frame { frame, .. } in frames { let decoded_frame = download_wgpu_texture(device, queue, frame); output_file.write_all(&decoded_frame).unwrap(); diff --git a/vk-video/src/lib.rs b/vk-video/src/lib.rs index 92fcbb26f..5948eed65 100644 --- a/vk-video/src/lib.rs +++ b/vk-video/src/lib.rs @@ -6,9 +6,7 @@ use parser::Parser; use vulkan_decoder::{FrameSorter, VulkanDecoder}; pub use parser::ParserError; -pub use vulkan_decoder::{VulkanCtx, VulkanCtxError, VulkanDecoderError}; - -pub use vulkan_decoder::WgpuCtx; +pub use vulkan_decoder::{VulkanCtxError, VulkanDecoderError, VulkanDevice, VulkanInstance}; #[derive(Debug, thiserror::Error)] pub enum DecoderError { @@ -31,18 +29,6 @@ pub struct WgpuTexturesDeocder<'a> { } impl WgpuTexturesDeocder<'_> { - pub fn new(vulkan_ctx: std::sync::Arc) -> Result { - let parser = Parser::default(); - let vulkan_decoder = VulkanDecoder::new(vulkan_ctx)?; - let frame_sorter = FrameSorter::::new(); - - Ok(Self { - parser, - vulkan_decoder, - frame_sorter, - }) - } - // TODO: the below hasn't been verified. /// The produced textures have the [`wgpu::TextureFormat::NV12`] format and can be used as a copy source or a texture binding. pub fn decode( @@ -72,18 +58,6 @@ pub struct BytesDecoder<'a> { } impl BytesDecoder<'_> { - pub fn new(vulkan_ctx: std::sync::Arc) -> Result { - let parser = Parser::default(); - let vulkan_decoder = VulkanDecoder::new(vulkan_ctx)?; - let frame_sorter = FrameSorter::>::new(); - - Ok(Self { - parser, - vulkan_decoder, - frame_sorter, - }) - } - /// The result is a sequence of frames. Te payload of each [`Frame`] struct is a [`Vec`]. Each [`Vec`] contains a single /// decoded frame in the [NV12 format](https://en.wikipedia.org/wiki/YCbCr#4:2:0). pub fn decode( diff --git a/vk-video/src/vulkan_decoder.rs b/vk-video/src/vulkan_decoder.rs index d6486d478..1777a69d6 100644 --- a/vk-video/src/vulkan_decoder.rs +++ b/vk-video/src/vulkan_decoder.rs @@ -18,7 +18,7 @@ pub(crate) use frame_sorter::FrameSorter; pub use vulkan_ctx::*; pub struct VulkanDecoder<'a> { - vulkan_ctx: Arc, + vulkan_device: Arc, video_session_resources: Option>, command_buffers: CommandBuffers, _command_pools: CommandPools, @@ -99,7 +99,7 @@ pub enum VulkanDecoderError { } impl<'a> VulkanDecoder<'a> { - pub fn new(vulkan_ctx: Arc) -> Result { + pub fn new(vulkan_ctx: Arc) -> Result { let decode_pool = Arc::new(CommandPool::new( vulkan_ctx.device.clone(), vulkan_ctx.queues.h264_decode.idx, @@ -128,7 +128,7 @@ impl<'a> VulkanDecoder<'a> { }; Ok(Self { - vulkan_ctx, + vulkan_device: vulkan_ctx, video_session_resources: None, _command_pools: command_pools, command_buffers: CommandBuffers { @@ -237,14 +237,14 @@ impl VulkanDecoder<'_> { fn process_sps(&mut self, sps: &SeqParameterSet) -> Result<(), VulkanDecoderError> { match self.video_session_resources.as_mut() { Some(session) => session.process_sps( - &self.vulkan_ctx, + &self.vulkan_device, &self.command_buffers.decode_buffer, sps.clone(), &self.sync_structures.fence_memory_barrier_completed, )?, None => { self.video_session_resources = Some(VideoSessionResources::new_from_sps( - &self.vulkan_ctx, + &self.vulkan_device, &self.command_buffers.decode_buffer, sps.clone(), &self.sync_structures.fence_memory_barrier_completed, @@ -298,7 +298,7 @@ impl VulkanDecoder<'_> { // upload data to a buffer let size = Self::pad_size_to_alignment( decode_information.rbsp_bytes.len() as u64, - self.vulkan_ctx + self.vulkan_device .video_capabilities .min_bitstream_buffer_offset_alignment, ); @@ -310,7 +310,7 @@ impl VulkanDecoder<'_> { .ok_or(VulkanDecoderError::NoSession)?; let decode_buffer = Buffer::new_with_decode_data( - self.vulkan_ctx.allocator.clone(), + self.vulkan_device.allocator.clone(), &decode_information.rbsp_bytes, size, &video_session_resources.profile_info, @@ -337,7 +337,7 @@ impl VulkanDecoder<'_> { ); unsafe { - self.vulkan_ctx.device.cmd_pipeline_barrier2( + self.vulkan_device.device.cmd_pipeline_barrier2( *self.command_buffers.decode_buffer, &vk::DependencyInfo::default().memory_barriers(&[memory_barrier]), ) @@ -357,7 +357,7 @@ impl VulkanDecoder<'_> { .reference_slots(&reference_slots); unsafe { - self.vulkan_ctx + self.vulkan_device .device .video_queue_ext .cmd_begin_video_coding_khr(*self.command_buffers.decode_buffer, &begin_info) @@ -369,7 +369,7 @@ impl VulkanDecoder<'_> { .flags(vk::VideoCodingControlFlagsKHR::RESET); unsafe { - self.vulkan_ctx + self.vulkan_device .device .video_queue_ext .cmd_control_video_coding_khr( @@ -481,7 +481,7 @@ impl VulkanDecoder<'_> { } unsafe { - self.vulkan_ctx + self.vulkan_device .device .video_decode_queue_ext .cmd_decode_video_khr(*self.command_buffers.decode_buffer, &decode_info) @@ -492,7 +492,7 @@ impl VulkanDecoder<'_> { } unsafe { - self.vulkan_ctx + self.vulkan_device .device .video_queue_ext .cmd_end_video_coding_khr( @@ -503,7 +503,7 @@ impl VulkanDecoder<'_> { self.command_buffers.decode_buffer.end()?; - self.vulkan_ctx.queues.h264_decode.submit( + self.vulkan_device.queues.h264_decode.submit( &self.command_buffers.decode_buffer, &[], &[( @@ -552,8 +552,8 @@ impl VulkanDecoder<'_> { }; let queue_indices = [ - self.vulkan_ctx.queues.transfer.idx as u32, - self.vulkan_ctx.queues.wgpu.idx as u32, + self.vulkan_device.queues.transfer.idx as u32, + self.vulkan_device.queues.wgpu.idx as u32, ]; let create_info = vk::ImageCreateInfo::default() @@ -574,7 +574,10 @@ impl VulkanDecoder<'_> { .queue_family_indices(&queue_indices) .initial_layout(vk::ImageLayout::UNDEFINED); - let image = Arc::new(Image::new(self.vulkan_ctx.allocator.clone(), &create_info)?); + let image = Arc::new(Image::new( + self.vulkan_device.allocator.clone(), + &create_info, + )?); self.command_buffers .vulkan_to_wgpu_transfer_buffer @@ -617,7 +620,7 @@ impl VulkanDecoder<'_> { }); unsafe { - self.vulkan_ctx.device.cmd_pipeline_barrier2( + self.vulkan_device.device.cmd_pipeline_barrier2( *self.command_buffers.vulkan_to_wgpu_transfer_buffer, &vk::DependencyInfo::default() .image_memory_barriers(&[memory_barrier_src, memory_barrier_dst]), @@ -664,7 +667,7 @@ impl VulkanDecoder<'_> { ]; unsafe { - self.vulkan_ctx.device.cmd_copy_image( + self.vulkan_device.device.cmd_copy_image( *self.command_buffers.vulkan_to_wgpu_transfer_buffer, decode_output.image, vk::ImageLayout::TRANSFER_SRC_OPTIMAL, @@ -691,7 +694,7 @@ impl VulkanDecoder<'_> { .new_layout(vk::ImageLayout::GENERAL); unsafe { - self.vulkan_ctx.device.cmd_pipeline_barrier2( + self.vulkan_device.device.cmd_pipeline_barrier2( *self.command_buffers.vulkan_to_wgpu_transfer_buffer, &vk::DependencyInfo::default() .image_memory_barriers(&[memory_barrier_src, memory_barrier_dst]), @@ -700,7 +703,7 @@ impl VulkanDecoder<'_> { self.command_buffers.vulkan_to_wgpu_transfer_buffer.end()?; - self.vulkan_ctx.queues.transfer.submit( + self.vulkan_device.queues.transfer.submit( &self.command_buffers.vulkan_to_wgpu_transfer_buffer, &[( decode_output.wait_semaphore, @@ -759,9 +762,8 @@ impl VulkanDecoder<'_> { }; let wgpu_texture = unsafe { - self.vulkan_ctx - .wgpu_ctx - .device + self.vulkan_device + .wgpu_device .create_texture_from_hal::( hal_texture, &wgpu::TextureDescriptor { @@ -906,7 +908,7 @@ impl VulkanDecoder<'_> { }); unsafe { - self.vulkan_ctx.device.cmd_pipeline_barrier2( + self.vulkan_device.device.cmd_pipeline_barrier2( *self.command_buffers.gpu_to_mem_transfer_buffer, &vk::DependencyInfo::default().image_memory_barriers(&[memory_barrier]), ) @@ -915,7 +917,7 @@ impl VulkanDecoder<'_> { let y_plane_size = dimensions.width as u64 * dimensions.height as u64; let dst_buffer = Buffer::new_transfer( - self.vulkan_ctx.allocator.clone(), + self.vulkan_device.allocator.clone(), y_plane_size * 3 / 2, TransferDirection::GpuToMem, )?; @@ -956,7 +958,7 @@ impl VulkanDecoder<'_> { ]; unsafe { - self.vulkan_ctx.device.cmd_copy_image_to_buffer( + self.vulkan_device.device.cmd_copy_image_to_buffer( *self.command_buffers.gpu_to_mem_transfer_buffer, image, vk::ImageLayout::TRANSFER_SRC_OPTIMAL, @@ -974,7 +976,7 @@ impl VulkanDecoder<'_> { .new_layout(current_image_layout); unsafe { - self.vulkan_ctx.device.cmd_pipeline_barrier2( + self.vulkan_device.device.cmd_pipeline_barrier2( *self.command_buffers.gpu_to_mem_transfer_buffer, &vk::DependencyInfo::default().image_memory_barriers(&[memory_barrier]), ) @@ -982,7 +984,7 @@ impl VulkanDecoder<'_> { self.command_buffers.gpu_to_mem_transfer_buffer.end()?; - self.vulkan_ctx.queues.transfer.submit( + self.vulkan_device.queues.transfer.submit( &self.command_buffers.gpu_to_mem_transfer_buffer, wait_semaphores, signal_semaphores, diff --git a/vk-video/src/vulkan_decoder/session_resources.rs b/vk-video/src/vulkan_decoder/session_resources.rs index b57892e45..9c41a1fb1 100644 --- a/vk-video/src/vulkan_decoder/session_resources.rs +++ b/vk-video/src/vulkan_decoder/session_resources.rs @@ -10,7 +10,7 @@ use parameters::VideoSessionParametersManager; use super::{ h264_level_idc_to_max_dpb_mbs, vk_to_h264_level_idc, CommandBuffer, DecodeQueryPool, Fence, - H264ProfileInfo, SeqParameterSetExt, VideoSession, VulkanCtx, VulkanDecoderError, + H264ProfileInfo, SeqParameterSetExt, VideoSession, VulkanDecoderError, VulkanDevice, }; mod images; @@ -55,7 +55,7 @@ fn calculate_max_num_reorder_frames(sps: &SeqParameterSet) -> Result { pub(crate) fn new_from_sps( - vulkan_ctx: &VulkanCtx, + vulkan_ctx: &VulkanDevice, decode_buffer: &CommandBuffer, sps: SeqParameterSet, fence_memory_barrier_completed: &Fence, @@ -131,7 +131,7 @@ impl VideoSessionResources<'_> { pub(crate) fn process_sps( &mut self, - vulkan_ctx: &VulkanCtx, + vulkan_ctx: &VulkanDevice, decode_buffer: &CommandBuffer, sps: SeqParameterSet, fence_memory_barrier_completed: &Fence, @@ -200,7 +200,7 @@ impl VideoSessionResources<'_> { } fn new_decoding_images<'a>( - vulkan_ctx: &VulkanCtx, + vulkan_ctx: &VulkanDevice, profile: &H264ProfileInfo, max_coded_extent: vk::Extent2D, max_dpb_slots: u32, diff --git a/vk-video/src/vulkan_decoder/session_resources/images.rs b/vk-video/src/vulkan_decoder/session_resources/images.rs index 79b0e60f1..ab88132fc 100644 --- a/vk-video/src/vulkan_decoder/session_resources/images.rs +++ b/vk-video/src/vulkan_decoder/session_resources/images.rs @@ -4,7 +4,7 @@ use ash::vk; use crate::{ vulkan_decoder::{H264ProfileInfo, Image, ImageView}, - VulkanCtx, VulkanDecoderError, + VulkanDecoderError, VulkanDevice, }; pub(crate) struct DecodingImages<'a> { @@ -22,7 +22,7 @@ pub(crate) struct DecodingImageBundle<'a> { impl<'a> DecodingImageBundle<'a> { #[allow(clippy::too_many_arguments)] pub(crate) fn new( - vulkan_ctx: &VulkanCtx, + vulkan_ctx: &VulkanDevice, format: &vk::VideoFormatPropertiesKHR<'a>, dimensions: vk::Extent2D, image_usage: vk::ImageUsageFlags, @@ -156,7 +156,7 @@ impl<'a> DecodingImages<'a> { } pub(crate) fn new( - vulkan_ctx: &VulkanCtx, + vulkan_ctx: &VulkanDevice, profile: &H264ProfileInfo, dpb_format: &vk::VideoFormatPropertiesKHR<'a>, dst_format: &Option>, diff --git a/vk-video/src/vulkan_decoder/session_resources/parameters.rs b/vk-video/src/vulkan_decoder/session_resources/parameters.rs index e5f366f67..97af83f06 100644 --- a/vk-video/src/vulkan_decoder/session_resources/parameters.rs +++ b/vk-video/src/vulkan_decoder/session_resources/parameters.rs @@ -7,7 +7,7 @@ use crate::{ vulkan_decoder::{ Device, VideoSessionParameters, VkPictureParameterSet, VkSequenceParameterSet, }, - VulkanCtx, VulkanDecoderError, + VulkanDecoderError, VulkanDevice, }; /// Since `VideoSessionParameters` can only add sps and pps values (inserting sps or pps with an @@ -23,7 +23,7 @@ pub(crate) struct VideoSessionParametersManager { impl VideoSessionParametersManager { pub(crate) fn new( - vulkan_ctx: &VulkanCtx, + vulkan_ctx: &VulkanDevice, session: vk::VideoSessionKHR, ) -> Result { Ok(Self { diff --git a/vk-video/src/vulkan_decoder/vulkan_ctx.rs b/vk-video/src/vulkan_decoder/vulkan_ctx.rs index 24d94c37b..132ab4a3f 100644 --- a/vk-video/src/vulkan_decoder/vulkan_ctx.rs +++ b/vk-video/src/vulkan_decoder/vulkan_ctx.rs @@ -5,9 +5,13 @@ use std::{ use ash::{vk, Entry}; use tracing::{debug, error, warn}; +use wgpu::hal::Adapter; + +use crate::{parser::Parser, BytesDecoder, DecoderError, WgpuTexturesDeocder}; use super::{ - Allocator, CommandBuffer, CommandPool, DebugMessenger, Device, Instance, VulkanDecoderError, + Allocator, CommandBuffer, CommandPool, DebugMessenger, Device, FrameSorter, Instance, + VulkanDecoder, VulkanDecoderError, }; const REQUIRED_EXTENSIONS: &[&CStr] = &[ @@ -43,103 +47,15 @@ pub enum VulkanCtxError { StringConversionError(#[from] std::ffi::FromBytesUntilNulError), } -pub struct VulkanCtx { +pub struct VulkanInstance { _entry: Arc, - _instance: Arc, - _physical_device: vk::PhysicalDevice, - pub(crate) device: Arc, - pub(crate) allocator: Arc, - pub(crate) queues: Queues, + instance: Arc, _debug_messenger: Option, - pub(crate) video_capabilities: vk::VideoCapabilitiesKHR<'static>, - pub(crate) h264_dpb_format_properties: vk::VideoFormatPropertiesKHR<'static>, - pub(crate) h264_dst_format_properties: Option>, - pub(crate) h264_caps: vk::VideoDecodeH264CapabilitiesKHR<'static>, - pub wgpu_ctx: WgpuCtx, -} - -pub struct WgpuCtx { - pub instance: Arc, - pub adapter: Arc, - pub device: Arc, - pub queue: Arc, + pub wgpu_instance: Arc, } -pub(crate) struct CommandPools { - pub(crate) _decode_pool: Arc, - pub(crate) _transfer_pool: Arc, -} - -pub(crate) struct Queue { - pub(crate) queue: std::sync::Mutex, - pub(crate) idx: usize, - _video_properties: vk::QueueFamilyVideoPropertiesKHR<'static>, - pub(crate) query_result_status_properties: - vk::QueueFamilyQueryResultStatusPropertiesKHR<'static>, - device: Arc, -} - -impl Queue { - pub(crate) fn supports_result_status_queries(&self) -> bool { - self.query_result_status_properties - .query_result_status_support - == vk::TRUE - } - - pub(crate) fn submit( - &self, - buffer: &CommandBuffer, - wait_semaphores: &[(vk::Semaphore, vk::PipelineStageFlags2)], - signal_semaphores: &[(vk::Semaphore, vk::PipelineStageFlags2)], - fence: Option, - ) -> Result<(), VulkanDecoderError> { - fn to_sem_submit_info( - submits: &[(vk::Semaphore, vk::PipelineStageFlags2)], - ) -> Vec { - submits - .iter() - .map(|&(sem, stage)| { - vk::SemaphoreSubmitInfo::default() - .semaphore(sem) - .stage_mask(stage) - }) - .collect::>() - } - - let wait_semaphores = to_sem_submit_info(wait_semaphores); - let signal_semaphores = to_sem_submit_info(signal_semaphores); - - let buffer_submit_info = - [vk::CommandBufferSubmitInfo::default().command_buffer(buffer.buffer)]; - - let submit_info = [vk::SubmitInfo2::default() - .wait_semaphore_infos(&wait_semaphores) - .signal_semaphore_infos(&signal_semaphores) - .command_buffer_infos(&buffer_submit_info)]; - - unsafe { - self.device.queue_submit2( - *self.queue.lock().unwrap(), - &submit_info, - fence.unwrap_or(vk::Fence::null()), - )? - }; - - Ok(()) - } -} - -pub(crate) struct Queues { - pub(crate) transfer: Queue, - pub(crate) h264_decode: Queue, - pub(crate) wgpu: Queue, -} - -impl VulkanCtx { - pub fn new( - wgpu_features: wgpu::Features, - wgpu_limits: wgpu::Limits, - ) -> Result { +impl VulkanInstance { + pub fn new() -> Result, VulkanCtxError> { let entry = Arc::new(unsafe { Entry::load()? }); let api_version = vk::make_api_version(0, 1, 3, 0); @@ -232,20 +148,44 @@ impl VulkanCtx { )? }; - let physical_devices = unsafe { instance.enumerate_physical_devices()? }; + let wgpu_instance = + unsafe { wgpu::Instance::from_hal::(wgpu_instance) }; + + Ok(Self { + _entry: entry, + instance, + _debug_messenger: debug_messenger, + wgpu_instance: wgpu_instance.into(), + } + .into()) + } + + /// The `compatible surface` being a `&mut Option<&mut wgpu::Surface<'_>>` is a result of + /// weirdness in wgpu API, which we fixed upstream. When wgpu releases, this will be converted to + /// `Option<&wgpu::Surface<'_>>` + pub fn create_device( + &self, + wgpu_features: wgpu::Features, + wgpu_limits: wgpu::Limits, + compatible_surface: &mut Option<&mut wgpu::Surface<'_>>, + ) -> Result, VulkanCtxError> { + let physical_devices = unsafe { self.instance.enumerate_physical_devices()? }; let ChosenDevice { physical_device, + wgpu_adapter, queue_indices, h264_dpb_format_properties, h264_dst_format_properties, video_capabilities, h264_caps, - } = find_device(&physical_devices, &instance, REQUIRED_EXTENSIONS)?; - - let wgpu_adapter = wgpu_instance - .expose_adapter(physical_device) - .ok_or(VulkanCtxError::WgpuAdapterNotCreated)?; + } = find_device( + &physical_devices, + &self.instance, + &self.wgpu_instance, + REQUIRED_EXTENSIONS, + compatible_surface, + )?; let wgpu_features = wgpu_features | wgpu::Features::TEXTURE_FORMAT_NV12; @@ -281,15 +221,19 @@ impl VulkanCtx { .add_to_device_create(device_create_info) .push_next(&mut vk_synch_2_feature); - let device = unsafe { instance.create_device(physical_device, &device_create_info, None)? }; - let video_queue_ext = ash::khr::video_queue::Device::new(&instance, &device); - let video_decode_queue_ext = ash::khr::video_decode_queue::Device::new(&instance, &device); + let device = unsafe { + self.instance + .create_device(physical_device, &device_create_info, None)? + }; + let video_queue_ext = ash::khr::video_queue::Device::new(&self.instance, &device); + let video_decode_queue_ext = + ash::khr::video_decode_queue::Device::new(&self.instance, &device); let device = Arc::new(Device { device, video_queue_ext, video_decode_queue_ext, - _instance: instance.clone(), + _instance: self.instance.clone(), }); let h264_decode_queue = @@ -350,14 +294,12 @@ impl VulkanCtx { }; let allocator = Arc::new(Allocator::new( - instance.clone(), + self.instance.clone(), physical_device, device.clone(), )?); - let wgpu_instance = - unsafe { wgpu::Instance::from_hal::(wgpu_instance) }; - let wgpu_adapter = unsafe { wgpu_instance.create_adapter_from_hal(wgpu_adapter) }; + let wgpu_adapter = unsafe { self.wgpu_instance.create_adapter_from_hal(wgpu_adapter) }; let (wgpu_device, wgpu_queue) = unsafe { wgpu_adapter.create_device_from_hal( wgpu_device, @@ -371,38 +313,80 @@ impl VulkanCtx { )? }; - let wgpu_ctx = WgpuCtx { - instance: Arc::new(wgpu_instance), - adapter: Arc::new(wgpu_adapter), - device: Arc::new(wgpu_device), - queue: Arc::new(wgpu_queue), - }; - - Ok(Self { - _entry: entry, - _instance: instance, + Ok(VulkanDevice { _physical_device: physical_device, device, allocator, queues, - _debug_messenger: debug_messenger, video_capabilities, h264_dpb_format_properties, h264_dst_format_properties, h264_caps, - wgpu_ctx, + wgpu_device: wgpu_device.into(), + wgpu_queue: wgpu_queue.into(), + wgpu_adapter: wgpu_adapter.into(), + } + .into()) + } +} + +impl std::fmt::Debug for VulkanInstance { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("VulkanInstance").finish() + } +} + +pub struct VulkanDevice { + _physical_device: vk::PhysicalDevice, + pub(crate) device: Arc, + pub(crate) allocator: Arc, + pub(crate) queues: Queues, + pub(crate) video_capabilities: vk::VideoCapabilitiesKHR<'static>, + pub(crate) h264_dpb_format_properties: vk::VideoFormatPropertiesKHR<'static>, + pub(crate) h264_dst_format_properties: Option>, + pub(crate) h264_caps: vk::VideoDecodeH264CapabilitiesKHR<'static>, + pub wgpu_device: Arc, + pub wgpu_queue: Arc, + pub wgpu_adapter: Arc, +} + +impl VulkanDevice { + pub fn create_wgpu_textures_decoder( + self: &Arc, + ) -> Result { + let parser = Parser::default(); + let vulkan_decoder = VulkanDecoder::new(self.clone())?; + let frame_sorter = FrameSorter::::new(); + + Ok(WgpuTexturesDeocder { + parser, + vulkan_decoder, + frame_sorter, + }) + } + + pub fn create_bytes_decoder(self: &Arc) -> Result { + let parser = Parser::default(); + let vulkan_decoder = VulkanDecoder::new(self.clone())?; + let frame_sorter = FrameSorter::>::new(); + + Ok(BytesDecoder { + parser, + vulkan_decoder, + frame_sorter, }) } } -impl std::fmt::Debug for VulkanCtx { +impl std::fmt::Debug for VulkanDevice { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("VulkanCtx").finish() + f.debug_struct("VulkanDevice").finish() } } struct ChosenDevice<'a> { physical_device: vk::PhysicalDevice, + wgpu_adapter: wgpu::hal::ExposedAdapter, queue_indices: QueueIndices<'a>, h264_dpb_format_properties: vk::VideoFormatPropertiesKHR<'a>, h264_dst_format_properties: Option>, @@ -413,11 +397,31 @@ struct ChosenDevice<'a> { fn find_device<'a>( devices: &[vk::PhysicalDevice], instance: &Instance, + wgpu_instance: &wgpu::Instance, required_extension_names: &[&CStr], + compatible_surface: &mut Option<&mut wgpu::Surface<'_>>, ) -> Result, VulkanCtxError> { for &device in devices { let properties = unsafe { instance.get_physical_device_properties(device) }; + let wgpu_instance = unsafe { wgpu_instance.as_hal::() }.unwrap(); + + let wgpu_adapter = wgpu_instance + .expose_adapter(device) + .ok_or(VulkanCtxError::WgpuAdapterNotCreated)?; + + if let Some(surface) = compatible_surface { + let surface_capabilities = unsafe { + (*surface).as_hal::(|surface| { + surface.and_then(|surface| wgpu_adapter.adapter.surface_capabilities(surface)) + }) + }; + + if surface_capabilities.is_none() { + continue; + } + } + let mut vk_13_features = vk::PhysicalDeviceVulkan13Features::default(); let mut features = vk::PhysicalDeviceFeatures2::default().push_next(&mut vk_13_features); @@ -628,6 +632,7 @@ fn find_device<'a>( return Ok(ChosenDevice { physical_device: device, + wgpu_adapter, queue_indices: QueueIndices { transfer: QueueIndex { idx: transfer_queue_idx, @@ -703,6 +708,76 @@ fn query_video_format_properties<'a>( Ok(format_properties) } +pub(crate) struct CommandPools { + pub(crate) _decode_pool: Arc, + pub(crate) _transfer_pool: Arc, +} + +pub(crate) struct Queue { + pub(crate) queue: std::sync::Mutex, + pub(crate) idx: usize, + _video_properties: vk::QueueFamilyVideoPropertiesKHR<'static>, + pub(crate) query_result_status_properties: + vk::QueueFamilyQueryResultStatusPropertiesKHR<'static>, + device: Arc, +} + +impl Queue { + pub(crate) fn supports_result_status_queries(&self) -> bool { + self.query_result_status_properties + .query_result_status_support + == vk::TRUE + } + + pub(crate) fn submit( + &self, + buffer: &CommandBuffer, + wait_semaphores: &[(vk::Semaphore, vk::PipelineStageFlags2)], + signal_semaphores: &[(vk::Semaphore, vk::PipelineStageFlags2)], + fence: Option, + ) -> Result<(), VulkanDecoderError> { + fn to_sem_submit_info( + submits: &[(vk::Semaphore, vk::PipelineStageFlags2)], + ) -> Vec { + submits + .iter() + .map(|&(sem, stage)| { + vk::SemaphoreSubmitInfo::default() + .semaphore(sem) + .stage_mask(stage) + }) + .collect::>() + } + + let wait_semaphores = to_sem_submit_info(wait_semaphores); + let signal_semaphores = to_sem_submit_info(signal_semaphores); + + let buffer_submit_info = + [vk::CommandBufferSubmitInfo::default().command_buffer(buffer.buffer)]; + + let submit_info = [vk::SubmitInfo2::default() + .wait_semaphore_infos(&wait_semaphores) + .signal_semaphore_infos(&signal_semaphores) + .command_buffer_infos(&buffer_submit_info)]; + + unsafe { + self.device.queue_submit2( + *self.queue.lock().unwrap(), + &submit_info, + fence.unwrap_or(vk::Fence::null()), + )? + }; + + Ok(()) + } +} + +pub(crate) struct Queues { + pub(crate) transfer: Queue, + pub(crate) h264_decode: Queue, + pub(crate) wgpu: Queue, +} + struct QueueIndex<'a> { idx: usize, video_properties: vk::QueueFamilyVideoPropertiesKHR<'a>, diff --git a/vk-video/src/vulkan_decoder/wrappers/video.rs b/vk-video/src/vulkan_decoder/wrappers/video.rs index 315441719..7c3757820 100644 --- a/vk-video/src/vulkan_decoder/wrappers/video.rs +++ b/vk-video/src/vulkan_decoder/wrappers/video.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use ash::vk; -use crate::{vulkan_decoder::VulkanDecoderError, VulkanCtx}; +use crate::{vulkan_decoder::VulkanDecoderError, VulkanDevice}; use super::{Device, MemoryAllocation, VideoQueueExt}; @@ -96,7 +96,7 @@ pub(crate) struct VideoSession { impl VideoSession { pub(crate) fn new( - vulkan_ctx: &VulkanCtx, + vulkan_ctx: &VulkanDevice, profile_info: &vk::VideoProfileInfoKHR, max_coded_extent: vk::Extent2D, max_dpb_slots: u32, From ac42ba4aca110bdd3a1ba9dd5452df65e1900a8b Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Fri, 22 Nov 2024 12:31:48 +0100 Subject: [PATCH 42/51] get settings from api, support both or just one track --- .../src/types/from_register_output.rs | 35 +++- compositor_api/src/types/register_output.rs | 27 ++- .../src/pipeline/output/whip.rs | 70 +++++--- .../output/whip/establish_peer_connection.rs | 1 + .../output/whip/init_peer_connection.rs | 170 ++++++++++++------ .../src/pipeline/output/whip/payloader.rs | 6 +- 6 files changed, 225 insertions(+), 84 deletions(-) diff --git a/compositor_api/src/types/from_register_output.rs b/compositor_api/src/types/from_register_output.rs index ff7a3ebe2..8aba4815b 100644 --- a/compositor_api/src/types/from_register_output.rs +++ b/compositor_api/src/types/from_register_output.rs @@ -10,6 +10,7 @@ use compositor_pipeline::pipeline::{ output::{ self, mp4::{Mp4AudioTrack, Mp4OutputOptions, Mp4VideoTrack}, + whip::WhipAudioOptions, }, }; @@ -193,8 +194,21 @@ impl TryFrom for pipeline::RegisterOutputOptions pipeline::VideoCodec::H264, }); - let audio_codec = audio.as_ref().map(|a| match a.encoder { - RtpAudioEncoderOptions::Opus { .. } => pipeline::AudioCodec::Opus, + let audio_options = audio.as_ref().map(|a| match &a.encoder { + WhipAudioEncoderOptions::Opus { + channels, + preset: _, + } => WhipAudioOptions { + codec: pipeline::AudioCodec::Opus, + channels: match channels { + audio::AudioChannels::Mono => { + compositor_pipeline::audio_mixer::AudioChannels::Mono + } + audio::AudioChannels::Stereo => { + compositor_pipeline::audio_mixer::AudioChannels::Stereo + } + }, + }, }); if let Some(token) = &bearer_token { @@ -205,7 +219,7 @@ impl TryFrom for pipeline::RegisterOutputOptions for pipeline::RegisterOutputOptions for pipeline::encoder::AudioEncoderOptions { } } +impl From for pipeline::encoder::AudioEncoderOptions { + fn from(value: WhipAudioEncoderOptions) -> Self { + match value { + WhipAudioEncoderOptions::Opus { channels, preset } => { + AudioEncoderOptions::Opus(encoder::opus::OpusEncoderOptions { + channels: channels.into(), + preset: preset.unwrap_or(OpusEncoderPreset::Voip).into(), + }) + } + } + } +} + impl TryFrom for pipeline::PipelineOutputEndCondition { type Error = TypeError; diff --git a/compositor_api/src/types/register_output.rs b/compositor_api/src/types/register_output.rs index c70fad968..cd8cc26f8 100644 --- a/compositor_api/src/types/register_output.rs +++ b/compositor_api/src/types/register_output.rs @@ -48,7 +48,7 @@ pub struct WhipOutput { /// Video track configuration. pub video: Option, /// Audio track configuration. - pub audio: Option, + pub audio: Option, } #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] @@ -90,6 +90,19 @@ pub struct OutputMp4AudioOptions { pub initial: Audio, } +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct OutputWhipAudioOptions { + /// (**default="sum_clip"**) Specifies how audio should be mixed. + pub mixing_strategy: Option, + /// Condition for termination of output stream based on the input streams states. + pub send_eos_when: Option, + /// Audio encoder options. + pub encoder: WhipAudioEncoderOptions, + /// Initial audio mixer configuration for output. + pub initial: Audio, +} + #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] #[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)] pub enum VideoEncoderOptions { @@ -121,6 +134,18 @@ pub enum Mp4AudioEncoderOptions { Aac { channels: AudioChannels }, } +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)] +pub enum WhipAudioEncoderOptions { + Opus { + /// Specifies channels configuration. + channels: AudioChannels, + + /// (**default="voip"**) Specifies preset for audio output encoder. + preset: Option, + }, +} + /// This type defines when end of an input stream should trigger end of the output stream. Only one of those fields can be set at the time. /// Unless specified otherwise the input stream is considered finished/ended when: /// - TCP connection was dropped/closed. diff --git a/compositor_pipeline/src/pipeline/output/whip.rs b/compositor_pipeline/src/pipeline/output/whip.rs index 98d3e07f1..9be315cd7 100644 --- a/compositor_pipeline/src/pipeline/output/whip.rs +++ b/compositor_pipeline/src/pipeline/output/whip.rs @@ -16,6 +16,7 @@ use url::{ParseError, Url}; use webrtc::track::track_local::TrackLocalWriter; use crate::{ + audio_mixer::AudioChannels, error::OutputInitError, event::{Event, EventEmitter}, pipeline::{AudioCodec, EncoderOutputEvent, PipelineCtx, VideoCodec}, @@ -37,13 +38,20 @@ pub struct WhipSenderOptions { pub endpoint_url: String, pub bearer_token: Option>, pub video: Option, - pub audio: Option, + pub audio: Option, +} + +#[derive(Debug, Clone, Copy)] +pub struct WhipAudioOptions { + pub codec: AudioCodec, + pub channels: AudioChannels, } #[derive(Debug, Clone)] pub struct WhipCtx { - options: WhipSenderOptions, output_id: OutputId, + options: WhipSenderOptions, + sample_rate: u32, request_keyframe_sender: Option>, should_close: Arc, tokio_rt: Arc, @@ -106,6 +114,9 @@ pub enum WhipError { #[error("Entity Tag non-matching")] EntityTagNonMatching, + + #[error("Codec not supported: {0}")] + UnsupportedCodec(&'static str), } const WHIP_INIT_TIMEOUT: Duration = Duration::from_secs(60); @@ -125,8 +136,9 @@ impl WhipSender { oneshot::channel::>(); let whip_ctx = WhipCtx { - options: options.clone(), output_id: output_id.clone(), + options: options.clone(), + sample_rate: pipeline_ctx.output_sample_rate, request_keyframe_sender, should_close: should_close.clone(), tokio_rt: pipeline_ctx.tokio_rt.clone(), @@ -188,7 +200,7 @@ async fn run_whip_sender_task( event_emitter: Arc, ) { let client = Arc::new(reqwest::Client::new()); - let (peer_connection, video_track, audio_track) = match init_peer_connection().await { + let (peer_connection, video_track, audio_track) = match init_peer_connection(&whip_ctx).await { Ok(pc) => pc, Err(err) => { init_confirmation_sender.send(Err(err)).unwrap(); @@ -219,26 +231,44 @@ async fn run_whip_sender_task( }; match chunk { - Payload::Video(video_payload) => match video_payload { - Ok(video_bytes) => { - if video_track.write(&video_bytes).await.is_err() { - error!("Error occurred while writing to video track for session"); + Payload::Video(video_payload) => { + match video_track.clone() { + Some(video_track) => match video_payload { + Ok(video_bytes) => { + if video_track.write(&video_bytes).await.is_err() { + error!("Error occurred while writing to video track, closing connection."); + break; + } + } + Err(err) => { + error!("Error while reading video bytes: {err}"); + } + }, + None => { + error!("Video payload detected on output with no video, shutting down"); + break; } } - Err(err) => { - error!("Error while reading video bytes: {err}"); - } - }, - Payload::Audio(audio_payload) => match audio_payload { - Ok(audio_bytes) => { - if audio_track.write(&audio_bytes).await.is_err() { - error!("Error occurred while writing to video track for session"); + } + Payload::Audio(audio_payload) => { + match audio_track.clone() { + Some(audio_track) => match audio_payload { + Ok(audio_bytes) => { + if audio_track.write(&audio_bytes).await.is_err() { + error!("Error occurred while writing to audio track, closing connection."); + break; + } + } + Err(err) => { + error!("Error while audio video bytes: {err}"); + } + }, + None => { + error!("Audio payload detected on output with no audio, shutting down"); + break; } } - Err(err) => { - error!("Error while reading audio bytes: {err}"); - } - }, + } } } if let Err(err) = client.delete(whip_session_url).send().await { diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs index 9b074bac0..098cfd1b2 100644 --- a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -67,6 +67,7 @@ pub async fn connect( .create_offer(None) .await .map_err(WhipError::OfferCreationError)?; + error!("offer: {offer:?}"); let endpoint_url = Url::parse(&whip_ctx.options.endpoint_url) .map_err(|e| WhipError::InvalidEndpointUrl(e, whip_ctx.options.endpoint_url.clone()))?; diff --git a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs index e4e979550..8e37d99cc 100644 --- a/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/init_peer_connection.rs @@ -1,9 +1,14 @@ -use super::WhipError; +use crate::{ + audio_mixer::AudioChannels, + pipeline::{AudioCodec, VideoCodec}, +}; + +use super::{WhipAudioOptions, WhipCtx, WhipError}; use std::{ env::{self, VarError}, sync::Arc, }; -use tracing::{info, warn}; +use tracing::{error, info, warn}; use webrtc::{ api::{ interceptor_registry::register_default_interceptors, @@ -22,44 +27,29 @@ use webrtc::{ const STUN_SERVER_ENV: &str = "LIVE_COMPOSITOR_STUN_SERVERS"; -pub async fn init_peer_connection() -> Result< +pub async fn init_peer_connection( + whip_ctx: &WhipCtx, +) -> Result< ( Arc, - Arc, - Arc, + Option>, + Option>, ), WhipError, > { let mut media_engine = MediaEngine::default(); media_engine.register_default_codecs()?; - media_engine.register_codec( - RTCRtpCodecParameters { - capability: RTCRtpCodecCapability { - mime_type: MIME_TYPE_H264.to_owned(), - clock_rate: 90000, - channels: 0, - sdp_fmtp_line: "".to_owned(), - rtcp_feedback: vec![], - }, - payload_type: 96, - ..Default::default() - }, - RTPCodecType::Video, - )?; - media_engine.register_codec( - RTCRtpCodecParameters { - capability: RTCRtpCodecCapability { - mime_type: MIME_TYPE_OPUS.to_owned(), - clock_rate: 48000, - channels: 2, - sdp_fmtp_line: "".to_owned(), - rtcp_feedback: vec![], - }, - payload_type: 111, - ..Default::default() - }, - RTPCodecType::Audio, - )?; + + if let Some(video) = whip_ctx.options.video { + media_engine.register_codec(video_codec_parameters(video), RTPCodecType::Video)?; + } + + if let Some(audio) = whip_ctx.options.audio { + media_engine.register_codec( + audio_codec_parameters(audio, whip_ctx.sample_rate)?, + RTPCodecType::Audio, + )?; + } let mut registry = Registry::new(); registry = register_default_interceptors(registry, &mut media_engine)?; let api = APIBuilder::new() @@ -93,30 +83,37 @@ pub async fn init_peer_connection() -> Result< ..Default::default() }; let peer_connection = Arc::new(api.new_peer_connection(config).await?); - let video_track = Arc::new(TrackLocalStaticRTP::new( - RTCRtpCodecCapability { - mime_type: MIME_TYPE_H264.to_owned(), - ..Default::default() - }, - "video".to_owned(), - "webrtc-rs".to_owned(), - )); - let audio_track = Arc::new(TrackLocalStaticRTP::new( - RTCRtpCodecCapability { - mime_type: MIME_TYPE_OPUS.to_owned(), - ..Default::default() - }, - "audio".to_owned(), - "webrtc-rs".to_owned(), - )); - peer_connection - .add_track(video_track.clone()) - .await - .map_err(WhipError::PeerConnectionInitError)?; - peer_connection - .add_track(audio_track.clone()) - .await - .map_err(WhipError::PeerConnectionInitError)?; + + let video_track = match whip_ctx.options.video { + Some(video) => { + let video_track = Arc::new(TrackLocalStaticRTP::new( + video_codec_capability(video), + "video".to_owned(), + format!("live-compositor-{}-video", whip_ctx.output_id).to_owned(), + )); + peer_connection + .add_track(video_track.clone()) + .await + .map_err(WhipError::PeerConnectionInitError)?; + Some(video_track) + } + None => None, + }; + let audio_track = match whip_ctx.options.audio { + Some(audio_options) => { + let audio_track = Arc::new(TrackLocalStaticRTP::new( + audio_codec_capability(audio_options, whip_ctx.sample_rate)?, + "audio".to_owned(), + format!("live-compositor-{}-audio", whip_ctx.output_id).to_owned(), + )); + peer_connection + .add_track(audio_track.clone()) + .await + .map_err(WhipError::PeerConnectionInitError)?; + Some(audio_track) + } + None => None, + }; let transceivers = peer_connection.get_transceivers().await; for transceiver in transceivers { transceiver @@ -125,3 +122,62 @@ pub async fn init_peer_connection() -> Result< } Ok((peer_connection, video_track, audio_track)) } + +fn video_codec_capability(video: VideoCodec) -> RTCRtpCodecCapability { + match video { + VideoCodec::H264 => RTCRtpCodecCapability { + mime_type: MIME_TYPE_H264.to_owned(), + clock_rate: 90000, + channels: 0, + sdp_fmtp_line: "".to_owned(), + rtcp_feedback: vec![], + }, + } +} + +fn audio_codec_capability( + audio_options: WhipAudioOptions, + sample_rate: u32, +) -> Result { + match audio_options.codec { + AudioCodec::Opus => Ok(RTCRtpCodecCapability { + mime_type: MIME_TYPE_OPUS.to_owned(), + clock_rate: sample_rate, + channels: match audio_options.channels { + AudioChannels::Mono => 1, + AudioChannels::Stereo => 2, + }, + sdp_fmtp_line: "".to_owned(), + rtcp_feedback: vec![], + }), + AudioCodec::Aac => Err(WhipError::UnsupportedCodec("AAC")), + } +} + +fn video_codec_parameters(video: VideoCodec) -> RTCRtpCodecParameters { + let capability = video_codec_capability(video); + let payload_type = match video { + VideoCodec::H264 => 96, + }; + RTCRtpCodecParameters { + capability, + payload_type, + ..Default::default() + } +} + +fn audio_codec_parameters( + audio_options: WhipAudioOptions, + sample_rate: u32, +) -> Result { + let capability = audio_codec_capability(audio_options, sample_rate)?; + let payload_type = match audio_options.codec { + AudioCodec::Aac => return Err(WhipError::UnsupportedCodec("AAC")), + AudioCodec::Opus => 111, + }; + Ok(RTCRtpCodecParameters { + capability, + payload_type, + ..Default::default() + }) +} diff --git a/compositor_pipeline/src/pipeline/output/whip/payloader.rs b/compositor_pipeline/src/pipeline/output/whip/payloader.rs index 720dddb32..f64a51772 100644 --- a/compositor_pipeline/src/pipeline/output/whip/payloader.rs +++ b/compositor_pipeline/src/pipeline/output/whip/payloader.rs @@ -12,6 +12,8 @@ use crate::pipeline::{ AudioCodec, VideoCodec, }; +use super::WhipAudioOptions; + const H264_CLOCK_RATE: u32 = 90000; const OPUS_CLOCK_RATE: u32 = 48000; @@ -104,10 +106,10 @@ pub enum Payload { } impl Payloader { - pub fn new(video: Option, audio: Option) -> Self { + pub fn new(video: Option, audio: Option) -> Self { Self { video: video.map(VideoPayloader::new), - audio: audio.map(AudioPayloader::new), + audio: audio.map(|audio| AudioPayloader::new(audio.codec)), } } From 9dfa17b430c495975ca24cf635c65e7db409f880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Radkowski?= Date: Fri, 22 Nov 2024 13:06:50 +0100 Subject: [PATCH 43/51] Revert "Update wgpu to 23.0.0 (#846)" (#882) --- Cargo.lock | 222 ++++++++++-------- Cargo.toml | 4 +- compositor_render/Cargo.toml | 2 +- compositor_render/src/wgpu/common_pipeline.rs | 4 +- .../wgpu/format/interleaved_yuv_to_rgba.rs | 4 +- .../src/wgpu/format/nv12_to_rgba.rs | 4 +- .../src/wgpu/format/planar_yuv_to_rgba.rs | 4 +- .../src/wgpu/format/rgba_to_yuv.rs | 4 +- .../src/wgpu/utils/r8_fill_with_color.rs | 4 +- compositor_web/Cargo.toml | 2 +- vk-video/Cargo.toml | 2 +- vk-video/examples/player/player/renderer.rs | 4 +- vk-video/src/vulkan_decoder.rs | 9 +- vk-video/src/vulkan_decoder/vulkan_ctx.rs | 18 +- 14 files changed, 145 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07a98612b..70509b2a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -371,18 +371,18 @@ dependencies = [ [[package]] name = "bit-set" -version = "0.8.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.8.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" [[package]] name = "bit_field" @@ -450,9 +450,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] @@ -591,9 +591,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -601,9 +601,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -625,9 +625,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "cmake" @@ -660,6 +660,37 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "com" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "combine" version = "4.6.7" @@ -981,6 +1012,17 @@ dependencies = [ "syn 2.0.75", ] +[[package]] +name = "d3d12" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017" +dependencies = [ + "bitflags 2.6.0", + "libloading 0.8.0", + "winapi", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -1476,9 +1518,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "glow" -version = "0.14.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" dependencies = [ "js-sys", "slotmap", @@ -1498,7 +1540,8 @@ dependencies = [ [[package]] name = "glyphon" version = "0.6.0" -source = "git+https://github.com/grovesNL/glyphon?rev=f1f50ab#f1f50ab7b1d35291c3504f4b0a50c7f12e0099db" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11b1afb04c1a1be055989042258499473d0a9447f16450b433aba10bc2a46e7" dependencies = [ "cosmic-text", "etagere", @@ -1528,14 +1571,15 @@ dependencies = [ [[package]] name = "gpu-allocator" -version = "0.27.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7" dependencies = [ "log", "presser", "thiserror", - "windows 0.58.0", + "winapi", + "windows 0.52.0", ] [[package]] @@ -1616,9 +1660,24 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "hassle-rs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" +dependencies = [ + "bitflags 2.6.0", + "com", + "libc", + "libloading 0.8.0", + "thiserror", + "widestring", + "winapi", +] [[package]] name = "heck" @@ -1781,7 +1840,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core", ] [[package]] @@ -1857,7 +1916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", ] [[package]] @@ -1963,9 +2022,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -2309,9 +2368,9 @@ checksum = "96a1fe2275b68991faded2c80aa4a33dba398b77d276038b8f50701a22e55918" [[package]] name = "naga" -version = "23.0.0" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d5941e45a15b53aad4375eedf02033adb7a28931eedc31117faffa52e6a857e" +checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad" dependencies = [ "arrayvec", "bit-set", @@ -2584,9 +2643,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" @@ -2775,9 +2834,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.3" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", @@ -3841,18 +3900,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -4359,9 +4418,9 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.6" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "untrusted" @@ -4528,9 +4587,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", @@ -4539,9 +4598,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -4554,9 +4613,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -4566,9 +4625,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4576,9 +4635,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -4589,9 +4648,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-log" @@ -4715,9 +4774,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -4761,9 +4820,9 @@ checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" [[package]] name = "wgpu" -version = "23.0.0" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ab52f2d3d18b70d5ab8dd270a1cff3ebe6dbe4a7d13c1cc2557138a9777fdc" +checksum = "e1d1c4ba43f80542cf63a0a6ed3134629ae73e8ab51e4b765a67f3aa062eb433" dependencies = [ "arrayvec", "cfg_aliases 0.1.1", @@ -4786,9 +4845,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "23.0.0" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0c68e7b6322a03ee5b83fcd92caeac5c2a932f6457818179f4652ad2a9c065" +checksum = "0348c840d1051b8e86c3bcd31206080c5e71e5933dabd79be1ce732b0b2f089a" dependencies = [ "arrayvec", "bit-vec", @@ -4811,9 +4870,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "23.0.0" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de6e7266b869de56c7e3ed72a954899f71d14fec6cc81c102b7530b92947601b" +checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f" dependencies = [ "android_system_properties", "arrayvec", @@ -4821,14 +4880,15 @@ dependencies = [ "bit-set", "bitflags 2.6.0", "block", - "bytemuck", "cfg_aliases 0.1.1", "core-graphics-types", + "d3d12", "glow", "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", "gpu-descriptor", + "hassle-rs", "js-sys", "khronos-egl", "libc", @@ -4850,15 +4910,14 @@ dependencies = [ "wasm-bindgen", "web-sys", "wgpu-types", - "windows 0.58.0", - "windows-core 0.58.0", + "winapi", ] [[package]] name = "wgpu-types" -version = "23.0.0" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068" +checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d" dependencies = [ "bitflags 2.6.0", "js-sys", @@ -4947,11 +5006,11 @@ dependencies = [ [[package]] name = "windows" -version = "0.58.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core 0.58.0", + "windows-core", "windows-targets 0.52.6", ] @@ -4964,41 +5023,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.75", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.75", -] - [[package]] name = "windows-registry" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 5607ce975..c0261eb4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ socket2 = "0.5.5" webrtc-util = "0.8.0" opus = "0.3.0" rubato = "0.15.0" -glyphon = { git = "https://github.com/grovesNL/glyphon", rev = "f1f50ab" } +glyphon = "0.6.0" futures-util = "0.3.30" tokio = { version = "1", features = ["full"] } schemars = { git = "https://github.com/membraneframework-labs/schemars", rev = "a5ad1f9", features = [ @@ -59,7 +59,7 @@ schemars = { git = "https://github.com/membraneframework-labs/schemars", rev = " ] } shared_memory = "0.12.4" vk-video = { path = "vk-video" } -wgpu = { version = "23.0.0", default-features = false, features = [ +wgpu = { version = "22.1.0", default-features = false, features = [ "wgsl", "dx12", "metal", diff --git a/compositor_render/Cargo.toml b/compositor_render/Cargo.toml index b3b09df27..b1e47a3f7 100644 --- a/compositor_render/Cargo.toml +++ b/compositor_render/Cargo.toml @@ -22,7 +22,7 @@ glyphon = { workspace = true } crossbeam-channel = { workspace = true } resvg = "0.35.0" nalgebra-glm = { version = "0.18.0", features = ["convert-bytemuck"] } -naga = "23.0.0" +naga = "22.1.0" rand = { workspace = true } tracing = { workspace = true } shared_memory = { workspace = true, optional = true } diff --git a/compositor_render/src/wgpu/common_pipeline.rs b/compositor_render/src/wgpu/common_pipeline.rs index 68a48796d..5c22de2cd 100644 --- a/compositor_render/src/wgpu/common_pipeline.rs +++ b/compositor_render/src/wgpu/common_pipeline.rs @@ -111,12 +111,12 @@ pub fn create_render_pipeline( vertex: wgpu::VertexState { buffers: &[Vertex::LAYOUT], module: shader_module, - entry_point: Some(crate::wgpu::common_pipeline::VERTEX_ENTRYPOINT_NAME), + entry_point: crate::wgpu::common_pipeline::VERTEX_ENTRYPOINT_NAME, compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: shader_module, - entry_point: Some(crate::wgpu::common_pipeline::FRAGMENT_ENTRYPOINT_NAME), + entry_point: crate::wgpu::common_pipeline::FRAGMENT_ENTRYPOINT_NAME, targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs b/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs index e60702524..5b7e9b909 100644 --- a/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs +++ b/compositor_render/src/wgpu/format/interleaved_yuv_to_rgba.rs @@ -33,14 +33,14 @@ impl InterleavedYuv422ToRgbaConverter { vertex: wgpu::VertexState { module: &shader_module, - entry_point: Some("vs_main"), + entry_point: "vs_main", buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: Some("fs_main"), + entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/format/nv12_to_rgba.rs b/compositor_render/src/wgpu/format/nv12_to_rgba.rs index 0a8deac30..dddcb5091 100644 --- a/compositor_render/src/wgpu/format/nv12_to_rgba.rs +++ b/compositor_render/src/wgpu/format/nv12_to_rgba.rs @@ -32,14 +32,14 @@ impl Nv12ToRgbaConverter { vertex: wgpu::VertexState { module: &shader_module, - entry_point: Some("vs_main"), + entry_point: "vs_main", buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: Some("fs_main"), + entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs b/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs index a9e6f4b61..79fed53a8 100644 --- a/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs +++ b/compositor_render/src/wgpu/format/planar_yuv_to_rgba.rs @@ -38,14 +38,14 @@ impl PlanarYuvToRgbaConverter { vertex: wgpu::VertexState { module: &shader_module, - entry_point: Some("vs_main"), + entry_point: "vs_main", buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: Some("fs_main"), + entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8UnormSrgb, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/format/rgba_to_yuv.rs b/compositor_render/src/wgpu/format/rgba_to_yuv.rs index 866ea3bae..e1f8e46db 100644 --- a/compositor_render/src/wgpu/format/rgba_to_yuv.rs +++ b/compositor_render/src/wgpu/format/rgba_to_yuv.rs @@ -36,14 +36,14 @@ impl RgbaToYuvConverter { vertex: wgpu::VertexState { module: &shader_module, - entry_point: Some("vs_main"), + entry_point: "vs_main", buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: Some("fs_main"), + entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::R8Unorm, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_render/src/wgpu/utils/r8_fill_with_color.rs b/compositor_render/src/wgpu/utils/r8_fill_with_color.rs index c5554d01e..65b4d67fb 100644 --- a/compositor_render/src/wgpu/utils/r8_fill_with_color.rs +++ b/compositor_render/src/wgpu/utils/r8_fill_with_color.rs @@ -30,13 +30,13 @@ impl R8FillWithValue { primitive: PRIMITIVE_STATE, vertex: wgpu::VertexState { module: &shader_module, - entry_point: Some("vs_main"), + entry_point: "vs_main", buffers: &[Vertex::LAYOUT], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader_module, - entry_point: Some("fs_main"), + entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::R8Unorm, write_mask: wgpu::ColorWrites::all(), diff --git a/compositor_web/Cargo.toml b/compositor_web/Cargo.toml index 88b41e0ff..682029a67 100644 --- a/compositor_web/Cargo.toml +++ b/compositor_web/Cargo.toml @@ -17,7 +17,7 @@ tracing-subscriber = "0.2.19" log = { workspace = true } wasm-log = "0.3.1" js-sys = "0.3.69" -wasm-bindgen = "0.2.95" +wasm-bindgen = "0.2.93" wasm-bindgen-futures = "0.4.42" web-sys = { version = "0.3.69", features = [ "Document", diff --git a/vk-video/Cargo.toml b/vk-video/Cargo.toml index a31f2ff0d..9204336c0 100644 --- a/vk-video/Cargo.toml +++ b/vk-video/Cargo.toml @@ -18,7 +18,7 @@ h264-reader = { git = "https://github.com/membraneframework-labs/h264-reader.git thiserror = "1.0.59" tracing = "0.1.40" vk-mem = "0.4.0" -wgpu = "23.0.0" +wgpu = "22.1.0" [dev-dependencies] tracing-subscriber = "0.3.18" diff --git a/vk-video/examples/player/player/renderer.rs b/vk-video/examples/player/player/renderer.rs index e68d625c2..fafb7664c 100644 --- a/vk-video/examples/player/player/renderer.rs +++ b/vk-video/examples/player/player/renderer.rs @@ -227,7 +227,7 @@ impl<'a> Renderer<'a> { module: &shader_module, buffers: &[Vertex::LAYOUT], compilation_options: Default::default(), - entry_point: None, + entry_point: "vs_main", }, fragment: Some(wgpu::FragmentState { module: &shader_module, @@ -237,7 +237,7 @@ impl<'a> Renderer<'a> { write_mask: wgpu::ColorWrites::ALL, })], compilation_options: Default::default(), - entry_point: None, + entry_point: "fs_main", }), primitive: wgpu::PrimitiveState { diff --git a/vk-video/src/vulkan_decoder.rs b/vk-video/src/vulkan_decoder.rs index 1777a69d6..84ffdccd5 100644 --- a/vk-video/src/vulkan_decoder.rs +++ b/vk-video/src/vulkan_decoder.rs @@ -730,11 +730,6 @@ impl VulkanDecoder<'_> { } } - // this has to be done with Option and mut, because the closure we create has to be FnMut. - // this means we cannot consume its captures, so we have to take the option to be able to - // drop the resource. - let mut image_clone = Some(image.clone()); - let hal_texture = unsafe { wgpu::hal::vulkan::Device::texture_from_raw( **image, @@ -755,9 +750,7 @@ impl VulkanDecoder<'_> { format: wgpu::TextureFormat::NV12, mip_level_count: 1, }, - Some(Box::new(move || { - image_clone.take(); - })), + Some(Box::new(image.clone())), ) }; diff --git a/vk-video/src/vulkan_decoder/vulkan_ctx.rs b/vk-video/src/vulkan_decoder/vulkan_ctx.rs index 132ab4a3f..daf9761e2 100644 --- a/vk-video/src/vulkan_decoder/vulkan_ctx.rs +++ b/vk-video/src/vulkan_decoder/vulkan_ctx.rs @@ -127,11 +127,6 @@ impl VulkanInstance { None }; - // this has to be done with Option and mut, because the closure we create has to be FnMut. - // this means we cannot consume its captures, so we have to take the option to be able to - // drop the resource. - let mut instance_clone = Some(instance.clone()); - let wgpu_instance = unsafe { wgpu::hal::vulkan::Instance::from_raw( (*entry).clone(), @@ -142,9 +137,7 @@ impl VulkanInstance { extensions, wgpu::InstanceFlags::empty(), false, - Some(Box::new(move || { - instance_clone.take(); - })), + None, )? }; @@ -274,17 +267,10 @@ impl VulkanInstance { }, }; - // this has to be done with Option and mut, because the closure we create has to be FnMut. - // this means we cannot consume its captures, so we have to take the option to be able to - // drop the resource. - let mut device_clone = Some(device.clone()); - let wgpu_device = unsafe { wgpu_adapter.adapter.device_from_raw( device.device.clone(), - Some(Box::new(move || { - device_clone.take(); - })), + false, &required_extensions, wgpu_features, &wgpu::MemoryHints::default(), From e3dc0972a40e3e794aef2e53d644d0f894f35fb3 Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:27:58 +0100 Subject: [PATCH 44/51] [vk-video] Add a readme. (#866) Co-authored-by: Wojciech Kozyra --- vk-video/Cargo.toml | 8 +++- vk-video/README.md | 91 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 vk-video/README.md diff --git a/vk-video/Cargo.toml b/vk-video/Cargo.toml index 9204336c0..deedb94ef 100644 --- a/vk-video/Cargo.toml +++ b/vk-video/Cargo.toml @@ -6,12 +6,15 @@ authors = ["Software Mansion "] readme = "README.md" license = "MIT" repository = "https://github.com/software-mansion/live-compositor" +rust-version = "1.81" +description = "A library for hardware video coding using Vulkan Video, with wgpu integration." +categories = ["multimedia::video", "multimedia::encoding", "hardware-support", "encoding", "graphics"] +keywords = ["vulkan", "video", "wgpu", "decoding", "h264"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] ash = "0.38.0" -bytemuck = { version = "1.19.0", features = ["derive"] } bytes = "1" derivative = "2.2.0" h264-reader = { git = "https://github.com/membraneframework-labs/h264-reader.git", branch = "live-compositor" } @@ -21,9 +24,10 @@ vk-mem = "0.4.0" wgpu = "22.1.0" [dev-dependencies] +bytemuck = { version = "1.19.0", features = ["derive"] } +clap = { version = "4.5.20", features = ["derive"] } tracing-subscriber = "0.3.18" winit = "0.29" -clap = { version = "4.5.20", features = ["derive"] } [build-dependencies] cfg_aliases = "0.2.1" diff --git a/vk-video/README.md b/vk-video/README.md new file mode 100644 index 000000000..c0f848952 --- /dev/null +++ b/vk-video/README.md @@ -0,0 +1,91 @@ +# vk-video + +A library for hardware video coding using Vulkan Video, with [wgpu] integration. + +[![Crates.io][crates-badge]][crates-url] +[![docs.rs][docs-badge]][docs-url] +[![MIT licensed][mit-badge]][mit-url] +[![Build Status][actions-badge]][actions-url] + +[crates-badge]: https://img.shields.io/crates/v/vk-video +[crates-url]: https://crates.io/crates/vk-video +[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[mit-url]: https://github.com/software-mansion/live-compositor/blob/master/vk-video/LICENSE +[actions-badge]: https://github.com/software-mansion/live-compositor/actions/workflows/test.yml/badge.svg +[actions-url]: https://github.com/software-mansion/live-compositor/actions/workflows/test.yml?query=branch%3Amaster +[docs-badge]: https://img.shields.io/docsrs/vk-video +[docs-url]: https://docs.rs/vk-video/latest/vk-video/ + +## Overview + +The goal of this library is to provide easy access to hardware video coding. You can use it to decode a video frame into a `Vec` with pixel data, or into a [`wgpu::Texture`]. Currently, we only support H.264 (aka AVC or MPEG 4 Part 10) decoding, but we plan to support at least H.264 encoding and hopefully other codecs supported by Vulkan Video. + +An advantage of using this library with wgpu is that decoded video frames never leave the GPU memory. There's no copying the frames to RAM and back to the GPU, so it should be quite fast if you want to use them for rendering. + +## Usage + +```rs +fn decode_video( + window: &winit::window::Window, + mut encoded_video_reader: impl std::io::Read, +) { + let instance = vk_video::VulkanInstance::new().unwrap(); + let mut surface = instance.wgpu_instance.create_surface(window).unwrap(); + let device = instance + .create_device( + wgpu::Features::empty(), + wgpu::Limits::default(), + &mut Some(&mut surface), + ) + .unwrap(); + + let mut decoder = device.create_wgpu_textures_decoder().unwrap(); + let mut buffer = vec![0; 4096]; + + while let Ok(n) = encoded_video_reader.read(&mut buffer) { + if n == 0 { + return; + } + + let decoded_frames = decoder.decode(&buffer[..n], None).unwrap(); + + for frame in decoded_frames { + // Each frame contains a wgpu::Texture you can sample for drawing. + // device.wgpu_device is a wgpu::Device and device.wgpu_queue + // is a wgpu::Queue. You can use these for interacting with the frames. + } + } +} +``` +Be sure to check out our examples, especially the `player` example, which is a simple video player built using this library and wgpu. Because the player is very simple, you need to extract the raw h264 data from a container before usage. Here's an example on how to extract the h264 bytestream out of an mp4 file using ffmpeg: + +```sh +ffmpeg -i input.mp4 -c:v copy -bsf:v h264_mp4toannexb -an output.h264 +``` + +Then you can run the example with: + +```sh +git clone https://github.com/software-mansion/live-compositor.git +cd live-compositor/vk-video +cargo run --example player -- output.h264 FRAMERATE +``` + +## Compatibility + +On Linux, the library should work on NVIDIA GPUs out of the box. For AMD GPUs with recent Mesa drivers, you need to set the `RADV_PERFTEST=video_decode` environment variable for now: + +```sh +RADV_PERFTEST=video_decode cargo run +``` + +It should work on Windows with recent drivers out of the box. Be sure to submit an issue if it doesn't. + +[wgpu]: https://wgpu.rs/ +[`wgpu::Texture`]: https://docs.rs/wgpu/latest/wgpu/struct.Texture.html + +## vk-video is created by Software Mansion + +[![swm](https://logo.swmansion.com/logo?color=white&variant=desktop&width=150&tag=live-compositor-vk-video 'Software Mansion')](https://swmansion.com) + +Since 2012 [Software Mansion](https://swmansion.com) is a software agency with experience in building web and mobile apps as well as complex multimedia solutions. We are Core React Native Contributors and experts in live streaming and broadcasting technologies. We can help you build your next dream product โ€“ [Hire us](https://swmansion.com/contact/projects?utm_source=live-compositor-vk-video&utm_medium=readme). From d6d252fe053ad5dea075a8c0ba356cba5724544b Mon Sep 17 00:00:00 2001 From: Jerzy Wilczek <72213407+jerzywilczek@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:40:18 +0100 Subject: [PATCH 45/51] Add hardware encoding to the compositor API. (#875) --- .../src/types/from_register_input.rs | 30 ++- compositor_api/src/types/register_input.rs | 26 ++- compositor_pipeline/Cargo.toml | 5 +- compositor_pipeline/src/pipeline/input/mp4.rs | 11 +- .../src/pipeline/input/mp4/mp4_file_reader.rs | 8 +- .../examples/encoded_channel_output.rs | 1 + integration_tests/examples/mp4_hw_dec.rs | 66 ++++++ .../examples/raw_channel_output.rs | 1 + integration_tests/examples/vulkan.rs | 192 +++++------------- 9 files changed, 179 insertions(+), 161 deletions(-) create mode 100644 integration_tests/examples/mp4_hw_dec.rs diff --git a/compositor_api/src/types/from_register_input.rs b/compositor_api/src/types/from_register_input.rs index fa2e0ab51..f11332c43 100644 --- a/compositor_api/src/types/from_register_input.rs +++ b/compositor_api/src/types/from_register_input.rs @@ -81,6 +81,10 @@ impl TryFrom for InputAudioStream { } } +#[cfg(not(feature = "vk-video"))] +const NO_VULKAN_VIDEO: &str = + "Requested `vulkan_video` decoder, but this binary was compiled without the `vk-video` feature."; + impl TryFrom for pipeline::RegisterInputOptions { type Error = TypeError; @@ -106,10 +110,20 @@ impl TryFrom for pipeline::RegisterInputOptions { .as_ref() .map(|video| { Ok(input::rtp::InputVideoStream { - options: match video { - InputRtpVideoOptions::FfmepgH264 => decoder::VideoDecoderOptions { + options: match video.decoder { + VideoDecoder::FfmpegH264 => decoder::VideoDecoderOptions { decoder: pipeline::VideoDecoder::FFmpegH264, }, + + #[cfg(feature = "vk-video")] + VideoDecoder::VulkanVideo => decoder::VideoDecoderOptions { + decoder: pipeline::VideoDecoder::VulkanVideoH264, + }, + + #[cfg(not(feature = "vk-video"))] + VideoDecoder::VulkanVideo => { + return Err(TypeError::new(NO_VULKAN_VIDEO)) + } }, }) }) @@ -146,6 +160,7 @@ impl TryFrom for pipeline::RegisterInputOptions { required, offset_ms, should_loop, + video_decoder, } = value; const BAD_URL_PATH_SPEC: &str = @@ -165,10 +180,21 @@ impl TryFrom for pipeline::RegisterInputOptions { buffer_duration: None, }; + let video_decoder = match video_decoder.unwrap_or(VideoDecoder::FfmpegH264) { + VideoDecoder::FfmpegH264 => pipeline::VideoDecoder::FFmpegH264, + + #[cfg(feature = "vk-video")] + VideoDecoder::VulkanVideo => pipeline::VideoDecoder::VulkanVideoH264, + + #[cfg(not(feature = "vk-video"))] + VideoDecoder::VulkanVideo => return Err(TypeError::new(NO_VULKAN_VIDEO)), + }; + Ok(pipeline::RegisterInputOptions { input_options: input::InputOptions::Mp4(input::mp4::Mp4Options { source, should_loop: should_loop.unwrap_or(false), + video_decoder, }), queue_options, }) diff --git a/compositor_api/src/types/register_input.rs b/compositor_api/src/types/register_input.rs index e66f14fc4..93d919f78 100644 --- a/compositor_api/src/types/register_input.rs +++ b/compositor_api/src/types/register_input.rs @@ -45,6 +45,8 @@ pub struct Mp4Input { /// Offset in milliseconds relative to the pipeline start (start request). If offset is /// not defined then stream is synchronized based on the first frames delivery time. pub offset_ms: Option, + /// (**default=`ffmpeg_h264`**) The decoder to use for decoding video. + pub video_decoder: Option, } /// Capture streams from devices connected to Blackmagic DeckLink card. @@ -122,8 +124,24 @@ pub enum InputRtpAudioOptions { } #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(tag = "decoder", rename_all = "snake_case", deny_unknown_fields)] -pub enum InputRtpVideoOptions { - #[serde(rename = "ffmpeg_h264")] - FfmepgH264, +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub struct InputRtpVideoOptions { + pub decoder: VideoDecoder, +} + +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub enum VideoDecoder { + /// Use the software decoder based on ffmpeg. + FfmpegH264, + + /// Use hardware decoder based on Vulkan Video. + /// + /// This should be faster and more scalable than teh ffmpeg decoder, if the hardware and OS + /// support it. + /// + /// This requires hardware that supports Vulkan Video. Another requirement is this program has + /// to be compiled with the `vk-video` feature enabled (enabled by default on platforms which + /// support Vulkan, i.e. non-Apple operating systems and not the web). + VulkanVideo, } diff --git a/compositor_pipeline/Cargo.toml b/compositor_pipeline/Cargo.toml index c7593a088..488d769cd 100644 --- a/compositor_pipeline/Cargo.toml +++ b/compositor_pipeline/Cargo.toml @@ -29,11 +29,8 @@ tracing = { workspace = true } fdk-aac-sys = "0.5.0" rubato = "0.15.0" wgpu = { workspace = true } +vk-video = { path = "../vk-video/", optional = true } glyphon = { workspace = true } [target.x86_64-unknown-linux-gnu.dependencies] decklink = { path = "../decklink", optional = true } - -# platforms that support vulkan are: windows and all non-apple unixes. emscripten is a web-based platform, where vulkan is not available either -[target.'cfg(any(windows, all(unix, not(target_os = "emscripten"), not(target_os = "ios"), not(target_os = "macos"))))'.dependencies] -vk-video = { path = "../vk-video/", optional = true } diff --git a/compositor_pipeline/src/pipeline/input/mp4.rs b/compositor_pipeline/src/pipeline/input/mp4.rs index c23ef87f4..1f1306f9a 100644 --- a/compositor_pipeline/src/pipeline/input/mp4.rs +++ b/compositor_pipeline/src/pipeline/input/mp4.rs @@ -6,7 +6,10 @@ use crossbeam_channel::Receiver; use tracing::error; use crate::{ - pipeline::decoder::{AudioDecoderOptions, VideoDecoderOptions}, + pipeline::{ + decoder::{AudioDecoderOptions, VideoDecoderOptions}, + VideoDecoder, + }, queue::PipelineEvent, }; @@ -20,6 +23,7 @@ pub mod mp4_file_reader; pub struct Mp4Options { pub source: Source, pub should_loop: bool, + pub video_decoder: VideoDecoder, } pub(crate) enum Mp4ReaderOptions { @@ -96,13 +100,16 @@ impl Mp4 { should_loop: options.should_loop, }, input_id.clone(), + options.video_decoder, )?; let (video_reader, video_receiver) = match video { Some((reader, receiver)) => { let input_receiver = VideoInputReceiver::Encoded { chunk_receiver: receiver, - decoder_options: reader.decoder_options(), + decoder_options: VideoDecoderOptions { + decoder: options.video_decoder, + }, }; (Some(reader), Some(input_receiver)) } diff --git a/compositor_pipeline/src/pipeline/input/mp4/mp4_file_reader.rs b/compositor_pipeline/src/pipeline/input/mp4/mp4_file_reader.rs index 205c76d6d..fedd15b2e 100644 --- a/compositor_pipeline/src/pipeline/input/mp4/mp4_file_reader.rs +++ b/compositor_pipeline/src/pipeline/input/mp4/mp4_file_reader.rs @@ -125,6 +125,7 @@ impl Mp4FileReader { pub(crate) fn new_video( options: Mp4ReaderOptions, input_id: InputId, + video_decoder: VideoDecoder, ) -> Result, ChunkReceiver)>, Mp4Error> { let stop_thread = Arc::new(AtomicBool::new(false)); let span = span!(Level::INFO, "MP4 video", input_id = input_id.to_string()); @@ -136,7 +137,7 @@ impl Mp4FileReader { Self::new( input_file, size, - Self::find_h264_info, + |r| Self::find_h264_info(r, video_decoder), None, stop_thread, span, @@ -153,7 +154,7 @@ impl Mp4FileReader { Self::new( reader, size, - Self::find_h264_info, + |r| Self::find_h264_info(r, video_decoder), Some(fragment_receiver), stop_thread, span, @@ -165,6 +166,7 @@ impl Mp4FileReader { fn find_h264_info( reader: &mp4::Mp4Reader, + video_decoder: VideoDecoder, ) -> Option Bytes>> { let (&track_id, track, avc) = reader.tracks().iter().find_map(|(id, track)| { let track_type = track.track_type().ok()?; @@ -234,7 +236,7 @@ impl Mp4FileReader { }; let decoder_options = VideoDecoderOptions { - decoder: VideoDecoder::FFmpegH264, + decoder: video_decoder, }; Some(TrackInfo { diff --git a/integration_tests/examples/encoded_channel_output.rs b/integration_tests/examples/encoded_channel_output.rs index fdf5e6d26..715235591 100644 --- a/integration_tests/examples/encoded_channel_output.rs +++ b/integration_tests/examples/encoded_channel_output.rs @@ -91,6 +91,7 @@ fn main() { input_options: InputOptions::Mp4(Mp4Options { source: Source::File(root_dir.join(BUNNY_FILE_PATH)), should_loop: false, + video_decoder: compositor_pipeline::pipeline::VideoDecoder::FFmpegH264, }), queue_options: QueueInputOptions { required: true, diff --git a/integration_tests/examples/mp4_hw_dec.rs b/integration_tests/examples/mp4_hw_dec.rs new file mode 100644 index 000000000..cbbd4c5b1 --- /dev/null +++ b/integration_tests/examples/mp4_hw_dec.rs @@ -0,0 +1,66 @@ +use anyhow::Result; +use compositor_api::types::Resolution; +use serde_json::json; +use std::time::Duration; + +use integration_tests::{ + examples::{self, run_example}, + ffmpeg::start_ffmpeg_receive, +}; + +const VIDEO_RESOLUTION: Resolution = Resolution { + width: 1280, + height: 720, +}; + +const IP: &str = "127.0.0.1"; +const OUTPUT_PORT: u16 = 8004; + +fn main() { + run_example(client_code); +} + +fn client_code() -> Result<()> { + start_ffmpeg_receive(Some(OUTPUT_PORT), None)?; + + examples::post( + "input/input_1/register", + &json!({ + "type": "mp4", + "path": "examples/assets/BigBuckBunny.mp4", + "video_decoder": "vulkan_video", + }), + )?; + + examples::post( + "output/output_1/register", + &json!({ + "type": "rtp_stream", + "port": OUTPUT_PORT, + "ip": IP, + "video": { + "resolution": { + "width": VIDEO_RESOLUTION.width, + "height": VIDEO_RESOLUTION.height, + }, + "encoder": { + "type": "ffmpeg_h264", + "preset": "ultrafast" + }, + "initial": { + "root": { + "id": "input_1", + "type": "input_stream", + "input_id": "input_1", + } + } + } + }), + )?; + + std::thread::sleep(Duration::from_millis(500)); + + examples::post("start", &json!({}))?; + + Ok(()) +} diff --git a/integration_tests/examples/raw_channel_output.rs b/integration_tests/examples/raw_channel_output.rs index 3b21da594..ec8e11b74 100644 --- a/integration_tests/examples/raw_channel_output.rs +++ b/integration_tests/examples/raw_channel_output.rs @@ -113,6 +113,7 @@ fn main() { input_options: InputOptions::Mp4(Mp4Options { source: Source::File(root_dir().join(BUNNY_FILE_PATH)), should_loop: false, + video_decoder: compositor_pipeline::pipeline::VideoDecoder::FFmpegH264, }), queue_options: QueueInputOptions { required: true, diff --git a/integration_tests/examples/vulkan.rs b/integration_tests/examples/vulkan.rs index 46e8e14e7..6e9ed6c11 100644 --- a/integration_tests/examples/vulkan.rs +++ b/integration_tests/examples/vulkan.rs @@ -1,17 +1,8 @@ use anyhow::Result; -use integration_tests::examples::download_all_assets; -use live_compositor::{ - config::read_config, - logger::{self}, -}; +use integration_tests::examples::run_example; fn main() { - ffmpeg_next::format::network::init(); - logger::init_logger(read_config().logger); - - download_all_assets().unwrap(); - - client_code().unwrap(); + run_example(client_code); } #[cfg(target_os = "macos")] @@ -22,45 +13,10 @@ fn client_code() -> Result<()> { #[cfg(target_os = "linux")] fn client_code() -> Result<()> { use compositor_api::types::Resolution; - use compositor_pipeline::{ - pipeline::{ - decoder::VideoDecoderOptions, - encoder::{ - ffmpeg_h264::{EncoderPreset, Options as H264Options}, - VideoEncoderOptions, - }, - input::{ - rtp::{InputVideoStream, RtpReceiverOptions, RtpStream}, - InputOptions, - }, - output::{ - rtp::{RtpConnectionOptions, RtpSenderOptions}, - OutputOptions, OutputProtocolOptions, - }, - rtp::{RequestedPort, TransportProtocol}, - Options, OutputVideoOptions, PipelineOutputEndCondition, Port, RegisterInputOptions, - RegisterOutputOptions, VideoCodec, VideoDecoder, - }, - queue::QueueInputOptions, - Pipeline, - }; - use compositor_render::{ - error::ErrorStack, - scene::{ - Component, ComponentId, HorizontalAlign, InputStreamComponent, RGBAColor, - TilesComponent, VerticalAlign, - }, - InputId, OutputId, - }; - use live_compositor::config::read_config; - use signal_hook::{consts, iterator::Signals}; - use std::{ - sync::{Arc, Mutex}, - time::Duration, - }; + use serde_json::json; use integration_tests::{ - examples::TestSample, + examples::{self, TestSample}, ffmpeg::{start_ffmpeg_receive, start_ffmpeg_send}, }; @@ -76,119 +32,63 @@ fn client_code() -> Result<()> { const VIDEOS: u16 = 6; start_ffmpeg_receive(Some(OUTPUT_PORT), None)?; - let config = read_config(); - let (pipeline, event_loop) = Pipeline::new(Options { - queue_options: config.queue_options, - stream_fallback_timeout: config.stream_fallback_timeout, - web_renderer: config.web_renderer, - force_gpu: config.force_gpu, - download_root: config.download_root, - output_sample_rate: config.output_sample_rate, - wgpu_features: config.required_wgpu_features, - load_system_fonts: Some(true), - wgpu_ctx: None, - }) - .unwrap_or_else(|err| { - panic!( - "Failed to start compositor.\n{}", - ErrorStack::new(&err).into_string() - ) - }); - - let pipeline = Arc::new(Mutex::new(pipeline)); - let mut children = Vec::new(); for i in 0..VIDEOS { - let input_id = InputId(format!("input_{i}").into()); - - let input_options = RegisterInputOptions { - input_options: InputOptions::Rtp(RtpReceiverOptions { - port: RequestedPort::Exact(INPUT_PORT + 2 * i), - transport_protocol: TransportProtocol::Udp, - stream: RtpStream { - video: Some(InputVideoStream { - options: VideoDecoderOptions { - decoder: VideoDecoder::VulkanVideoH264, - }, - }), - audio: None, - }, + let input_id = format!("input_{i}"); + + examples::post( + &format!("input/{input_id}/register"), + &json!({ + "type": "rtp_stream", + "port": INPUT_PORT + i * 2, + "video": { + "decoder": "vulkan_video" + } }), - queue_options: QueueInputOptions { - offset: Some(Duration::ZERO), - required: false, - buffer_duration: None, - }, - }; - - Pipeline::register_input(&pipeline, input_id.clone(), input_options).unwrap(); + )?; - children.push(Component::InputStream(InputStreamComponent { - id: None, - input_id, + children.push(json!({ + "type": "input_stream", + "input_id": input_id, })); } - let output_options = RegisterOutputOptions { - output_options: OutputOptions { - output_protocol: OutputProtocolOptions::Rtp(RtpSenderOptions { - video: Some(VideoCodec::H264), - audio: None, - connection_options: RtpConnectionOptions::Udp { - port: Port(OUTPUT_PORT), - ip: IP.into(), - }, - }), - video: Some(VideoEncoderOptions::H264(H264Options { - preset: EncoderPreset::Ultrafast, - resolution: VIDEO_RESOLUTION.into(), - raw_options: Vec::new(), - })), - audio: None, - }, - video: Some(OutputVideoOptions { - initial: Component::Tiles(TilesComponent { - id: Some(ComponentId("tiles".into())), - padding: 5.0, - background_color: RGBAColor(0x44, 0x44, 0x44, 0xff), - children, - width: None, - height: None, - margin: 0.0, - transition: None, - vertical_align: VerticalAlign::Center, - horizontal_align: HorizontalAlign::Center, - tile_aspect_ratio: (16, 9), - }), + let scene = json!({ + "type": "tiles", + "id": "tile", + "padding": 5, + "background_color_rgba": "#444444FF", + "children": children, + }); - end_condition: PipelineOutputEndCondition::Never, + examples::post( + "output/output_1/register", + &json!({ + "type": "rtp_stream", + "ip": IP, + "port": OUTPUT_PORT, + "video": { + "resolution": { + "width": VIDEO_RESOLUTION.width, + "height": VIDEO_RESOLUTION.height, + }, + "encoder": { + "type": "ffmpeg_h264", + "preset": "ultrafast", + }, + "initial": { + "root": scene, + }, + }, }), - audio: None, - }; - - pipeline - .lock() - .unwrap() - .register_output(OutputId("output_1".into()), output_options) - .unwrap(); + )?; - Pipeline::start(&pipeline); + examples::post("start", &json!({}))?; for i in 0..VIDEOS { start_ffmpeg_send(IP, Some(INPUT_PORT + 2 * i), None, TestSample::BigBuckBunny)?; } - let event_loop_fallback = || { - let mut signals = Signals::new([consts::SIGINT]).unwrap(); - signals.forever().next(); - }; - if let Err(err) = event_loop.run_with_fallback(&event_loop_fallback) { - panic!( - "Failed to start event loop.\n{}", - ErrorStack::new(&err).into_string() - ) - } - Ok(()) } From 89e88adb25948f382972952176401ffa48fddfcc Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Wed, 27 Nov 2024 12:10:22 +0100 Subject: [PATCH 46/51] extend disc space druging github build and test job --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3938507a..da74a8535 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,6 +14,11 @@ jobs: check: runs-on: ubuntu-24.04 steps: + - name: Maximize build space + uses: easimon/maximize-build-space@master + with: + remove-dotnet: 'true' + - name: ๐Ÿ›  Install system dependencies run: | set -e From f1d3abaae9e8553778fe836aca7e7f57248647a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Radkowski?= Date: Thu, 28 Nov 2024 13:06:29 +0100 Subject: [PATCH 47/51] Download CEF binaries to `~/.cache` (#887) --- Cargo.lock | 39 +++++++++++++++++++++ compositor_chromium/chromium_sys/Cargo.toml | 1 + compositor_chromium/chromium_sys/build.rs | 5 +-- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70509b2a3..7e46e2f1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -556,6 +556,7 @@ dependencies = [ "anyhow", "bindgen 0.66.1", "cmake", + "dirs", "fs_extra", "reqwest", ] @@ -1067,6 +1068,27 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -2691,6 +2713,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "opus" version = "0.3.0" @@ -3054,6 +3082,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.10.6" diff --git a/compositor_chromium/chromium_sys/Cargo.toml b/compositor_chromium/chromium_sys/Cargo.toml index 719b01167..cdb8e3e4c 100644 --- a/compositor_chromium/chromium_sys/Cargo.toml +++ b/compositor_chromium/chromium_sys/Cargo.toml @@ -12,5 +12,6 @@ license = "BUSL-1.1" anyhow = "1.0.72" bindgen = "0.66.1" cmake = "0.1.50" +dirs = "5.0.1" fs_extra = "1.3.0" reqwest = { workspace = true } diff --git a/compositor_chromium/chromium_sys/build.rs b/compositor_chromium/chromium_sys/build.rs index 4d52b405c..d38a174cb 100644 --- a/compositor_chromium/chromium_sys/build.rs +++ b/compositor_chromium/chromium_sys/build.rs @@ -14,9 +14,10 @@ fn main() -> Result<()> { println!("cargo:rerun-if-env-changed=CEF_ROOT"); let out_dir = PathBuf::from(env::var("OUT_DIR")?); + let cache_dir = dirs::cache_dir().unwrap().join("live-compositor"); let cef_root = env::var("CEF_ROOT") .map(PathBuf::from) - .unwrap_or(out_dir.join("cef_root")); + .unwrap_or(cache_dir.join("cef_root")); if !cef_root.exists() { for i in 0..5 { @@ -157,9 +158,9 @@ fn download_cef(cef_root_path: &Path) -> Result<()> { let archive_name = "cef.tar.bz2"; let content = resp.bytes()?; - fs::write(download_path.join(archive_name), content)?; fs::create_dir_all(cef_root_path)?; + fs::write(download_path.join(archive_name), content)?; let tar_status = Command::new("tar") .args([ From 4bf6d0914141369f5618597b02783626bc4fa0b1 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Fri, 29 Nov 2024 13:37:06 +0100 Subject: [PATCH 48/51] initializing runtime once --- Cargo.lock | 1 + compositor_pipeline/src/pipeline.rs | 3 ++- generate/Cargo.toml | 1 + generate/src/compositor_instance.rs | 8 +++++--- .../examples/encoded_channel_output.rs | 6 ++++-- integration_tests/examples/raw_channel_input.rs | 2 ++ integration_tests/examples/raw_channel_output.rs | 2 ++ integration_tests/src/compositor_instance.rs | 8 +++++--- src/server.rs | 16 ++++++++++------ src/state.rs | 7 ++++++- 10 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06aeda741..b78821882 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1859,6 +1859,7 @@ dependencies = [ "serde", "serde_json", "socket2", + "tokio", "tracing", "tracing-subscriber 0.3.18", "webrtc-util 0.8.1", diff --git a/compositor_pipeline/src/pipeline.rs b/compositor_pipeline/src/pipeline.rs index fac91d36e..9ee2f1a3e 100644 --- a/compositor_pipeline/src/pipeline.rs +++ b/compositor_pipeline/src/pipeline.rs @@ -126,6 +126,7 @@ pub struct Options { pub wgpu_features: WgpuFeatures, pub load_system_fonts: Option, pub wgpu_ctx: Option, + pub tokio_rt: Arc, } #[derive(Clone)] @@ -197,7 +198,7 @@ impl Pipeline { output_framerate: opts.queue_options.output_framerate, download_dir: download_dir.into(), event_emitter, - tokio_rt: Arc::new(Runtime::new().map_err(InitPipelineError::CreateTokioRuntime)?), + tokio_rt: opts.tokio_rt, #[cfg(feature = "vk-video")] vulkan_ctx: preinitialized_ctx.and_then(|ctx| ctx.vulkan_ctx), }, diff --git a/generate/Cargo.toml b/generate/Cargo.toml index 313c5caee..fc1e3f922 100644 --- a/generate/Cargo.toml +++ b/generate/Cargo.toml @@ -32,3 +32,4 @@ pitch-detection = "0.3.0" rand = { workspace = true } schemars = { workspace = true} tracing-subscriber = { version = "0.3.18", features = ["json", "env-filter"] } +tokio = { workspace = true } diff --git a/generate/src/compositor_instance.rs b/generate/src/compositor_instance.rs index aa36656ce..89ef7d730 100644 --- a/generate/src/compositor_instance.rs +++ b/generate/src/compositor_instance.rs @@ -6,11 +6,12 @@ use std::{ env, sync::{ atomic::{AtomicU16, Ordering}, - OnceLock, + Arc, OnceLock, }, thread, time::{Duration, Instant}, }; +use tokio::runtime::Runtime; use tracing::info; pub struct CompositorInstance { @@ -37,12 +38,13 @@ impl CompositorInstance { info!("Starting LiveCompositor Integration Test with config:\n{config:#?}",); let (should_close_sender, should_close_receiver) = crossbeam_channel::bounded(1); - let (state, _event_loop) = ApiState::new(config).unwrap(); + let runtime = Arc::new(Runtime::new().unwrap()); + let (state, _event_loop) = ApiState::new(config, runtime.clone()).unwrap(); thread::Builder::new() .name("HTTP server startup thread".to_string()) .spawn(move || { - run_api(state, should_close_receiver).unwrap(); + run_api(state, runtime, should_close_receiver).unwrap(); }) .unwrap(); diff --git a/integration_tests/examples/encoded_channel_output.rs b/integration_tests/examples/encoded_channel_output.rs index d47fdbd5a..9795ac107 100644 --- a/integration_tests/examples/encoded_channel_output.rs +++ b/integration_tests/examples/encoded_channel_output.rs @@ -1,5 +1,5 @@ use core::panic; -use std::{fs::File, io::Write, path::PathBuf, time::Duration}; +use std::{fs::File, io::Write, path::PathBuf, sync::Arc, time::Duration}; use compositor_pipeline::{ audio_mixer::{AudioChannels, AudioMixingParams, InputParams, MixingStrategy}, @@ -24,6 +24,7 @@ use compositor_render::{ }; use integration_tests::examples::download_file; use live_compositor::{config::read_config, logger, state::ApiState}; +use tokio::runtime::Runtime; const BUNNY_FILE_URL: &str = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"; @@ -39,7 +40,8 @@ fn main() { let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); config.queue_options.ahead_of_time_processing = true; // no chromium support, so we can ignore _event_loop - let (state, _event_loop) = ApiState::new(config).unwrap_or_else(|err| { + let runtime = Arc::new(Runtime::new().unwrap()); + let (state, _event_loop) = ApiState::new(config, runtime).unwrap_or_else(|err| { panic!( "Failed to start compositor.\n{}", ErrorStack::new(&err).into_string() diff --git a/integration_tests/examples/raw_channel_input.rs b/integration_tests/examples/raw_channel_input.rs index 837785fd1..7dae31dce 100644 --- a/integration_tests/examples/raw_channel_input.rs +++ b/integration_tests/examples/raw_channel_input.rs @@ -32,6 +32,7 @@ use live_compositor::{ config::read_config, logger::{self}, }; +use tokio::runtime::Runtime; const VIDEO_OUTPUT_PORT: u16 = 8002; @@ -53,6 +54,7 @@ fn main() { wgpu_features: config.required_wgpu_features, load_system_fonts: Some(true), wgpu_ctx: Some(ctx), + tokio_rt: Arc::new(Runtime::new().unwrap()), }) .unwrap_or_else(|err| { panic!( diff --git a/integration_tests/examples/raw_channel_output.rs b/integration_tests/examples/raw_channel_output.rs index 11f0299ba..217f653a5 100644 --- a/integration_tests/examples/raw_channel_output.rs +++ b/integration_tests/examples/raw_channel_output.rs @@ -34,6 +34,7 @@ use live_compositor::{ config::read_config, logger::{self}, }; +use tokio::runtime::Runtime; const BUNNY_FILE_URL: &str = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"; @@ -66,6 +67,7 @@ fn main() { wgpu_features: config.required_wgpu_features, load_system_fonts: Some(true), wgpu_ctx: Some(ctx), + tokio_rt: Arc::new(Runtime::new().unwrap()), }) .unwrap_or_else(|err| { panic!( diff --git a/integration_tests/src/compositor_instance.rs b/integration_tests/src/compositor_instance.rs index 9f90e4244..8aedfa259 100644 --- a/integration_tests/src/compositor_instance.rs +++ b/integration_tests/src/compositor_instance.rs @@ -11,11 +11,12 @@ use std::{ env, sync::{ atomic::{AtomicU16, Ordering}, - OnceLock, + Arc, OnceLock, }, thread, time::{Duration, Instant}, }; +use tokio::runtime::Runtime; use tracing::info; pub struct CompositorInstance { @@ -41,12 +42,13 @@ impl CompositorInstance { info!("Starting LiveCompositor Integration Test with config:\n{config:#?}",); let (should_close_sender, should_close_receiver) = crossbeam_channel::bounded(1); - let (state, _event_loop) = ApiState::new(config).unwrap(); + let runtime = Arc::new(Runtime::new().unwrap()); + let (state, _event_loop) = ApiState::new(config, runtime.clone()).unwrap(); thread::Builder::new() .name("HTTP server startup thread".to_string()) .spawn(move || { - run_api(state, should_close_receiver).unwrap(); + run_api(state, runtime, should_close_receiver).unwrap(); }) .unwrap(); diff --git a/src/server.rs b/src/server.rs index f99ce60d0..9a63281c2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -4,7 +4,7 @@ use log::info; use signal_hook::{consts, iterator::Signals}; use tracing::error; -use std::{net::SocketAddr, process, thread}; +use std::{net::SocketAddr, process, sync::Arc, thread}; use tokio::runtime::Runtime; use crate::{config::read_config, logger::init_logger, routes::routes, state::ApiState}; @@ -15,7 +15,8 @@ pub fn run() { init_logger(config.logger.clone()); info!("Starting LiveCompositor with config:\n{:#?}", config); - let (state, event_loop) = ApiState::new(config).unwrap_or_else(|err| { + let runtime = Arc::new(Runtime::new().unwrap()); + let (state, event_loop) = ApiState::new(config, runtime.clone()).unwrap_or_else(|err| { panic!( "Failed to start event loop.\n{}", ErrorStack::new(&err).into_string() @@ -26,7 +27,7 @@ pub fn run() { .name("HTTP server startup thread".to_string()) .spawn(move || { let (_should_close_sender, should_close_receiver) = crossbeam_channel::bounded(1); - if let Err(err) = run_api(state, should_close_receiver) { + if let Err(err) = run_api(state, runtime, should_close_receiver) { error!(%err); process::exit(1); } @@ -44,9 +45,12 @@ pub fn run() { } } -pub fn run_api(state: ApiState, should_close: Receiver<()>) -> tokio::io::Result<()> { - let rt = Runtime::new().unwrap(); - rt.block_on(async { +pub fn run_api( + state: ApiState, + runtime: Arc, + should_close: Receiver<()>, +) -> tokio::io::Result<()> { + runtime.block_on(async { let port = state.config.api_port; let app = routes(state); let listener = diff --git a/src/state.rs b/src/state.rs index 60166a3a7..686a3bb6d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -5,6 +5,7 @@ use compositor_pipeline::{error::InitPipelineError, pipeline}; use compositor_render::EventLoop; use serde::Serialize; +use tokio::runtime::Runtime; use crate::config::Config; @@ -30,7 +31,10 @@ pub struct ApiState { } impl ApiState { - pub fn new(config: Config) -> Result<(ApiState, Arc), InitPipelineError> { + pub fn new( + config: Config, + runtime: Arc, + ) -> Result<(ApiState, Arc), InitPipelineError> { let Config { queue_options, stream_fallback_timeout, @@ -51,6 +55,7 @@ impl ApiState { wgpu_features: required_wgpu_features, wgpu_ctx: None, load_system_fonts: Some(true), + tokio_rt: runtime, })?; Ok(( ApiState { From 4ef38b089b8e1e27b88ad6867e428769b1c40a72 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Fri, 29 Nov 2024 16:24:39 +0100 Subject: [PATCH 49/51] temporary fix runtime lifetime errors --- generate/src/compositor_instance.rs | 2 +- .../examples/manual_graphics_initialization.rs | 6 ++++++ integration_tests/src/compositor_instance.rs | 2 +- snapshot_tests/snapshots | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/generate/src/compositor_instance.rs b/generate/src/compositor_instance.rs index 89ef7d730..8e5c961e5 100644 --- a/generate/src/compositor_instance.rs +++ b/generate/src/compositor_instance.rs @@ -44,7 +44,7 @@ impl CompositorInstance { thread::Builder::new() .name("HTTP server startup thread".to_string()) .spawn(move || { - run_api(state, runtime, should_close_receiver).unwrap(); + run_api(state, runtime.clone(), should_close_receiver).unwrap(); }) .unwrap(); diff --git a/integration_tests/examples/manual_graphics_initialization.rs b/integration_tests/examples/manual_graphics_initialization.rs index 2ae7e096f..db05380f1 100644 --- a/integration_tests/examples/manual_graphics_initialization.rs +++ b/integration_tests/examples/manual_graphics_initialization.rs @@ -1,6 +1,11 @@ // This example illustrates how to initialize a GraphicsContext separately to get access to a wgpu // instance, adapter, queue and device. +#[cfg(target_os = "linux")] +use std::sync::Arc; +#[cfg(target_os = "linux")] +use tokio::runtime::Runtime; + #[cfg(target_os = "linux")] fn main() { use compositor_pipeline::{ @@ -34,6 +39,7 @@ fn main() { output_sample_rate: config.output_sample_rate, wgpu_features: config.required_wgpu_features, load_system_fonts: Some(true), + tokio_rt: Arc::new(Runtime::new().unwrap()), }) .unwrap(); } diff --git a/integration_tests/src/compositor_instance.rs b/integration_tests/src/compositor_instance.rs index 8aedfa259..bb3967ff6 100644 --- a/integration_tests/src/compositor_instance.rs +++ b/integration_tests/src/compositor_instance.rs @@ -48,7 +48,7 @@ impl CompositorInstance { thread::Builder::new() .name("HTTP server startup thread".to_string()) .spawn(move || { - run_api(state, runtime, should_close_receiver).unwrap(); + run_api(state, runtime.clone(), should_close_receiver).unwrap(); }) .unwrap(); diff --git a/snapshot_tests/snapshots b/snapshot_tests/snapshots index ac634ad38..57fbdbaa6 160000 --- a/snapshot_tests/snapshots +++ b/snapshot_tests/snapshots @@ -1 +1 @@ -Subproject commit ac634ad382cc6e6417167db3c768fe750e9b0240 +Subproject commit 57fbdbaa6cf83e4cfe907c04af409221e5a1d566 From ea0fd09cd37f6efae0f639c5a3f0e22bd453e4a5 Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Fri, 29 Nov 2024 16:48:47 +0100 Subject: [PATCH 50/51] try to extend ci disk space --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index da74a8535..e5eaf67fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -50,6 +50,9 @@ jobs: EOF git submodule update --init + - name: ๐Ÿงน cargo clean + run : cargo clean + - name: ๐Ÿ“ Rust cache uses: Swatinem/rust-cache@v2 From d1c6d77f39b9b7eb4cd5f03b3b43c2ad2895c5fc Mon Sep 17 00:00:00 2001 From: bartosz rzepa Date: Mon, 2 Dec 2024 15:42:04 +0100 Subject: [PATCH 51/51] remove new ci jobs, cleanup --- .github/workflows/test.yml | 8 -------- .../src/pipeline/output/whip/establish_peer_connection.rs | 1 - 2 files changed, 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e5eaf67fe..e3938507a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,11 +14,6 @@ jobs: check: runs-on: ubuntu-24.04 steps: - - name: Maximize build space - uses: easimon/maximize-build-space@master - with: - remove-dotnet: 'true' - - name: ๐Ÿ›  Install system dependencies run: | set -e @@ -50,9 +45,6 @@ jobs: EOF git submodule update --init - - name: ๐Ÿงน cargo clean - run : cargo clean - - name: ๐Ÿ“ Rust cache uses: Swatinem/rust-cache@v2 diff --git a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs index 098cfd1b2..9b074bac0 100644 --- a/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs +++ b/compositor_pipeline/src/pipeline/output/whip/establish_peer_connection.rs @@ -67,7 +67,6 @@ pub async fn connect( .create_offer(None) .await .map_err(WhipError::OfferCreationError)?; - error!("offer: {offer:?}"); let endpoint_url = Url::parse(&whip_ctx.options.endpoint_url) .map_err(|e| WhipError::InvalidEndpointUrl(e, whip_ctx.options.endpoint_url.clone()))?;