diff --git a/Cargo.lock b/Cargo.lock
index 1a2227d..40947db 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -180,6 +180,12 @@ dependencies = [
"alloc-stdlib",
]
+[[package]]
+name = "build-print"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8e6738dfb11354886f890621b4a34c0b177f75538023f7100b608ab9adbd66b"
+
[[package]]
name = "bumpalo"
version = "3.19.0"
@@ -2418,6 +2424,7 @@ dependencies = [
name = "trusted-server-js"
version = "0.1.0"
dependencies = [
+ "build-print",
"hex",
"sha2 0.10.9",
"which",
diff --git a/Cargo.toml b/Cargo.toml
index 9545c84..387fe3b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,7 @@ debug = 1
async-trait = "0.1"
base64 = "0.22"
brotli = "8.0"
+build-print = "1.0.1"
bytes = "1.11"
chacha20poly1305 = "0.10"
chrono = "0.4.42"
diff --git a/SEQUENCE.md b/SEQUENCE.md
index 235ef0e..c4bc28d 100644
--- a/SEQUENCE.md
+++ b/SEQUENCE.md
@@ -1,4 +1,4 @@
-# 🛡️ Trusted Server — First-Party Proxying Flow
+# 🛡️ Trusted Server — Proxying Flow
## 🔄 System Flow Diagram
@@ -80,7 +80,7 @@ sequenceDiagram
activate TS
activate PBS
activate DSP
- JS->>TS: GET /first-party/ad
(with signals)
+ JS->>TS: GET /ad/render
(with signals)
TS->>PBS: POST /openrtb2/auction
(OpenRTB 2.x)
PBS->>DSP: POST bid request
DSP-->>PBS: 200 bid response
diff --git a/crates/common/README.md b/crates/common/README.md
index 4fa5fad..50ad8bc 100644
--- a/crates/common/README.md
+++ b/crates/common/README.md
@@ -1,6 +1,6 @@
# trusted-server-common
-Utilities shared by Trusted Server components. This crate contains HTML/CSS rewriting helpers used to normalize ad creative assets to first‑party proxy endpoints.
+Utilities shared by Trusted Server components. This crate contains HTML/CSS rewriting helpers used to normalize ad creative assets to proxy endpoints.
## Creative Rewriting
diff --git a/crates/common/src/backend.rs b/crates/common/src/backend.rs
index ba5a1c8..2dbedb0 100644
--- a/crates/common/src/backend.rs
+++ b/crates/common/src/backend.rs
@@ -6,15 +6,42 @@ use url::Url;
use crate::error::TrustedServerError;
+/// Compute the Host header value for a backend request.
+///
+/// For standard ports (443 for HTTPS, 80 for HTTP), returns just the hostname.
+/// For non-standard ports, returns "hostname:port" to ensure backends that
+/// generate URLs based on the Host header include the port.
+///
+/// This fixes the issue where backends behind reverse proxies (like Caddy)
+/// would generate URLs without the port when the Host header didn't include it.
+#[inline]
+fn compute_host_header(scheme: &str, host: &str, port: u16) -> String {
+ let is_https = scheme.eq_ignore_ascii_case("https");
+ let default_port = if is_https { 443 } else { 80 };
+ if port != default_port {
+ format!("{}:{}", host, port)
+ } else {
+ host.to_string()
+ }
+}
+
/// Ensure a dynamic backend exists for the given origin and return its name.
///
/// The backend name is derived from the scheme and `host[:port]` to avoid collisions across
/// http/https or different ports. If a backend with the derived name already exists,
/// this function logs and reuses it.
+///
+/// # Arguments
+///
+/// * `scheme` - The URL scheme ("http" or "https")
+/// * `host` - The hostname
+/// * `port` - Optional port number
+/// * `certificate_check` - If true, enables TLS certificate verification (default for production)
pub fn ensure_origin_backend(
scheme: &str,
host: &str,
port: Option,
+ certificate_check: bool,
) -> Result> {
if host.is_empty() {
return Err(Report::new(TrustedServerError::Proxy {
@@ -32,20 +59,33 @@ pub fn ensure_origin_backend(
let host_with_port = format!("{}:{}", host, target_port);
// Name: iframe___ (sanitize '.' and ':')
+ // Include cert setting in name to avoid reusing a backend with different cert settings
let name_base = format!("{}_{}_{}", scheme, host, target_port);
- let backend_name = format!("backend_{}", name_base.replace(['.', ':'], "_"));
+ let cert_suffix = if certificate_check { "" } else { "_nocert" };
+ let backend_name = format!(
+ "backend_{}{}",
+ name_base.replace(['.', ':'], "_"),
+ cert_suffix
+ );
+
+ let host_header = compute_host_header(scheme, host, target_port);
// Target base is host[:port]; SSL is enabled only for https scheme
let mut builder = Backend::builder(&backend_name, &host_with_port)
- .override_host(host)
+ .override_host(&host_header)
.connect_timeout(Duration::from_secs(1))
.first_byte_timeout(Duration::from_secs(15))
.between_bytes_timeout(Duration::from_secs(10));
if scheme.eq_ignore_ascii_case("https") {
- builder = builder
- .enable_ssl()
- .sni_hostname(host)
- .check_certificate(host);
+ builder = builder.enable_ssl().sni_hostname(host);
+ if certificate_check {
+ builder = builder.check_certificate(host);
+ } else {
+ log::warn!(
+ "INSECURE: certificate check disabled for backend: {}",
+ backend_name
+ );
+ }
log::info!("enable ssl for backend: {}", backend_name);
}
@@ -75,7 +115,10 @@ pub fn ensure_origin_backend(
}
}
-pub fn ensure_backend_from_url(origin_url: &str) -> Result> {
+pub fn ensure_backend_from_url(
+ origin_url: &str,
+ certificate_check: bool,
+) -> Result> {
let parsed_url = Url::parse(origin_url).change_context(TrustedServerError::Proxy {
message: format!("Invalid origin_url: {}", origin_url),
})?;
@@ -88,22 +131,69 @@ pub fn ensure_backend_from_url(origin_url: &str) -> Result String {
// Image src + data-src
element!("img", |el| {
if let Some(src) = el.get_attribute("src") {
+ log::debug!("creative rewrite: img src input = {}", src);
if let Some(p) = proxy_if_abs(settings, &src) {
+ log::debug!("creative rewrite: img src output = {}", p);
let _ = el.set_attribute("src", &p);
}
}
@@ -539,6 +542,43 @@ mod tests {
assert_eq!(to_abs("mailto:test@example.com", &settings), None);
}
+ #[test]
+ fn to_abs_preserves_port_in_protocol_relative() {
+ let settings = crate::test_support::tests::create_test_settings();
+ // Protocol-relative URL with explicit port should preserve the port
+ assert_eq!(
+ to_abs("//cdn.example.com:8080/asset.js", &settings),
+ Some("https://cdn.example.com:8080/asset.js".to_string())
+ );
+ assert_eq!(
+ to_abs("//cdn.example.com:9443/img.png", &settings),
+ Some("https://cdn.example.com:9443/img.png".to_string())
+ );
+ }
+
+ #[test]
+ fn rewrite_creative_preserves_non_standard_port() {
+ // Verify creative rewriting preserves non-standard ports in URLs
+ let settings = crate::test_support::tests::create_test_settings();
+ let html = r#"
+
+
+
+
+
+
+
+"#;
+ let out = rewrite_creative_html(html, &settings);
+
+ // Port 9443 should be preserved (URL-encoded as %3A9443)
+ assert!(
+ out.contains("cdn.example.com%3A9443"),
+ "Port 9443 should be preserved in rewritten URLs: {}",
+ out
+ );
+ }
+
#[test]
fn rewrite_style_urls_handles_absolute_and_relative() {
let settings = crate::test_support::tests::create_test_settings();
diff --git a/crates/common/src/fastly_storage.rs b/crates/common/src/fastly_storage.rs
index c4a8241..0136326 100644
--- a/crates/common/src/fastly_storage.rs
+++ b/crates/common/src/fastly_storage.rs
@@ -84,7 +84,7 @@ impl FastlyApiClient {
}
pub fn from_secret_store(store_name: &str, key_name: &str) -> Result {
- ensure_backend_from_url("https://api.fastly.com").map_err(|e| {
+ ensure_backend_from_url("https://api.fastly.com", true).map_err(|e| {
TrustedServerError::Configuration {
message: format!("Failed to ensure API backend: {}", e),
}
diff --git a/crates/common/src/html_processor.rs b/crates/common/src/html_processor.rs
index 1803436..c7cfe25 100644
--- a/crates/common/src/html_processor.rs
+++ b/crates/common/src/html_processor.rs
@@ -1,4 +1,4 @@
-//! Simplified HTML processor that combines URL replacement and Prebid injection
+//! Simplified HTML processor that combines URL replacement and integration injection
//!
//! This module provides a StreamProcessor implementation for HTML content.
use std::cell::Cell;
@@ -189,10 +189,26 @@ pub fn create_html_processor(config: HtmlProcessorConfig) -> impl StreamProcesso
// Inject unified tsjs bundle once at the start of
element!("head", {
let injected_tsjs = injected_tsjs.clone();
+ let integrations = integration_registry.clone();
+ let patterns = patterns.clone();
+ let document_state = document_state.clone();
move |el| {
if !injected_tsjs.get() {
- let loader = tsjs::unified_script_tag();
- el.prepend(&loader, ContentType::Html);
+ let mut snippet = String::new();
+ let ctx = IntegrationHtmlContext {
+ request_host: &patterns.request_host,
+ request_scheme: &patterns.request_scheme,
+ origin_host: &patterns.origin_host,
+ document_state: &document_state,
+ };
+ // First inject the unified TSJS bundle (defines tsjs.setConfig, etc.)
+ snippet.push_str(&tsjs::unified_script_tag());
+ // Then add any integration-specific head inserts (e.g., mode config)
+ // These run after the bundle so tsjs API is available
+ for insert in integrations.head_inserts(&ctx) {
+ snippet.push_str(&insert);
+ }
+ el.prepend(&snippet, ContentType::Html);
injected_tsjs.set(true);
}
Ok(())
@@ -454,8 +470,10 @@ pub fn create_html_processor(config: HtmlProcessorConfig) -> impl StreamProcesso
#[cfg(test)]
mod tests {
use super::*;
+ use crate::integrations::prebid::{tsjs_config_script_tag, Mode as PrebidMode};
use crate::integrations::{
AttributeRewriteAction, IntegrationAttributeContext, IntegrationAttributeRewriter,
+ IntegrationHeadInjector,
};
use crate::streaming_processor::{Compression, PipelineConfig, StreamingPipeline};
use crate::test_support::tests::create_test_settings;
@@ -582,6 +600,59 @@ mod tests {
assert_eq!(config.request_scheme, "https");
}
+ #[test]
+ fn injects_tsjs_config_when_mode_set() {
+ struct ModeInjector;
+
+ impl IntegrationHeadInjector for ModeInjector {
+ fn integration_id(&self) -> &'static str {
+ "mode-injector"
+ }
+
+ fn head_inserts(&self, _ctx: &IntegrationHtmlContext<'_>) -> Vec {
+ vec![tsjs_config_script_tag(PrebidMode::Auction)]
+ }
+ }
+
+ let mut config = create_test_config();
+ config.integrations = IntegrationRegistry::from_rewriters_with_head_injectors(
+ Vec::new(),
+ Vec::new(),
+ vec![Arc::new(ModeInjector)],
+ );
+ let processor = create_html_processor(config);
+
+ let pipeline_config = PipelineConfig {
+ input_compression: Compression::None,
+ output_compression: Compression::None,
+ chunk_size: 8192,
+ };
+ let mut pipeline = StreamingPipeline::new(pipeline_config, processor);
+
+ let html = "";
+ let mut output = Vec::new();
+ pipeline
+ .process(Cursor::new(html.as_bytes()), &mut output)
+ .unwrap();
+ let result = String::from_utf8(output).unwrap();
+
+ let config_pos = result.find("setConfig({mode:\"auction\"})");
+ let script_pos = result.find("trustedserver-js");
+ assert!(
+ config_pos.is_some(),
+ "should inject tsjs mode config when configured"
+ );
+ assert!(
+ script_pos.is_some(),
+ "should inject unified tsjs script when processing HTML"
+ );
+ // Config must come AFTER the bundle so tsjs.setConfig is defined when called
+ assert!(
+ config_pos.unwrap() > script_pos.unwrap(),
+ "should place tsjs config after the unified bundle (so tsjs.setConfig is available)"
+ );
+ }
+
#[test]
fn test_real_publisher_html() {
// Test with publisher HTML from test_publisher.html
diff --git a/crates/common/src/http_util.rs b/crates/common/src/http_util.rs
index 132d6bd..c830aab 100644
--- a/crates/common/src/http_util.rs
+++ b/crates/common/src/http_util.rs
@@ -6,6 +6,157 @@ use sha2::{Digest, Sha256};
use crate::settings::Settings;
+/// Extracted request information for host rewriting.
+///
+/// This struct captures the effective host and scheme from an incoming request,
+/// accounting for proxy headers like `X-Forwarded-Host` and `X-Forwarded-Proto`.
+#[derive(Debug, Clone)]
+pub struct RequestInfo {
+ /// The effective host for URL rewriting (from Forwarded, X-Forwarded-Host, or Host header)
+ pub host: String,
+ /// The effective scheme (from TLS detection, Forwarded, X-Forwarded-Proto, or default)
+ pub scheme: String,
+}
+
+impl RequestInfo {
+ /// Extract request info from a Fastly request.
+ ///
+ /// Host priority:
+ /// 1. `Forwarded` header (RFC 7239, `host=...`)
+ /// 2. `X-Forwarded-Host` header (for chained proxy setups)
+ /// 3. `Host` header
+ ///
+ /// Scheme priority:
+ /// 1. Fastly SDK TLS detection (most reliable)
+ /// 2. `Forwarded` header (RFC 7239, `proto=https`)
+ /// 3. `X-Forwarded-Proto` header
+ /// 4. `Fastly-SSL` header
+ /// 5. Default to `http`
+ pub fn from_request(req: &Request) -> Self {
+ let host = extract_request_host(req);
+ let scheme = detect_request_scheme(req);
+
+ Self { host, scheme }
+ }
+}
+
+fn extract_request_host(req: &Request) -> String {
+ req.get_header("forwarded")
+ .and_then(|h| h.to_str().ok())
+ .and_then(|value| parse_forwarded_param(value, "host"))
+ .or_else(|| {
+ req.get_header("x-forwarded-host")
+ .and_then(|h| h.to_str().ok())
+ .and_then(parse_list_header_value)
+ })
+ .or_else(|| req.get_header(header::HOST).and_then(|h| h.to_str().ok()))
+ .unwrap_or_default()
+ .to_string()
+}
+
+fn parse_forwarded_param<'a>(forwarded: &'a str, param: &str) -> Option<&'a str> {
+ for entry in forwarded.split(',') {
+ for part in entry.split(';') {
+ let mut iter = part.splitn(2, '=');
+ let key = iter.next().unwrap_or("").trim();
+ let value = iter.next().unwrap_or("").trim();
+ if key.is_empty() || value.is_empty() {
+ continue;
+ }
+ if key.eq_ignore_ascii_case(param) {
+ let value = strip_quotes(value);
+ if !value.is_empty() {
+ return Some(value);
+ }
+ }
+ }
+ }
+ None
+}
+
+fn parse_list_header_value(value: &str) -> Option<&str> {
+ value
+ .split(',')
+ .map(|part| part.trim())
+ .find(|part| !part.is_empty())
+ .map(strip_quotes)
+ .filter(|part| !part.is_empty())
+}
+
+fn strip_quotes(value: &str) -> &str {
+ let trimmed = value.trim();
+ if trimmed.len() >= 2 && trimmed.starts_with('"') && trimmed.ends_with('"') {
+ &trimmed[1..trimmed.len() - 1]
+ } else {
+ trimmed
+ }
+}
+
+fn normalize_scheme(value: &str) -> Option {
+ let scheme = value.trim().to_ascii_lowercase();
+ if scheme == "https" || scheme == "http" {
+ Some(scheme)
+ } else {
+ None
+ }
+}
+
+/// Detects the request scheme (HTTP or HTTPS) using Fastly SDK methods and headers.
+///
+/// Tries multiple methods in order of reliability:
+/// 1. Fastly SDK TLS detection methods (most reliable)
+/// 2. Forwarded header (RFC 7239)
+/// 3. X-Forwarded-Proto header
+/// 4. Fastly-SSL header (least reliable, can be spoofed)
+/// 5. Default to HTTP
+fn detect_request_scheme(req: &Request) -> String {
+ // 1. First try Fastly SDK's built-in TLS detection methods
+ if let Some(tls_protocol) = req.get_tls_protocol() {
+ log::debug!("TLS protocol detected: {}", tls_protocol);
+ return "https".to_string();
+ }
+
+ // Also check TLS cipher - if present, connection is HTTPS
+ if req.get_tls_cipher_openssl_name().is_some() {
+ log::debug!("TLS cipher detected, using HTTPS");
+ return "https".to_string();
+ }
+
+ // 2. Try the Forwarded header (RFC 7239)
+ if let Some(forwarded) = req.get_header("forwarded") {
+ if let Ok(forwarded_str) = forwarded.to_str() {
+ if let Some(proto) = parse_forwarded_param(forwarded_str, "proto") {
+ if let Some(scheme) = normalize_scheme(proto) {
+ return scheme;
+ }
+ }
+ }
+ }
+
+ // 3. Try X-Forwarded-Proto header
+ if let Some(proto) = req.get_header("x-forwarded-proto") {
+ if let Ok(proto_str) = proto.to_str() {
+ if let Some(value) = parse_list_header_value(proto_str) {
+ if let Some(scheme) = normalize_scheme(value) {
+ return scheme;
+ }
+ }
+ }
+ }
+
+ // 4. Check Fastly-SSL header (can be spoofed by clients, use as last resort)
+ if let Some(ssl) = req.get_header("fastly-ssl") {
+ if let Ok(ssl_str) = ssl.to_str() {
+ if ssl_str == "1" || ssl_str.to_lowercase() == "true" {
+ return "https".to_string();
+ }
+ }
+ }
+
+ // Default to HTTP
+ "http".to_string()
+}
+
/// Build a static text response with strong ETag and standard caching headers.
/// Handles If-None-Match to return 304 when appropriate.
pub fn serve_static_with_etag(body: &str, req: &Request, content_type: &str) -> Response {
@@ -166,4 +317,118 @@ mod tests {
&t1
));
}
+
+ // RequestInfo tests
+
+ #[test]
+ fn test_request_info_from_host_header() {
+ let mut req = Request::new(fastly::http::Method::GET, "https://test.example.com/page");
+ req.set_header("host", "test.example.com");
+
+ let info = RequestInfo::from_request(&req);
+ assert_eq!(
+ info.host, "test.example.com",
+ "Host should use Host header when forwarded headers are missing"
+ );
+ // No TLS or forwarded headers, defaults to http.
+ assert_eq!(
+ info.scheme, "http",
+ "Scheme should default to http without TLS or forwarded headers"
+ );
+ }
+
+ #[test]
+ fn test_request_info_x_forwarded_host_precedence() {
+ let mut req = Request::new(fastly::http::Method::GET, "https://test.example.com/page");
+ req.set_header("host", "internal-proxy.local");
+ req.set_header("x-forwarded-host", "public.example.com, proxy.local");
+
+ let info = RequestInfo::from_request(&req);
+ assert_eq!(
+ info.host, "public.example.com",
+ "Host should prefer X-Forwarded-Host over Host"
+ );
+ }
+
+ #[test]
+ fn test_request_info_scheme_from_x_forwarded_proto() {
+ let mut req = Request::new(fastly::http::Method::GET, "https://test.example.com/page");
+ req.set_header("host", "test.example.com");
+ req.set_header("x-forwarded-proto", "https, http");
+
+ let info = RequestInfo::from_request(&req);
+ assert_eq!(
+ info.scheme, "https",
+ "Scheme should prefer the first X-Forwarded-Proto value"
+ );
+
+ // Test HTTP
+ let mut req = Request::new(fastly::http::Method::GET, "http://test.example.com/page");
+ req.set_header("host", "test.example.com");
+ req.set_header("x-forwarded-proto", "http");
+
+ let info = RequestInfo::from_request(&req);
+ assert_eq!(
+ info.scheme, "http",
+ "Scheme should use the X-Forwarded-Proto value when present"
+ );
+ }
+
+ #[test]
+ fn request_info_forwarded_header_precedence() {
+ // Forwarded header takes precedence over X-Forwarded-Proto
+ let mut req = Request::new(fastly::http::Method::GET, "https://test.example.com/page");
+ req.set_header(
+ "forwarded",
+ "for=192.0.2.60;proto=\"HTTPS\";host=\"public.example.com:443\"",
+ );
+ req.set_header("host", "internal-proxy.local");
+ req.set_header("x-forwarded-host", "proxy.local");
+ req.set_header("x-forwarded-proto", "http");
+
+ let info = RequestInfo::from_request(&req);
+ assert_eq!(
+ info.host, "public.example.com:443",
+ "Host should prefer Forwarded host over X-Forwarded-Host"
+ );
+ assert_eq!(
+ info.scheme, "https",
+ "Scheme should prefer Forwarded proto over X-Forwarded-Proto"
+ );
+ }
+
+ #[test]
+ fn test_request_info_scheme_from_fastly_ssl() {
+ let mut req = Request::new(fastly::http::Method::GET, "https://test.example.com/page");
+ req.set_header("fastly-ssl", "1");
+
+ let info = RequestInfo::from_request(&req);
+ assert_eq!(
+ info.scheme, "https",
+ "Scheme should fall back to Fastly-SSL when other signals are missing"
+ );
+ }
+
+ #[test]
+ fn test_request_info_chained_proxy_scenario() {
+ // Simulate: Client (HTTPS) -> Proxy A -> Trusted Server (HTTP internally)
+ // Proxy A sets X-Forwarded-Host and X-Forwarded-Proto
+ let mut req = Request::new(
+ fastly::http::Method::GET,
+ "http://trusted-server.internal/page",
+ );
+ req.set_header("host", "trusted-server.internal");
+ req.set_header("x-forwarded-host", "public.example.com");
+ req.set_header("x-forwarded-proto", "https");
+
+ let info = RequestInfo::from_request(&req);
+ assert_eq!(
+ info.host, "public.example.com",
+ "Host should use X-Forwarded-Host in chained proxy scenarios"
+ );
+ assert_eq!(
+ info.scheme, "https",
+ "Scheme should use X-Forwarded-Proto in chained proxy scenarios"
+ );
+ }
}
diff --git a/crates/common/src/integrations/didomi.rs b/crates/common/src/integrations/didomi.rs
index 6c1a2ed..ab601ad 100644
--- a/crates/common/src/integrations/didomi.rs
+++ b/crates/common/src/integrations/didomi.rs
@@ -202,7 +202,7 @@ impl IntegrationProxy for DidomiIntegration {
let target_url = self
.build_target_url(base_origin, consent_path, req.get_query_str())
.change_context(Self::error("Failed to build Didomi target URL"))?;
- let backend_name = ensure_backend_from_url(base_origin)
+ let backend_name = ensure_backend_from_url(base_origin, true)
.change_context(Self::error("Failed to configure Didomi backend"))?;
let mut proxy_req = Request::new(req.get_method().clone(), &target_url);
diff --git a/crates/common/src/integrations/gam.rs b/crates/common/src/integrations/gam.rs
new file mode 100644
index 0000000..ae39ccd
--- /dev/null
+++ b/crates/common/src/integrations/gam.rs
@@ -0,0 +1,157 @@
+//! GAM (Google Ad Manager) Interceptor Integration
+//!
+//! This integration forces Prebid creatives to render when GAM doesn't have
+//! matching line items configured. It's a client-side only integration that
+//! works by intercepting GPT's `slotRenderEnded` event.
+//!
+//! # Configuration
+//!
+//! ```toml
+//! [integrations.gam]
+//! enabled = true
+//! bidders = ["mocktioneer"] # Only intercept these bidders, empty = all
+//! force_render = false # Force render even if GAM has a line item
+//! ```
+//!
+//! # Environment Variables
+//!
+//! ```bash
+//! TRUSTED_SERVER__INTEGRATIONS__GAM__ENABLED=true
+//! TRUSTED_SERVER__INTEGRATIONS__GAM__BIDDERS="mocktioneer,appnexus"
+//! TRUSTED_SERVER__INTEGRATIONS__GAM__FORCE_RENDER=false
+//! ```
+
+use serde::{Deserialize, Serialize};
+use validator::Validate;
+
+use crate::settings::IntegrationConfig;
+
+use super::{IntegrationHeadInjector, IntegrationHtmlContext, IntegrationRegistration};
+
+const GAM_INTEGRATION_ID: &str = "gam";
+
+/// GAM interceptor configuration.
+#[derive(Debug, Clone, Default, Deserialize, Serialize, Validate)]
+pub struct GamIntegrationConfig {
+ /// Enable the GAM interceptor. Defaults to false.
+ #[serde(default)]
+ pub enabled: bool,
+
+ /// Only intercept bids from these bidders. Empty = all bidders.
+ #[serde(default, deserialize_with = "crate::settings::vec_from_seq_or_map")]
+ pub bidders: Vec,
+
+ /// Force render Prebid creative even if GAM returned a line item.
+ #[serde(default)]
+ pub force_render: bool,
+}
+
+impl IntegrationConfig for GamIntegrationConfig {
+ fn is_enabled(&self) -> bool {
+ self.enabled
+ }
+}
+
+/// Generate the JavaScript config script tag for GAM integration.
+/// Sets window.tsGamConfig which is picked up by the GAM integration on init.
+pub fn gam_config_script_tag(config: &GamIntegrationConfig) -> String {
+ let bidders_json = if config.bidders.is_empty() {
+ "[]".to_string()
+ } else {
+ format!(
+ "[{}]",
+ config
+ .bidders
+ .iter()
+ .map(|b| format!("\"{}\"", b))
+ .collect::>()
+ .join(",")
+ )
+ };
+
+ format!(
+ r#""#,
+ bidders_json, config.force_render
+ )
+}
+
+pub struct GamIntegration {
+ config: GamIntegrationConfig,
+}
+
+impl GamIntegration {
+ pub fn new(config: GamIntegrationConfig) -> Self {
+ Self { config }
+ }
+}
+
+impl IntegrationHeadInjector for GamIntegration {
+ fn integration_id(&self) -> &'static str {
+ GAM_INTEGRATION_ID
+ }
+
+ fn head_inserts(&self, _ctx: &IntegrationHtmlContext<'_>) -> Vec {
+ vec![gam_config_script_tag(&self.config)]
+ }
+}
+
+/// Register the GAM integration if enabled.
+pub fn register(settings: &crate::settings::Settings) -> Option {
+ use std::sync::Arc;
+
+ let config: GamIntegrationConfig =
+ settings.integrations.get_typed(GAM_INTEGRATION_ID).ok()??;
+
+ log::info!(
+ "GAM integration enabled: bidders={:?}, force_render={}",
+ config.bidders,
+ config.force_render
+ );
+
+ let integration = Arc::new(GamIntegration::new(config));
+
+ Some(
+ IntegrationRegistration::builder(GAM_INTEGRATION_ID)
+ .with_head_injector(integration)
+ .build(),
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn gam_config_script_tag_with_bidders() {
+ let config = GamIntegrationConfig {
+ enabled: true,
+ bidders: vec!["mocktioneer".to_string(), "appnexus".to_string()],
+ force_render: false,
+ };
+ let tag = gam_config_script_tag(&config);
+ assert!(tag.contains("window.tsGamConfig="));
+ assert!(tag.contains("enabled:true"));
+ assert!(tag.contains(r#"bidders:["mocktioneer","appnexus"]"#));
+ assert!(tag.contains("forceRender:false"));
+ }
+
+ #[test]
+ fn gam_config_script_tag_empty_bidders() {
+ let config = GamIntegrationConfig {
+ enabled: true,
+ bidders: vec![],
+ force_render: true,
+ };
+ let tag = gam_config_script_tag(&config);
+ assert!(tag.contains("bidders:[]"));
+ assert!(tag.contains("forceRender:true"));
+ }
+
+ #[test]
+ fn gam_config_disabled_by_default() {
+ let config = GamIntegrationConfig::default();
+ assert!(!config.enabled);
+ assert!(config.bidders.is_empty());
+ assert!(!config.force_render);
+ }
+}
diff --git a/crates/common/src/integrations/lockr.rs b/crates/common/src/integrations/lockr.rs
index 014e226..84a0335 100644
--- a/crates/common/src/integrations/lockr.rs
+++ b/crates/common/src/integrations/lockr.rs
@@ -141,7 +141,7 @@ impl LockrIntegration {
lockr_req.set_header(header::USER_AGENT, "TrustedServer/1.0");
lockr_req.set_header(header::ACCEPT, "application/javascript, */*");
- let backend_name = ensure_backend_from_url(sdk_url)
+ let backend_name = ensure_backend_from_url(sdk_url, true)
.change_context(Self::error("Failed to determine backend for SDK fetch"))?;
let mut lockr_response =
@@ -235,7 +235,7 @@ impl LockrIntegration {
}
// Get backend and forward
- let backend_name = ensure_backend_from_url(&self.config.api_endpoint)
+ let backend_name = ensure_backend_from_url(&self.config.api_endpoint, true)
.change_context(Self::error("Failed to determine backend for API proxy"))?;
let response = match target_req.send(backend_name) {
@@ -265,6 +265,7 @@ impl LockrIntegration {
header::ACCEPT_LANGUAGE,
header::ACCEPT_ENCODING,
header::COOKIE,
+ header::ORIGIN,
];
for header_name in &headers_to_copy {
diff --git a/crates/common/src/integrations/mod.rs b/crates/common/src/integrations/mod.rs
index 076d5cb..8e7e940 100644
--- a/crates/common/src/integrations/mod.rs
+++ b/crates/common/src/integrations/mod.rs
@@ -3,6 +3,7 @@
use crate::settings::Settings;
pub mod didomi;
+pub mod gam;
pub mod lockr;
pub mod nextjs;
pub mod permutive;
@@ -13,9 +14,9 @@ pub mod testlight;
pub use registry::{
AttributeRewriteAction, AttributeRewriteOutcome, IntegrationAttributeContext,
IntegrationAttributeRewriter, IntegrationDocumentState, IntegrationEndpoint,
- IntegrationHtmlContext, IntegrationHtmlPostProcessor, IntegrationMetadata, IntegrationProxy,
- IntegrationRegistration, IntegrationRegistrationBuilder, IntegrationRegistry,
- IntegrationScriptContext, IntegrationScriptRewriter, ScriptRewriteAction,
+ IntegrationHeadInjector, IntegrationHtmlContext, IntegrationHtmlPostProcessor,
+ IntegrationMetadata, IntegrationProxy, IntegrationRegistration, IntegrationRegistrationBuilder,
+ IntegrationRegistry, IntegrationScriptContext, IntegrationScriptRewriter, ScriptRewriteAction,
};
type IntegrationBuilder = fn(&Settings) -> Option;
@@ -28,5 +29,6 @@ pub(crate) fn builders() -> &'static [IntegrationBuilder] {
permutive::register,
lockr::register,
didomi::register,
+ gam::register,
]
}
diff --git a/crates/common/src/integrations/permutive.rs b/crates/common/src/integrations/permutive.rs
index 6d565e8..986948c 100644
--- a/crates/common/src/integrations/permutive.rs
+++ b/crates/common/src/integrations/permutive.rs
@@ -118,7 +118,7 @@ impl PermutiveIntegration {
permutive_req.set_header(header::USER_AGENT, "TrustedServer/1.0");
permutive_req.set_header(header::ACCEPT, "application/javascript, */*");
- let backend_name = ensure_backend_from_url(&sdk_url)
+ let backend_name = ensure_backend_from_url(&sdk_url, true)
.change_context(Self::error("Failed to determine backend for SDK fetch"))?;
let mut permutive_response =
@@ -208,7 +208,7 @@ impl PermutiveIntegration {
}
// Get backend and forward
- let backend_name = ensure_backend_from_url(&self.config.api_endpoint)
+ let backend_name = ensure_backend_from_url(&self.config.api_endpoint, true)
.change_context(Self::error("Failed to determine backend for API proxy"))?;
let response = target_req
@@ -277,7 +277,7 @@ impl PermutiveIntegration {
}
// Get backend and forward
- let backend_name = ensure_backend_from_url(&self.config.secure_signals_endpoint)
+ let backend_name = ensure_backend_from_url(&self.config.secure_signals_endpoint, true)
.change_context(Self::error(
"Failed to determine backend for Secure Signals proxy",
))?;
@@ -342,7 +342,7 @@ impl PermutiveIntegration {
}
// Get backend and forward
- let backend_name = ensure_backend_from_url("https://events.permutive.app")
+ let backend_name = ensure_backend_from_url("https://events.permutive.app", true)
.change_context(Self::error("Failed to determine backend for Events proxy"))?;
let response = target_req
@@ -405,7 +405,7 @@ impl PermutiveIntegration {
}
// Get backend and forward
- let backend_name = ensure_backend_from_url("https://sync.permutive.com")
+ let backend_name = ensure_backend_from_url("https://sync.permutive.com", true)
.change_context(Self::error("Failed to determine backend for Sync proxy"))?;
let response = target_req
@@ -460,7 +460,7 @@ impl PermutiveIntegration {
self.copy_request_headers(&req, &mut target_req);
// Get backend and forward
- let backend_name = ensure_backend_from_url("https://cdn.permutive.com")
+ let backend_name = ensure_backend_from_url("https://cdn.permutive.com", true)
.change_context(Self::error("Failed to determine backend for CDN proxy"))?;
let response = target_req
diff --git a/crates/common/src/integrations/prebid.rs b/crates/common/src/integrations/prebid.rs
index 51b1b9f..485cafd 100644
--- a/crates/common/src/integrations/prebid.rs
+++ b/crates/common/src/integrations/prebid.rs
@@ -2,13 +2,12 @@ use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
-use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use error_stack::{Report, ResultExt};
use fastly::http::{header, Method, StatusCode};
use fastly::{Request, Response};
use serde::{Deserialize, Serialize};
-use serde_json::{json, Value as Json, Value as JsonValue};
-use url::Url;
+use serde_json::{Value as Json, Value as JsonValue};
+use url::{form_urlencoded, Url};
use validator::Validate;
use crate::backend::ensure_backend_from_url;
@@ -16,18 +15,50 @@ use crate::constants::{HEADER_SYNTHETIC_FRESH, HEADER_SYNTHETIC_TRUSTED_SERVER};
use crate::creative;
use crate::error::TrustedServerError;
use crate::geo::GeoInfo;
+use crate::http_util::compute_encrypted_sha256_token;
+use crate::http_util::RequestInfo;
use crate::integrations::{
AttributeRewriteAction, IntegrationAttributeContext, IntegrationAttributeRewriter,
- IntegrationEndpoint, IntegrationProxy, IntegrationRegistration,
+ IntegrationEndpoint, IntegrationHeadInjector, IntegrationHtmlContext, IntegrationProxy,
+ IntegrationRegistration,
+};
+use crate::openrtb::{
+ Banner, Device, Format, Geo, Imp, ImpExt, OpenRtbRequest, OpenRtbResponse, PrebidImpExt, Regs,
+ RegsExt, RequestExt, Site, TrustedServerExt, User, UserExt,
};
-use crate::openrtb::{Banner, Format, Imp, ImpExt, OpenRtbRequest, PrebidImpExt, Site};
use crate::request_signing::RequestSigner;
use crate::settings::{IntegrationConfig, Settings};
use crate::synthetic::{generate_synthetic_id, get_or_generate_synthetic_id};
const PREBID_INTEGRATION_ID: &str = "prebid";
-const ROUTE_FIRST_PARTY_AD: &str = "/first-party/ad";
-const ROUTE_THIRD_PARTY_AD: &str = "/third-party/ad";
+const ROUTE_RENDER: &str = "/ad/render";
+const ROUTE_AUCTION: &str = "/ad/auction";
+
+/// Mode determines how TSJS handles ad requests.
+///
+/// - `Render`: Uses iframe-based server-side rendering.
+/// The server handles the full auction and returns ready-to-display HTML.
+/// - `Auction`: Uses client-side OpenRTB auctions.
+/// Clients (for example, Prebid.js) send OpenRTB to /ad/auction.
+#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "lowercase")]
+pub enum Mode {
+ Render,
+ Auction,
+}
+
+/// Generate TSJS config script tag based on mode.
+/// This script runs after the unified TSJS bundle has loaded.
+pub fn tsjs_config_script_tag(mode: Mode) -> String {
+ match mode {
+ Mode::Render => {
+ r#""#.to_string()
+ }
+ Mode::Auction => {
+ r#""#.to_string()
+ }
+ }
+}
#[derive(Debug, Clone, Deserialize, Serialize, Validate)]
pub struct PrebidIntegrationConfig {
@@ -41,12 +72,19 @@ pub struct PrebidIntegrationConfig {
deserialize_with = "crate::settings::vec_from_seq_or_map"
)]
pub bidders: Vec,
- #[serde(default = "default_auto_configure")]
- pub auto_configure: bool,
#[serde(default)]
pub debug: bool,
+ /// Optional default mode to enqueue when injecting the unified bundle.
#[serde(default)]
- pub script_handler: Option,
+ pub mode: Option,
+ /// Patterns to match Prebid script URLs for serving empty JS.
+ /// Supports suffix matching (e.g., "/prebid.min.js" matches any path ending with that)
+ /// and wildcard patterns (e.g., "/static/prebid/*" matches paths under that prefix).
+ #[serde(
+ default = "default_script_patterns",
+ deserialize_with = "crate::settings::vec_from_seq_or_map"
+ )]
+ pub script_patterns: Vec,
}
impl IntegrationConfig for PrebidIntegrationConfig {
@@ -63,12 +101,29 @@ fn default_bidders() -> Vec {
vec!["mocktioneer".to_string()]
}
-fn default_auto_configure() -> bool {
+fn default_enabled() -> bool {
true
}
-fn default_enabled() -> bool {
- true
+/// Default suffixes that identify Prebid scripts
+const PREBID_SCRIPT_SUFFIXES: &[&str] = &[
+ "/prebid.js",
+ "/prebid.min.js",
+ "/prebidjs.js",
+ "/prebidjs.min.js",
+];
+
+fn default_script_patterns() -> Vec {
+ // Default patterns to intercept Prebid scripts and serve empty JS
+ // - Exact paths like "/prebid.min.js" match only that path
+ // - Wildcard paths like "/static/prebid/*" match anything under that prefix
+ // and are filtered by PREBID_SCRIPT_SUFFIXES in matches_script_pattern()
+ vec![
+ "/prebid.js".to_string(),
+ "/prebid.min.js".to_string(),
+ "/prebidjs.js".to_string(),
+ "/prebidjs.min.js".to_string(),
+ ]
}
#[derive(Debug, Deserialize)]
@@ -118,6 +173,92 @@ impl PrebidIntegration {
Arc::new(Self { config })
}
+ fn matches_script_url(&self, attr_value: &str) -> bool {
+ let trimmed = attr_value.trim();
+ let without_query = trimmed.split(['?', '#']).next().unwrap_or(trimmed);
+
+ if self.matches_script_pattern(without_query) {
+ return true;
+ }
+
+ if !without_query.starts_with('/')
+ && !without_query.starts_with("//")
+ && !without_query.contains("://")
+ {
+ let with_slash = format!("/{without_query}");
+ if self.matches_script_pattern(&with_slash) {
+ return true;
+ }
+ }
+
+ let parsed = if without_query.starts_with("//") {
+ Url::parse(&format!("https:{without_query}"))
+ } else {
+ Url::parse(without_query)
+ };
+
+ parsed
+ .ok()
+ .is_some_and(|url| self.matches_script_pattern(url.path()))
+ }
+
+ fn matches_script_pattern(&self, path: &str) -> bool {
+ // Normalize path to lowercase for case-insensitive matching
+ let path_lower = path.to_ascii_lowercase();
+
+ log::debug!(
+ "matches_script_pattern: path='{}', patterns={:?}",
+ path,
+ self.config.script_patterns
+ );
+
+ // Check if path matches any configured pattern
+ for pattern in &self.config.script_patterns {
+ let pattern_lower = pattern.to_ascii_lowercase();
+
+ // Check for wildcard patterns: /* or {*name}
+ if pattern_lower.ends_with("/*") || pattern_lower.contains("{*") {
+ // Extract prefix before the wildcard
+ let prefix = if pattern_lower.ends_with("/*") {
+ &pattern_lower[..pattern_lower.len() - 1] // Remove trailing *
+ } else {
+ // Find {* and extract prefix before it
+ pattern_lower.split("{*").next().unwrap_or("")
+ };
+
+ log::debug!(
+ " wildcard pattern='{}', prefix='{}', path_starts_with_prefix={}",
+ pattern,
+ prefix,
+ path_lower.starts_with(prefix)
+ );
+
+ if path_lower.starts_with(prefix) {
+ // Check if it ends with a known Prebid script suffix
+ let has_suffix = PREBID_SCRIPT_SUFFIXES
+ .iter()
+ .any(|suffix| path_lower.ends_with(suffix));
+ log::debug!(
+ " checking suffixes: path ends with known suffix={}",
+ has_suffix
+ );
+ if has_suffix {
+ return true;
+ }
+ }
+ } else {
+ // Exact match or suffix match
+ let matches = path_lower.ends_with(&pattern_lower);
+ log::debug!(" exact/suffix pattern='{}', matches={}", pattern, matches);
+ if matches {
+ return true;
+ }
+ }
+ }
+ log::debug!(" no pattern matched, returning false");
+ false
+ }
+
fn error(message: impl Into) -> TrustedServerError {
TrustedServerError::Integration {
integration: PREBID_INTEGRATION_ID.to_string(),
@@ -125,62 +266,35 @@ impl PrebidIntegration {
}
}
- async fn handle_third_party_ad(
+ async fn handle_auction(
&self,
settings: &Settings,
- mut req: Request,
+ req: Request,
) -> Result> {
- let body: AdRequest = serde_json::from_slice(&req.take_body_bytes()).change_context(
- TrustedServerError::Prebid {
- message: "Failed to parse tsjs auction request".to_string(),
- },
- )?;
-
- log::info!("/third-party/ad: received {} adUnits", body.ad_units.len());
- for unit in &body.ad_units {
- if let Some(mt) = &unit.media_types {
- if let Some(banner) = &mt.banner {
- log::debug!("unit={} sizes={:?}", unit.code, banner.sizes);
- }
- }
- }
-
- let openrtb = build_openrtb_from_ts(&body, settings, &self.config);
- if let Ok(preview) = serde_json::to_string(&openrtb) {
- log::debug!(
- "OpenRTB payload (truncated): {}",
- &preview.chars().take(512).collect::()
- );
- }
-
- req.set_body_json(&openrtb)
- .change_context(TrustedServerError::Prebid {
- message: "Failed to set OpenRTB body".to_string(),
- })?;
-
handle_prebid_auction(settings, req, &self.config).await
}
fn handle_script_handler(&self) -> Result> {
- let body = "// Script overridden by Trusted Server\n";
-
+ // Serve empty JS - Prebid.js is already bundled in the unified TSJS bundle
+ // that gets injected into the page. We just need to prevent the original
+ // Prebid script from loading/executing.
Ok(Response::from_status(StatusCode::OK)
.with_header(
header::CONTENT_TYPE,
"application/javascript; charset=utf-8",
)
.with_header(header::CACHE_CONTROL, "public, max-age=31536000, immutable")
- .with_body(body))
+ .with_body("/* prebid.js replaced by tsjs-unified */"))
}
- async fn handle_first_party_ad(
+ async fn handle_render(
&self,
settings: &Settings,
mut req: Request,
) -> Result> {
let url = req.get_url_str();
let parsed = Url::parse(url).change_context(TrustedServerError::Prebid {
- message: "Invalid first-party serve-ad URL".to_string(),
+ message: "Invalid render URL".to_string(),
})?;
let qp = parsed
.query_pairs()
@@ -257,7 +371,8 @@ pub fn register(settings: &Settings) -> Option {
Some(
IntegrationRegistration::builder(PREBID_INTEGRATION_ID)
.with_proxy(integration.clone())
- .with_attribute_rewriter(integration)
+ .with_attribute_rewriter(integration.clone())
+ .with_head_injector(integration)
.build(),
)
}
@@ -270,14 +385,15 @@ impl IntegrationProxy for PrebidIntegration {
fn routes(&self) -> Vec {
let mut routes = vec![
- IntegrationEndpoint::get(ROUTE_FIRST_PARTY_AD),
- IntegrationEndpoint::post(ROUTE_THIRD_PARTY_AD),
+ IntegrationEndpoint::get(ROUTE_RENDER),
+ IntegrationEndpoint::post(ROUTE_AUCTION),
];
- if let Some(script_path) = &self.config.script_handler {
- // We need to leak the string to get a 'static str for IntegrationEndpoint
- // This is safe because the config lives for the lifetime of the application
- let static_path: &'static str = Box::leak(script_path.clone().into_boxed_str());
+ // Register routes for script removal patterns
+ // Patterns can be exact paths (e.g., "/prebid.min.js") or use matchit wildcards
+ // (e.g., "/static/prebid/{*rest}")
+ for pattern in &self.config.script_patterns {
+ let static_path: &'static str = Box::leak(pattern.clone().into_boxed_str());
routes.push(IntegrationEndpoint::get(static_path));
}
@@ -292,19 +408,34 @@ impl IntegrationProxy for PrebidIntegration {
let path = req.get_path().to_string();
let method = req.get_method().clone();
+ log::debug!(
+ "Prebid handle: method={}, path='{}', script_patterns={:?}",
+ method,
+ path,
+ self.config.script_patterns
+ );
+
match method {
- Method::GET if self.config.script_handler.as_ref() == Some(&path) => {
+ Method::GET if path == ROUTE_RENDER => self.handle_render(settings, req).await,
+ Method::POST if path == ROUTE_AUCTION => self.handle_auction(settings, req).await,
+ // Serve empty JS for any other GET request that was routed here by matchit
+ // (i.e., matched one of our script_patterns wildcards).
+ // Prebid.js is already bundled in tsjs-unified, so we just need to
+ // prevent the original script from loading.
+ Method::GET => {
+ log::debug!("Prebid: serving empty JS stub for path '{}'", path);
self.handle_script_handler()
}
- Method::GET if path == ROUTE_FIRST_PARTY_AD => {
- self.handle_first_party_ad(settings, req).await
- }
- Method::POST if path == ROUTE_THIRD_PARTY_AD => {
- self.handle_third_party_ad(settings, req).await
+ _ => {
+ log::debug!(
+ "Prebid: no handler matched for {} '{}', returning error",
+ method,
+ path
+ );
+ Err(Report::new(Self::error(format!(
+ "Unsupported Prebid route: {path}"
+ ))))
}
- _ => Err(Report::new(Self::error(format!(
- "Unsupported Prebid route: {path}"
- )))),
}
}
}
@@ -315,7 +446,7 @@ impl IntegrationAttributeRewriter for PrebidIntegration {
}
fn handles_attribute(&self, attribute: &str) -> bool {
- self.config.auto_configure && matches!(attribute, "src" | "href")
+ matches!(attribute, "src" | "href")
}
fn rewrite(
@@ -324,7 +455,7 @@ impl IntegrationAttributeRewriter for PrebidIntegration {
attr_value: &str,
_ctx: &IntegrationAttributeContext<'_>,
) -> AttributeRewriteAction {
- if self.config.auto_configure && is_prebid_script_url(attr_value) {
+ if self.matches_script_url(attr_value) {
AttributeRewriteAction::remove_element()
} else {
AttributeRewriteAction::keep()
@@ -332,6 +463,22 @@ impl IntegrationAttributeRewriter for PrebidIntegration {
}
}
+impl IntegrationHeadInjector for PrebidIntegration {
+ fn integration_id(&self) -> &'static str {
+ PREBID_INTEGRATION_ID
+ }
+
+ fn head_inserts(&self, _ctx: &IntegrationHtmlContext<'_>) -> Vec {
+ // Only inject TSJS mode config if mode is set
+ // The Prebid bundle (served via script interception) already has s2sConfig built-in
+ // GAM config is now handled by the separate GAM integration
+ self.config
+ .mode
+ .map(|mode| vec![tsjs_config_script_tag(mode)])
+ .unwrap_or_default()
+ }
+}
+
fn build_openrtb_from_ts(
req: &AdRequest,
settings: &Settings,
@@ -370,10 +517,15 @@ fn build_openrtb_from_ts(
Imp {
id: unit.code.clone(),
- banner: Some(Banner { format: formats }),
+ banner: Some(Banner {
+ format: formats,
+ extra: HashMap::new(),
+ }),
ext: Some(ImpExt {
- prebid: PrebidImpExt { bidder },
+ prebid: Some(PrebidImpExt { bidder }),
+ extra: HashMap::new(),
}),
+ extra: HashMap::new(),
}
})
.collect();
@@ -384,20 +536,16 @@ fn build_openrtb_from_ts(
site: Some(Site {
domain: Some(settings.publisher.domain.clone()),
page: Some(format!("https://{}", settings.publisher.domain)),
+ extra: HashMap::new(),
}),
+ user: None,
+ regs: None,
+ device: None,
+ ext: None,
+ extra: HashMap::new(),
}
}
-fn is_prebid_script_url(url: &str) -> bool {
- let lower = url.to_ascii_lowercase();
- let without_query = lower.split('?').next().unwrap_or("");
- let filename = without_query.rsplit('/').next().unwrap_or("");
- matches!(
- filename,
- "prebid.js" | "prebid.min.js" | "prebidjs.js" | "prebidjs.min.js"
- )
-}
-
async fn pbs_auction_for_get(
settings: &Settings,
req: Request,
@@ -438,11 +586,10 @@ async fn handle_prebid_auction(
config: &PrebidIntegrationConfig,
) -> Result> {
log::info!("Handling Prebid auction request");
- let mut openrtb_request: Json = serde_json::from_slice(&req.take_body_bytes()).change_context(
- TrustedServerError::Prebid {
+ let mut openrtb_request: OpenRtbRequest = serde_json::from_slice(&req.take_body_bytes())
+ .change_context(TrustedServerError::Prebid {
message: "Failed to parse OpenRTB request".to_string(),
- },
- )?;
+ })?;
let synthetic_id = get_or_generate_synthetic_id(settings, &req)?;
let fresh_id = generate_synthetic_id(settings, &req)?;
@@ -460,6 +607,7 @@ async fn handle_prebid_auction(
settings,
&req,
)?;
+ override_prebid_bidders(&mut openrtb_request, &config.bidders);
let mut pbs_req = Request::new(
Method::POST,
@@ -473,7 +621,8 @@ async fn handle_prebid_auction(
})?;
log::info!("Sending request to Prebid Server");
- let backend_name = ensure_backend_from_url(&config.server_url)?;
+ let backend_name =
+ ensure_backend_from_url(&config.server_url, settings.proxy.certificate_check)?;
let mut pbs_response =
pbs_req
.send(backend_name)
@@ -483,18 +632,21 @@ async fn handle_prebid_auction(
if pbs_response.get_status().is_success() {
let response_body = pbs_response.take_body_bytes();
- match serde_json::from_slice::(&response_body) {
- Ok(mut response_json) => {
- let request_host = get_request_host(&req);
- let request_scheme = get_request_scheme(&req);
- transform_prebid_response(&mut response_json, &request_host, &request_scheme)?;
-
- let transformed_body = serde_json::to_vec(&response_json).change_context(
- TrustedServerError::Prebid {
- message: "Failed to serialize transformed response".to_string(),
- },
+ match serde_json::from_slice::(&response_body) {
+ Ok(mut response) => {
+ let request_info = RequestInfo::from_request(&req);
+ transform_prebid_response(
+ &mut response,
+ settings,
+ &request_info.host,
+ &request_info.scheme,
)?;
+ let transformed_body =
+ serde_json::to_vec(&response).change_context(TrustedServerError::Prebid {
+ message: "Failed to serialize transformed response".to_string(),
+ })?;
+
Ok(Response::from_status(StatusCode::OK)
.with_header(header::CONTENT_TYPE, "application/json")
.with_header("X-Synthetic-ID", &synthetic_id)
@@ -512,154 +664,264 @@ async fn handle_prebid_auction(
}
fn enhance_openrtb_request(
- request: &mut Json,
+ request: &mut OpenRtbRequest,
synthetic_id: &str,
fresh_id: &str,
settings: &Settings,
req: &Request,
) -> Result<(), Report> {
- if !request["user"].is_object() {
- request["user"] = json!({});
- }
- request["user"]["id"] = json!(synthetic_id);
-
- if !request["user"]["ext"].is_object() {
- request["user"]["ext"] = json!({});
- }
- request["user"]["ext"]["synthetic_fresh"] = json!(fresh_id);
+ let user = request.user.get_or_insert_with(User::default);
+ user.id = Some(synthetic_id.to_string());
+ let user_ext = user.ext.get_or_insert_with(UserExt::default);
+ user_ext.synthetic_fresh = Some(fresh_id.to_string());
if req.get_header("Sec-GPC").is_some() {
- if !request["regs"].is_object() {
- request["regs"] = json!({});
- }
- if !request["regs"]["ext"].is_object() {
- request["regs"]["ext"] = json!({});
- }
- request["regs"]["ext"]["us_privacy"] = json!("1YYN");
+ let regs = request.regs.get_or_insert_with(Regs::default);
+ let regs_ext = regs.ext.get_or_insert_with(RegsExt::default);
+ regs_ext.us_privacy = Some("1YYN".to_string());
}
if let Some(geo_info) = GeoInfo::from_request(req) {
- let geo_obj = json!({
- "type": 2,
- "country": geo_info.country,
- "city": geo_info.city,
- "region": geo_info.region,
- });
-
- if !request["device"].is_object() {
- request["device"] = json!({});
- }
- request["device"]["geo"] = geo_obj;
+ let device = request.device.get_or_insert_with(Device::default);
+ let geo = device.geo.get_or_insert_with(Geo::default);
+ geo.geo_type = Some(2);
+ geo.country = Some(geo_info.country);
+ geo.city = Some(geo_info.city);
+ geo.region = geo_info.region;
}
- if !request["site"].is_object() {
- request["site"] = json!({
- "domain": settings.publisher.domain,
- "page": format!("https://{}", settings.publisher.domain),
+ if request.site.is_none() {
+ request.site = Some(Site {
+ domain: Some(settings.publisher.domain.clone()),
+ page: Some(format!("https://{}", settings.publisher.domain)),
+ extra: HashMap::new(),
});
}
if let Some(request_signing_config) = &settings.request_signing {
- if request_signing_config.enabled && request["id"].is_string() {
- if !request["ext"].is_object() {
- request["ext"] = json!({});
- }
-
- let id = request["id"]
- .as_str()
- .expect("should have string id when is_string checked");
+ if request_signing_config.enabled {
let signer = RequestSigner::from_config()?;
- let signature = signer.sign(id.as_bytes())?;
- request["ext"]["trusted_server"] = json!({
- "signature": signature,
- "kid": signer.kid
- });
+ let signature = signer.sign(request.id.as_bytes())?;
+ let ext = request.ext.get_or_insert_with(RequestExt::default);
+ let trusted = ext
+ .trusted_server
+ .get_or_insert_with(TrustedServerExt::default);
+ trusted.signature = Some(signature);
+ trusted.kid = Some(signer.kid);
}
}
Ok(())
}
+/// Override bidders in the OpenRTB request with the server-configured bidder list.
+///
+/// This replaces any client-provided bidder configuration with the bidders specified
+/// in `[integrations.prebid].bidders` from trusted-server.toml. This ensures that:
+///
+/// 1. Only approved bidders are used (security/compliance control)
+/// 2. Bidder params are managed server-side, not exposed to clients
+/// 3. The publisher's Prebid.js config doesn't need bidder-specific setup
+///
+/// Note: Client-provided bidder params (e.g., `appnexus: { placementId: '123' }`)
+/// are intentionally stripped. Bidder params should be configured in Prebid Server
+/// or through trusted-server's bidder configuration.
+fn override_prebid_bidders(request: &mut OpenRtbRequest, bidders: &[String]) {
+ let bidder_map = bidders
+ .iter()
+ .map(|bidder| (bidder.clone(), JsonValue::Object(serde_json::Map::new())))
+ .collect::>();
+
+ log::debug!(
+ "Overriding OpenRTB bidders from settings: count={}",
+ bidder_map.len()
+ );
+
+ for imp in &mut request.imp {
+ let ext = imp.ext.get_or_insert_with(|| ImpExt {
+ prebid: None,
+ extra: HashMap::new(),
+ });
+ let prebid = ext.prebid.get_or_insert_with(PrebidImpExt::default);
+ prebid.bidder = bidder_map.clone();
+ }
+}
+
fn transform_prebid_response(
- response: &mut Json,
+ response: &mut OpenRtbResponse,
+ settings: &Settings,
request_host: &str,
request_scheme: &str,
) -> Result<(), Report> {
- if let Some(seatbids) = response["seatbid"].as_array_mut() {
- for seatbid in seatbids {
- if let Some(bids) = seatbid["bid"].as_array_mut() {
- for bid in bids {
- if let Some(adm) = bid["adm"].as_str() {
- bid["adm"] = json!(rewrite_ad_markup(adm, request_host, request_scheme));
- }
+ let Some(seatbids) = response.seatbid.as_mut() else {
+ return Ok(());
+ };
- if let Some(nurl) = bid["nurl"].as_str() {
- bid["nurl"] = json!(make_first_party_proxy_url(
- nurl,
- request_host,
- request_scheme,
- "track"
- ));
- }
+ for seatbid in seatbids {
+ let Some(bids) = seatbid.bid.as_mut() else {
+ continue;
+ };
- if let Some(burl) = bid["burl"].as_str() {
- bid["burl"] = json!(make_first_party_proxy_url(
- burl,
- request_host,
- request_scheme,
- "track"
- ));
- }
+ for bid in bids {
+ if let Some(adm) = bid.adm.as_deref() {
+ if looks_like_html(adm) {
+ bid.adm = Some(creative::rewrite_creative_html(adm, settings));
}
}
+
+ if let Some(nurl) = bid.nurl.as_deref() {
+ bid.nurl = Some(first_party_proxy_url(
+ settings,
+ request_host,
+ request_scheme,
+ nurl,
+ ));
+ }
+
+ if let Some(burl) = bid.burl.as_deref() {
+ bid.burl = Some(first_party_proxy_url(
+ settings,
+ request_host,
+ request_scheme,
+ burl,
+ ));
+ }
}
}
Ok(())
}
-fn rewrite_ad_markup(markup: &str, request_host: &str, request_scheme: &str) -> String {
- let mut content = markup.to_string();
- let cdn_patterns = vec![
- ("https://cdn.adsrvr.org", "adsrvr"),
- ("https://ib.adnxs.com", "adnxs"),
- ("https://rtb.openx.net", "openx"),
- ("https://as.casalemedia.com", "casale"),
- ("https://eus.rubiconproject.com", "rubicon"),
- ];
-
- for (cdn_url, cdn_name) in cdn_patterns {
- if content.contains(cdn_url) {
- let proxy_base = format!(
- "{}://{}/ad-proxy/{}",
- request_scheme, request_host, cdn_name
- );
- content = content.replace(cdn_url, &proxy_base);
- }
+fn first_party_proxy_url(
+ settings: &Settings,
+ request_host: &str,
+ request_scheme: &str,
+ clear_url: &str,
+) -> String {
+ let trimmed = clear_url.trim();
+ let Some(abs) = normalize_absolute_url(trimmed, request_scheme) else {
+ return clear_url.to_string();
+ };
+ if is_excluded_by_domain(settings, &abs) {
+ return clear_url.to_string();
}
-
- content = content.replace(
- "//cdn.adsrvr.org",
- &format!("//{}/ad-proxy/adsrvr", request_host),
- );
- content = content.replace(
- "//ib.adnxs.com",
- &format!("//{}/ad-proxy/adnxs", request_host),
- );
- content
+ let signed = creative::build_proxy_url(settings, &abs);
+ let proxy_path = if signed == abs {
+ build_proxy_path_for_raw_url(settings, &abs)
+ } else {
+ signed
+ };
+ absolutize_proxy_path(settings, request_host, request_scheme, proxy_path)
}
-fn make_first_party_proxy_url(
- third_party_url: &str,
+fn absolutize_proxy_path(
+ settings: &Settings,
request_host: &str,
request_scheme: &str,
- proxy_type: &str,
+ proxy_path: String,
) -> String {
- let encoded = BASE64.encode(third_party_url.as_bytes());
- format!(
- "{}://{}/ad-proxy/{}/{}",
- request_scheme, request_host, proxy_type, encoded
- )
+ if proxy_path.starts_with('/') {
+ let host = if request_host.is_empty() {
+ settings.publisher.domain.as_str()
+ } else {
+ request_host
+ };
+ if host.is_empty() {
+ return proxy_path;
+ }
+ return format!("{request_scheme}://{host}{proxy_path}");
+ }
+ proxy_path
+}
+
+fn looks_like_html(markup: &str) -> bool {
+ let trimmed = markup.trim_start();
+ if trimmed.is_empty() {
+ return false;
+ }
+ let lower = trimmed.to_ascii_lowercase();
+ if !lower.starts_with('<') {
+ return false;
+ }
+ if lower.starts_with(" Option {
+ let lower = url.to_ascii_lowercase();
+ if lower.starts_with("http://") || lower.starts_with("https://") {
+ return Some(url.to_string());
+ }
+ if url.starts_with("//") {
+ return Some(format!("{}:{}", request_scheme, url));
+ }
+ None
+}
+
+fn is_excluded_by_domain(settings: &Settings, abs_url: &str) -> bool {
+ if settings.rewrite.exclude_domains.is_empty() {
+ return false;
+ }
+ if let Ok(parsed) = Url::parse(abs_url) {
+ return settings.rewrite.is_excluded(parsed.as_str());
+ }
+ let Some(host) = extract_host(abs_url) else {
+ return false;
+ };
+ let check = format!("https://{}", host);
+ settings.rewrite.is_excluded(&check)
+}
+
+fn extract_host(abs_url: &str) -> Option<&str> {
+ let lower = abs_url.to_ascii_lowercase();
+ let rest = if lower.starts_with("https://") {
+ &abs_url["https://".len()..]
+ } else if lower.starts_with("http://") {
+ &abs_url["http://".len()..]
+ } else {
+ return None;
+ };
+ let host = rest.split(['/', '?', '#']).next().unwrap_or("");
+ if host.is_empty() {
+ return None;
+ }
+ Some(host)
+}
+
+fn build_proxy_path_for_raw_url(settings: &Settings, clear_url: &str) -> String {
+ let token = compute_encrypted_sha256_token(settings, clear_url);
+ let mut qs = form_urlencoded::Serializer::new(String::new());
+ qs.append_pair("tsurl", clear_url);
+ qs.append_pair("tstoken", &token);
+ format!("/first-party/proxy?{}", qs.finish())
}
fn copy_request_headers(from: &Request, to: &mut Request) {
@@ -678,38 +940,14 @@ fn copy_request_headers(from: &Request, to: &mut Request) {
}
}
-fn get_request_host(req: &Request) -> String {
- req.get_header(header::HOST)
- .and_then(|h| h.to_str().ok())
- .unwrap_or("")
- .to_string()
-}
-
-fn get_request_scheme(req: &Request) -> String {
- if req.get_tls_protocol().is_some() || req.get_tls_cipher_openssl_name().is_some() {
- return "https".to_string();
- }
-
- if let Some(proto) = req.get_header("X-Forwarded-Proto") {
- if let Ok(proto_str) = proto.to_str() {
- return proto_str.to_lowercase();
- }
- }
-
- "https".to_string()
-}
-
#[cfg(test)]
mod tests {
use super::*;
- use crate::html_processor::{create_html_processor, HtmlProcessorConfig};
- use crate::integrations::{AttributeRewriteAction, IntegrationRegistry};
+ use crate::integrations::{AttributeRewriteAction, IntegrationAttributeContext};
use crate::settings::Settings;
- use crate::streaming_processor::{Compression, PipelineConfig, StreamingPipeline};
use crate::test_support::tests::crate_test_settings_str;
use fastly::http::Method;
use serde_json::json;
- use std::io::Cursor;
fn make_settings() -> Settings {
Settings::from_toml(&crate_test_settings_str()).expect("should parse settings")
@@ -721,30 +959,15 @@ mod tests {
server_url: "https://prebid.example".to_string(),
timeout_ms: 1000,
bidders: vec!["exampleBidder".to_string()],
- auto_configure: true,
debug: false,
- script_handler: None,
+ mode: None,
+ script_patterns: default_script_patterns(),
}
}
- fn config_from_settings(
- settings: &Settings,
- registry: &IntegrationRegistry,
- ) -> HtmlProcessorConfig {
- HtmlProcessorConfig::from_settings(
- settings,
- registry,
- "origin.example.com",
- "test.example.com",
- "https",
- )
- }
-
#[test]
fn attribute_rewriter_removes_prebid_scripts() {
- let integration = PrebidIntegration {
- config: base_config(),
- };
+ let integration = PrebidIntegration::new(base_config());
let ctx = IntegrationAttributeContext {
attribute_name: "src",
request_host: "pub.example",
@@ -753,17 +976,21 @@ mod tests {
};
let rewritten = integration.rewrite("src", "https://cdn.prebid.org/prebid.min.js", &ctx);
- assert!(matches!(rewritten, AttributeRewriteAction::RemoveElement));
+ assert!(
+ matches!(rewritten, AttributeRewriteAction::RemoveElement),
+ "Prebid script tags should be removed"
+ );
let untouched = integration.rewrite("src", "https://cdn.example.com/app.js", &ctx);
- assert!(matches!(untouched, AttributeRewriteAction::Keep));
+ assert!(
+ matches!(untouched, AttributeRewriteAction::Keep),
+ "Non-Prebid scripts should remain"
+ );
}
#[test]
- fn attribute_rewriter_handles_query_strings_and_links() {
- let integration = PrebidIntegration {
- config: base_config(),
- };
+ fn attribute_rewriter_handles_query_strings() {
+ let integration = PrebidIntegration::new(base_config());
let ctx = IntegrationAttributeContext {
attribute_name: "href",
request_host: "pub.example",
@@ -773,146 +1000,225 @@ mod tests {
let rewritten =
integration.rewrite("href", "https://cdn.prebid.org/prebid.js?v=1.2.3", &ctx);
- assert!(matches!(rewritten, AttributeRewriteAction::RemoveElement));
+ assert!(
+ matches!(rewritten, AttributeRewriteAction::RemoveElement),
+ "Prebid links with query strings should be removed"
+ );
}
#[test]
- fn html_processor_keeps_prebid_scripts_when_auto_config_disabled() {
- let html = r#"
-
-
- "#;
-
- let mut settings = make_settings();
- settings
- .integrations
- .insert_config(
- "prebid",
- &json!({
- "enabled": true,
- "server_url": "https://test-prebid.com/openrtb2/auction",
- "timeout_ms": 1000,
- "bidders": ["mocktioneer"],
- "auto_configure": false,
- "debug": false
- }),
- )
- .expect("should update prebid config");
- let registry = IntegrationRegistry::new(&settings);
- let config = config_from_settings(&settings, ®istry);
- let processor = create_html_processor(config);
- let pipeline_config = PipelineConfig {
- input_compression: Compression::None,
- output_compression: Compression::None,
- chunk_size: 8192,
+ fn attribute_rewriter_matches_wildcard_patterns() {
+ let mut config = base_config();
+ config.script_patterns = vec!["/static/prebid/*".to_string()];
+ let integration = PrebidIntegration::new(config);
+ let ctx = IntegrationAttributeContext {
+ attribute_name: "src",
+ request_host: "pub.example",
+ request_scheme: "https",
+ origin_host: "origin.example",
};
- let mut pipeline = StreamingPipeline::new(pipeline_config, processor);
- let mut output = Vec::new();
- let result = pipeline.process(Cursor::new(html.as_bytes()), &mut output);
- assert!(result.is_ok());
- let processed = String::from_utf8_lossy(&output);
- assert!(
- processed.contains("tsjs-unified"),
- "Unified bundle should be injected"
+ let rewritten = integration.rewrite(
+ "src",
+ "https://cdn.example.com/static/prebid/v1/prebid.min.js",
+ &ctx,
);
assert!(
- processed.contains("prebid.min.js"),
- "Prebid script should remain when auto-config is disabled"
+ matches!(rewritten, AttributeRewriteAction::RemoveElement),
+ "Wildcard patterns should match prebid assets on full URLs"
);
+
+ let rewritten_relative = integration.rewrite("src", "static/prebid/prebid.min.js", &ctx);
assert!(
- processed.contains("cdn.prebid.org/prebid.js"),
- "Prebid preload should remain when auto-config is disabled"
+ matches!(rewritten_relative, AttributeRewriteAction::RemoveElement),
+ "Wildcard patterns should match relative paths without a leading slash"
);
}
#[test]
- fn html_processor_removes_prebid_scripts_when_auto_config_enabled() {
- let html = r#"
-
-
- "#;
-
- let mut settings = make_settings();
- settings
- .integrations
- .insert_config(
- "prebid",
- &json!({
- "enabled": true,
- "server_url": "https://test-prebid.com/openrtb2/auction",
- "timeout_ms": 1000,
- "bidders": ["mocktioneer"],
- "auto_configure": true,
- "debug": false
- }),
- )
- .expect("should update prebid config");
- let registry = IntegrationRegistry::new(&settings);
- let config = config_from_settings(&settings, ®istry);
- let processor = create_html_processor(config);
- let pipeline_config = PipelineConfig {
- input_compression: Compression::None,
- output_compression: Compression::None,
- chunk_size: 8192,
- };
- let mut pipeline = StreamingPipeline::new(pipeline_config, processor);
+ fn script_pattern_matching_exact_paths() {
+ let integration = PrebidIntegration::new(base_config());
+
+ // Should match default exact patterns (suffix matching)
+ assert!(integration.matches_script_pattern("/prebid.js"));
+ assert!(integration.matches_script_pattern("/prebid.min.js"));
+ assert!(integration.matches_script_pattern("/prebidjs.js"));
+ assert!(integration.matches_script_pattern("/prebidjs.min.js"));
+
+ // Suffix matching means nested paths also match
+ assert!(integration.matches_script_pattern("/static/prebid.min.js"));
+ assert!(integration.matches_script_pattern("/static/prebid/v8.53.0/prebid.min.js"));
+
+ // Should not match other scripts
+ assert!(!integration.matches_script_pattern("/app.js"));
+ assert!(!integration.matches_script_pattern("/static/bundle.min.js"));
+ }
- let mut output = Vec::new();
- let result = pipeline.process(Cursor::new(html.as_bytes()), &mut output);
- assert!(result.is_ok());
- let processed = String::from_utf8_lossy(&output);
- assert!(
- processed.contains("tsjs-unified"),
- "Unified bundle should be injected"
- );
- assert!(
- !processed.contains("prebid.min.js"),
- "Prebid script should be removed when auto-config is enabled"
- );
+ #[test]
+ fn script_pattern_matching_wildcard_slash_star() {
+ // Test /* wildcard pattern matching
+ let mut config = base_config();
+ config.script_patterns = vec!["/static/prebid/*".to_string()];
+ let integration = PrebidIntegration::new(config);
+
+ // Should match paths under the prefix with known suffixes
+ assert!(integration.matches_script_pattern("/static/prebid/prebid.min.js"));
+ assert!(integration.matches_script_pattern("/static/prebid/v8.53.0/prebid.min.js"));
+ assert!(integration.matches_script_pattern("/static/prebid/prebidjs.js"));
+
+ // Should not match paths outside prefix
+ assert!(!integration.matches_script_pattern("/prebid.min.js"));
+ assert!(!integration.matches_script_pattern("/other/prebid.min.js"));
+
+ // Should not match non-prebid scripts even under prefix
+ assert!(!integration.matches_script_pattern("/static/prebid/app.js"));
+ }
+
+ #[test]
+ fn script_pattern_matching_wildcard_matchit_syntax() {
+ // Test {*rest} matchit-style wildcard pattern matching
+ let mut config = base_config();
+ config.script_patterns = vec!["/wp-content/plugins/prebidjs/{*rest}".to_string()];
+ let integration = PrebidIntegration::new(config);
+
+ // Should match paths under the prefix with known suffixes
assert!(
- !processed.contains("cdn.prebid.org/prebid.js"),
- "Prebid preload should be removed when auto-config is enabled"
+ integration.matches_script_pattern("/wp-content/plugins/prebidjs/js/prebidjs.min.js")
);
+ assert!(integration.matches_script_pattern("/wp-content/plugins/prebidjs/prebid.min.js"));
+ assert!(integration.matches_script_pattern("/wp-content/plugins/prebidjs/v1/v2/prebid.js"));
+
+ // Should not match paths outside prefix
+ assert!(!integration.matches_script_pattern("/prebid.min.js"));
+ assert!(!integration.matches_script_pattern("/wp-content/other/prebid.min.js"));
+
+ // Should not match non-prebid scripts even under prefix
+ assert!(!integration.matches_script_pattern("/wp-content/plugins/prebidjs/app.js"));
+ }
+
+ #[test]
+ fn script_pattern_matching_case_insensitive() {
+ let integration = PrebidIntegration::new(base_config());
+
+ assert!(integration.matches_script_pattern("/Prebid.JS"));
+ assert!(integration.matches_script_pattern("/PREBID.MIN.JS"));
+ assert!(integration.matches_script_pattern("/Static/Prebid.min.js"));
+ }
+
+ #[test]
+ fn routes_include_script_patterns() {
+ let integration = PrebidIntegration::new(base_config());
+ let routes = integration.routes();
+
+ // Should include the default ad routes
+ assert!(routes.iter().any(|r| r.path == "/ad/render"));
+ assert!(routes.iter().any(|r| r.path == "/ad/auction"));
+
+ // Should include default script removal patterns
+ assert!(routes.iter().any(|r| r.path == "/prebid.js"));
+ assert!(routes.iter().any(|r| r.path == "/prebid.min.js"));
+ assert!(routes.iter().any(|r| r.path == "/prebidjs.js"));
+ assert!(routes.iter().any(|r| r.path == "/prebidjs.min.js"));
}
#[test]
fn enhance_openrtb_request_adds_ids_and_regs() {
let settings = make_settings();
- let mut request_json = json!({
- "id": "openrtb-request-id"
- });
+ let mut request = OpenRtbRequest {
+ id: "openrtb-request-id".to_string(),
+ imp: Vec::new(),
+ site: None,
+ user: None,
+ regs: None,
+ device: None,
+ ext: None,
+ extra: HashMap::new(),
+ };
let synthetic_id = "synthetic-123";
let fresh_id = "fresh-456";
- let mut req = Request::new(Method::POST, "https://edge.example/third-party/ad");
+ let mut req = Request::new(Method::POST, "https://edge.example/auction");
req.set_header("Sec-GPC", "1");
- enhance_openrtb_request(&mut request_json, synthetic_id, fresh_id, &settings, &req)
+ enhance_openrtb_request(&mut request, synthetic_id, fresh_id, &settings, &req)
.expect("should enhance request");
- assert_eq!(request_json["user"]["id"], synthetic_id);
- assert_eq!(request_json["user"]["ext"]["synthetic_fresh"], fresh_id);
+ let user = request.user.as_ref().expect("should have user");
+ assert_eq!(user.id.as_deref(), Some(synthetic_id), "should set user id");
+ let user_ext = user.ext.as_ref().expect("should have user ext");
assert_eq!(
- request_json["regs"]["ext"]["us_privacy"], "1YYN",
- "GPC header should map to US privacy flag"
+ user_ext.synthetic_fresh.as_deref(),
+ Some(fresh_id),
+ "should set synthetic fresh id"
);
+ let regs = request.regs.as_ref().expect("should have regs");
+ let regs_ext = regs.ext.as_ref().expect("should have regs ext");
assert_eq!(
- request_json["site"]["domain"], settings.publisher.domain,
- "site domain should match publisher domain"
+ regs_ext.us_privacy.as_deref(),
+ Some("1YYN"),
+ "should map GPC header to US privacy flag"
);
- assert!(
- request_json["site"]["page"]
- .as_str()
- .unwrap()
- .starts_with("https://"),
- "site page should be populated"
+ let site = request.site.as_ref().expect("should have site");
+ assert_eq!(
+ site.domain.as_deref(),
+ Some(settings.publisher.domain.as_str()),
+ "should set site domain"
+ );
+ let page = site.page.as_ref().expect("should have site page");
+ assert!(page.starts_with("https://"), "should set site page");
+ }
+
+ #[test]
+ fn override_prebid_bidders_replaces_request_values() {
+ let mut request: OpenRtbRequest = serde_json::from_value(json!({
+ "id": "openrtb-request-id",
+ "imp": [
+ {
+ "id": "slot-a",
+ "ext": {
+ "prebid": {
+ "bidder": { "legacy": {} }
+ }
+ }
+ },
+ { "id": "slot-b" }
+ ]
+ }))
+ .expect("should parse openrtb request");
+ let bidders = vec!["appnexus".to_string(), "rubicon".to_string()];
+
+ override_prebid_bidders(&mut request, &bidders);
+
+ let expected = bidders
+ .iter()
+ .map(|bidder| (bidder.clone(), JsonValue::Object(serde_json::Map::new())))
+ .collect::>();
+ let first = request.imp.first().expect("should have first imp");
+ let first_prebid = first
+ .ext
+ .as_ref()
+ .and_then(|ext| ext.prebid.as_ref())
+ .expect("should have prebid ext for first imp");
+ assert_eq!(
+ first_prebid.bidder, expected,
+ "should replace bidders in first imp"
+ );
+ let second = request.imp.get(1).expect("should have second imp");
+ let second_prebid = second
+ .ext
+ .as_ref()
+ .and_then(|ext| ext.prebid.as_ref())
+ .expect("should have prebid ext for second imp");
+ assert_eq!(
+ second_prebid.bidder, expected,
+ "should replace bidders in second imp"
);
}
#[test]
fn transform_prebid_response_rewrites_creatives_and_tracking() {
- let mut response = json!({
+ let settings = crate::test_support::tests::create_test_settings();
+ let mut response: OpenRtbResponse = serde_json::from_value(json!({
"seatbid": [{
"bid": [{
"adm": r#"
"#,
@@ -920,30 +1226,69 @@ mod tests {
"burl": "https://notify.example/bill"
}]
}]
- });
+ }))
+ .expect("should parse openrtb response");
- transform_prebid_response(&mut response, "pub.example", "https")
+ transform_prebid_response(&mut response, &settings, "pub.example", "https")
.expect("should rewrite response");
- let rewritten_adm = response["seatbid"][0]["bid"][0]["adm"]
- .as_str()
+ let rewritten_adm = response
+ .seatbid
+ .as_ref()
+ .and_then(|seatbids| seatbids.first())
+ .and_then(|seatbid| seatbid.bid.as_ref())
+ .and_then(|bids| bids.first())
+ .and_then(|bid| bid.adm.as_deref())
.expect("adm should be string");
assert!(
- rewritten_adm.contains("/ad-proxy/adsrvr"),
- "creative markup should proxy CDN urls"
+ rewritten_adm.contains("/first-party/proxy?tsurl="),
+ "creative markup should proxy asset urls"
);
- for url_field in ["nurl", "burl"] {
- let value = response["seatbid"][0]["bid"][0][url_field]
- .as_str()
- .unwrap();
+ let bid = response
+ .seatbid
+ .as_ref()
+ .and_then(|seatbids| seatbids.first())
+ .and_then(|seatbid| seatbid.bid.as_ref())
+ .and_then(|bids| bids.first())
+ .expect("should have bid");
+ for value in [bid.nurl.as_deref(), bid.burl.as_deref()] {
+ let value = value.expect("should have tracking url");
assert!(
- value.contains("/ad-proxy/track/"),
+ value.starts_with("https://pub.example/first-party/proxy?tsurl="),
"tracking URLs should be proxied"
);
}
}
+ #[test]
+ fn transform_prebid_response_preserves_non_html_adm() {
+ let settings = crate::test_support::tests::create_test_settings();
+ let adm = r#""#;
+ let mut response: OpenRtbResponse = serde_json::from_value(json!({
+ "seatbid": [{
+ "bid": [{
+ "adm": adm,
+ "nurl": "https://notify.example/win"
+ }]
+ }]
+ }))
+ .expect("should parse openrtb response");
+
+ transform_prebid_response(&mut response, &settings, "pub.example", "https")
+ .expect("should rewrite response");
+
+ let rewritten_adm = response
+ .seatbid
+ .as_ref()
+ .and_then(|seatbids| seatbids.first())
+ .and_then(|seatbid| seatbid.bid.as_ref())
+ .and_then(|bids| bids.first())
+ .and_then(|bid| bid.adm.as_deref())
+ .expect("adm should be string");
+ assert_eq!(rewritten_adm, adm, "non-html adm should remain unchanged");
+ }
+
#[test]
fn extract_adm_for_slot_prefers_exact_match() {
let response = json!({
@@ -967,32 +1312,54 @@ mod tests {
}
#[test]
- fn make_first_party_proxy_url_base64_encodes_target() {
+ fn first_party_proxy_url_signs_target() {
+ let settings = crate::test_support::tests::create_test_settings();
let url = "https://cdn.example/path?x=1";
- let rewritten = make_first_party_proxy_url(url, "pub.example", "https", "track");
+ let rewritten = first_party_proxy_url(&settings, "pub.example", "https", url);
assert!(
- rewritten.starts_with("https://pub.example/ad-proxy/track/"),
+ rewritten.starts_with("https://pub.example/first-party/proxy?tsurl="),
"proxy prefix should be applied"
);
+ assert!(
+ rewritten.contains("tstoken="),
+ "proxy url should include a signature"
+ );
+ }
- let encoded = rewritten.split("/ad-proxy/track/").nth(1).unwrap();
- let decoded = BASE64
- .decode(encoded.as_bytes())
- .expect("should decode base64 proxy payload");
- assert_eq!(String::from_utf8(decoded).unwrap(), url);
+ #[test]
+ fn first_party_proxy_url_handles_macros() {
+ let settings = crate::test_support::tests::create_test_settings();
+ let url = "https://notify.example/win?price=${AUCTION_PRICE}&id=123";
+ let rewritten = first_party_proxy_url(&settings, "pub.example", "https", url);
+ assert!(
+ rewritten.starts_with("https://pub.example/first-party/proxy?tsurl="),
+ "proxy prefix should be applied"
+ );
+ assert!(
+ rewritten.contains("tstoken="),
+ "proxy url should include a signature"
+ );
+ assert!(
+ rewritten.contains("notify.example"),
+ "proxy url should include target host"
+ );
+ assert!(
+ rewritten.contains("AUCTION_PRICE"),
+ "proxy url should preserve macro tokens"
+ );
}
#[test]
- fn is_prebid_script_url_matches_common_variants() {
- assert!(is_prebid_script_url("https://cdn.com/prebid.js"));
- assert!(is_prebid_script_url(
- "https://cdn.com/prebid.min.js?version=1"
- ));
- assert!(!is_prebid_script_url("https://cdn.com/app.js"));
+ fn first_party_proxy_url_respects_exclude_domains() {
+ let mut settings = crate::test_support::tests::create_test_settings();
+ settings.rewrite.exclude_domains = vec!["notify.example".to_string()];
+ let url = "https://notify.example/win";
+ let rewritten = first_party_proxy_url(&settings, "pub.example", "https", url);
+ assert_eq!(rewritten, url, "excluded domains should not be proxied");
}
#[test]
- fn test_script_handler_config_parsing() {
+ fn test_script_patterns_config_parsing() {
let toml_str = r#"
[publisher]
domain = "test-publisher.com"
@@ -1009,7 +1376,7 @@ template = "{{client_ip}}:{{user_agent}}"
[integrations.prebid]
enabled = true
server_url = "https://prebid.example"
-script_handler = "/prebid.js"
+script_patterns = ["/static/prebid/*"]
"#;
let settings = Settings::from_toml(toml_str).expect("should parse TOML");
@@ -1018,11 +1385,11 @@ script_handler = "/prebid.js"
.expect("should get config")
.expect("should be enabled");
- assert_eq!(config.script_handler, Some("/prebid.js".to_string()));
+ assert_eq!(config.script_patterns, vec!["/static/prebid/*"]);
}
#[test]
- fn test_script_handler_none_by_default() {
+ fn test_script_patterns_default() {
let toml_str = r#"
[publisher]
domain = "test-publisher.com"
@@ -1047,21 +1414,13 @@ server_url = "https://prebid.example"
.expect("should get config")
.expect("should be enabled");
- assert_eq!(config.script_handler, None);
+ // Should have default patterns
+ assert_eq!(config.script_patterns, default_script_patterns());
}
#[test]
fn test_script_handler_returns_empty_js() {
- let config = PrebidIntegrationConfig {
- enabled: true,
- server_url: "https://prebid.example".to_string(),
- timeout_ms: 1000,
- bidders: vec![],
- auto_configure: false,
- debug: false,
- script_handler: Some("/prebid.js".to_string()),
- };
- let integration = PrebidIntegration::new(config);
+ let integration = PrebidIntegration::new(base_config());
let response = integration
.handle_script_handler()
@@ -1081,41 +1440,104 @@ server_url = "https://prebid.example"
assert!(cache_control.contains("immutable"));
let body = response.into_body_str();
- assert!(body.contains("// Script overridden by Trusted Server"));
+ assert!(
+ body.contains("tsjs-unified"),
+ "should contain comment about replacement"
+ );
}
#[test]
- fn test_routes_includes_script_handler() {
- let config = PrebidIntegrationConfig {
- enabled: true,
- server_url: "https://prebid.example".to_string(),
- timeout_ms: 1000,
- bidders: vec![],
- auto_configure: false,
- debug: false,
- script_handler: Some("/prebid.js".to_string()),
- };
+ fn test_routes_with_default_patterns() {
+ let config = base_config(); // Has default script_patterns
let integration = PrebidIntegration::new(config);
let routes = integration.routes();
- // Should have 3 routes: first-party ad, third-party ad, and script handler
- assert_eq!(routes.len(), 3);
+ // Should have 2 ad routes + 4 default script patterns
+ assert_eq!(routes.len(), 6);
- let has_script_route = routes
- .iter()
- .any(|r| r.path == "/prebid.js" && r.method == Method::GET);
- assert!(has_script_route, "should register script handler route");
+ // Verify ad routes
+ assert!(routes.iter().any(|r| r.path == "/ad/render"));
+ assert!(routes.iter().any(|r| r.path == "/ad/auction"));
+
+ // Verify script pattern routes
+ assert!(routes.iter().any(|r| r.path == "/prebid.js"));
+ assert!(routes.iter().any(|r| r.path == "/prebid.min.js"));
+ assert!(routes.iter().any(|r| r.path == "/prebidjs.js"));
+ assert!(routes.iter().any(|r| r.path == "/prebidjs.min.js"));
+ }
+
+ #[test]
+ fn tsjs_config_script_tag_generates_render_mode() {
+ let tag = tsjs_config_script_tag(Mode::Render);
+ assert!(tag.starts_with(""));
+ assert!(tag.contains(r#"mode:"render""#));
+ assert!(tag.contains("tsjs.setConfig"));
+ // Should have guard for tsjs existence
+ assert!(tag.contains("window.tsjs&&"));
+ }
+
+ #[test]
+ fn tsjs_config_script_tag_generates_auction_mode() {
+ let tag = tsjs_config_script_tag(Mode::Auction);
+ assert!(tag.starts_with(""));
+ assert!(tag.contains(r#"mode:"auction""#));
+ assert!(tag.contains("tsjs.setConfig"));
+ // Should have guard for tsjs existence
+ assert!(tag.contains("window.tsjs&&"));
+ }
+
+ #[test]
+ fn head_injector_returns_empty_when_no_mode() {
+ // When no mode is set, no head inserts needed
+ // (s2sConfig is built into the Prebid bundle served via script interception)
+ let integration = PrebidIntegration::new(base_config());
+ let ctx = IntegrationHtmlContext {
+ request_host: "pub.example",
+ request_scheme: "https",
+ origin_host: "origin.example",
+ document_state: &Default::default(),
+ };
+ let inserts = integration.head_inserts(&ctx);
+ assert!(inserts.is_empty(), "no head inserts when mode not set");
}
#[test]
- fn test_routes_without_script_handler() {
- let config = base_config(); // Has script_handler: None
+ fn head_injector_injects_mode_config_when_mode_set() {
+ let mut config = base_config();
+ config.mode = Some(Mode::Auction);
let integration = PrebidIntegration::new(config);
+ let ctx = IntegrationHtmlContext {
+ request_host: "pub.example",
+ request_scheme: "https",
+ origin_host: "origin.example",
+ document_state: &Default::default(),
+ };
+ let inserts = integration.head_inserts(&ctx);
+ assert_eq!(inserts.len(), 1, "should inject mode config");
+ assert!(
+ inserts[0].contains(r#"mode:"auction""#),
+ "should contain mode config"
+ );
+ }
- let routes = integration.routes();
+ #[test]
+ fn script_handler_serves_empty_js_stub() {
+ let integration = PrebidIntegration::new(base_config());
- // Should only have 2 routes: first-party ad and third-party ad
- assert_eq!(routes.len(), 2);
+ let response = integration
+ .handle_script_handler()
+ .expect("should return response");
+
+ assert_eq!(response.get_status(), StatusCode::OK);
+ let body = response.into_body_str();
+ // Should be a small stub comment, not the full bundle
+ assert!(
+ body.len() < 100,
+ "should serve empty JS stub, not full bundle"
+ );
+ assert!(body.starts_with("/*"), "should be a JS comment");
}
}
diff --git a/crates/common/src/integrations/registry.rs b/crates/common/src/integrations/registry.rs
index 819890d..734586a 100644
--- a/crates/common/src/integrations/registry.rs
+++ b/crates/common/src/integrations/registry.rs
@@ -357,6 +357,14 @@ pub trait IntegrationHtmlPostProcessor: Send + Sync {
fn post_process(&self, html: &mut String, ctx: &IntegrationHtmlContext<'_>) -> bool;
}
+/// Trait for integration-provided HTML head injections.
+pub trait IntegrationHeadInjector: Send + Sync {
+ /// Identifier for logging/diagnostics.
+ fn integration_id(&self) -> &'static str;
+ /// Return HTML snippets to insert at the start of ``.
+ fn head_inserts(&self, ctx: &IntegrationHtmlContext<'_>) -> Vec;
+}
+
/// Registration payload returned by integration builders.
pub struct IntegrationRegistration {
pub integration_id: &'static str,
@@ -364,6 +372,7 @@ pub struct IntegrationRegistration {
pub attribute_rewriters: Vec>,
pub script_rewriters: Vec>,
pub html_post_processors: Vec>,
+ pub head_injectors: Vec>,
}
impl IntegrationRegistration {
@@ -386,6 +395,7 @@ impl IntegrationRegistrationBuilder {
attribute_rewriters: Vec::new(),
script_rewriters: Vec::new(),
html_post_processors: Vec::new(),
+ head_injectors: Vec::new(),
},
}
}
@@ -420,6 +430,12 @@ impl IntegrationRegistrationBuilder {
self
}
+ #[must_use]
+ pub fn with_head_injector(mut self, injector: Arc) -> Self {
+ self.registration.head_injectors.push(injector);
+ self
+ }
+
#[must_use]
pub fn build(self) -> IntegrationRegistration {
self.registration
@@ -441,6 +457,7 @@ struct IntegrationRegistryInner {
html_rewriters: Vec>,
script_rewriters: Vec>,
html_post_processors: Vec>,
+ head_injectors: Vec>,
}
impl Default for IntegrationRegistryInner {
@@ -455,6 +472,7 @@ impl Default for IntegrationRegistryInner {
html_rewriters: Vec::new(),
script_rewriters: Vec::new(),
html_post_processors: Vec::new(),
+ head_injectors: Vec::new(),
}
}
}
@@ -539,6 +557,9 @@ impl IntegrationRegistry {
inner
.html_post_processors
.extend(registration.html_post_processors.into_iter());
+ inner
+ .head_injectors
+ .extend(registration.head_injectors.into_iter());
}
}
@@ -622,6 +643,18 @@ impl IntegrationRegistry {
self.inner.html_post_processors.clone()
}
+ /// Collect HTML snippets for insertion at the start of ``.
+ pub fn head_inserts(&self, ctx: &IntegrationHtmlContext<'_>) -> Vec {
+ let mut inserts = Vec::new();
+ for injector in &self.inner.head_injectors {
+ let mut next = injector.head_inserts(ctx);
+ if !next.is_empty() {
+ inserts.append(&mut next);
+ }
+ }
+ inserts
+ }
+
/// Provide a snapshot of registered integrations and their hooks.
pub fn registered_integrations(&self) -> Vec {
let mut map: BTreeMap<&'static str, IntegrationMetadata> = BTreeMap::new();
@@ -668,6 +701,29 @@ impl IntegrationRegistry {
html_rewriters: attribute_rewriters,
script_rewriters,
html_post_processors: Vec::new(),
+ head_injectors: Vec::new(),
+ }),
+ }
+ }
+
+ #[cfg(test)]
+ pub fn from_rewriters_with_head_injectors(
+ attribute_rewriters: Vec>,
+ script_rewriters: Vec>,
+ head_injectors: Vec>,
+ ) -> Self {
+ Self {
+ inner: Arc::new(IntegrationRegistryInner {
+ get_router: Router::new(),
+ post_router: Router::new(),
+ put_router: Router::new(),
+ delete_router: Router::new(),
+ patch_router: Router::new(),
+ routes: Vec::new(),
+ html_rewriters: attribute_rewriters,
+ script_rewriters,
+ html_post_processors: Vec::new(),
+ head_injectors,
}),
}
}
@@ -711,6 +767,7 @@ impl IntegrationRegistry {
html_rewriters: Vec::new(),
script_rewriters: Vec::new(),
html_post_processors: Vec::new(),
+ head_injectors: Vec::new(),
}),
}
}
diff --git a/crates/common/src/openrtb.rs b/crates/common/src/openrtb.rs
index c73f974..0fcaabd 100644
--- a/crates/common/src/openrtb.rs
+++ b/crates/common/src/openrtb.rs
@@ -1,8 +1,10 @@
-use serde::Serialize;
+use std::collections::HashMap;
+
+use serde::{Deserialize, Serialize};
use serde_json::Value;
/// Minimal subset of OpenRTB 2.x bid request used by Trusted Server.
-#[derive(Debug, Serialize)]
+#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub struct OpenRtbRequest {
/// Unique ID of the bid request, provided by the exchange.
@@ -10,42 +12,168 @@ pub struct OpenRtbRequest {
pub imp: Vec,
#[serde(skip_serializing_if = "Option::is_none")]
pub site: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub user: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub regs: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub device: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub ext: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
}
-#[derive(Debug, Serialize)]
+#[derive(Debug, Serialize, Deserialize)]
pub struct Imp {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub banner: Option,
#[serde(skip_serializing_if = "Option::is_none")]
pub ext: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
}
-#[derive(Debug, Serialize)]
+#[derive(Debug, Serialize, Deserialize)]
pub struct Banner {
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub format: Vec,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
}
-#[derive(Debug, Serialize)]
+#[derive(Debug, Serialize, Deserialize)]
pub struct Format {
pub w: u32,
pub h: u32,
}
-#[derive(Debug, Serialize)]
+#[derive(Debug, Serialize, Deserialize)]
pub struct Site {
#[serde(skip_serializing_if = "Option::is_none")]
pub domain: Option,
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct User {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub id: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub ext: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct UserExt {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub synthetic_fresh: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct Regs {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub ext: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct RegsExt {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub us_privacy: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct Device {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub geo: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct Geo {
+ #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
+ pub geo_type: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub country: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub city: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub region: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct RequestExt {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub trusted_server: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
}
-#[derive(Debug, Serialize)]
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct TrustedServerExt {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub signature: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub kid: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct ImpExt {
- pub prebid: PrebidImpExt,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub prebid: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
}
-#[derive(Debug, Serialize)]
+#[derive(Debug, Serialize, Deserialize, Default)]
pub struct PrebidImpExt {
- pub bidder: std::collections::HashMap,
+ #[serde(default, skip_serializing_if = "HashMap::is_empty")]
+ pub bidder: HashMap,
+}
+
+/// Minimal subset of OpenRTB 2.x bid response used by Trusted Server.
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct OpenRtbResponse {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub seatbid: Option>,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct SeatBid {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub bid: Option>,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct Bid {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub impid: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub adm: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub nurl: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub burl: Option,
+ #[serde(default, flatten)]
+ pub extra: HashMap,
}
diff --git a/crates/common/src/proxy.rs b/crates/common/src/proxy.rs
index 64b72bc..6a7dbff 100644
--- a/crates/common/src/proxy.rs
+++ b/crates/common/src/proxy.rs
@@ -150,6 +150,11 @@ fn finalize_proxied_response(
if ct.contains("text/html") {
// HTML: rewrite and serve as HTML (safe to read as string)
let body = beresp.take_body_str();
+ // Debug: log first 500 chars of raw HTML to see if port is present
+ log::debug!(
+ "proxy: raw HTML body (first 500 chars): {}",
+ body.chars().take(500).collect::()
+ );
let rewritten = crate::creative::rewrite_creative_html(&body, settings);
return rebuild_text_response(beresp, "text/html; charset=utf-8", rewritten);
}
@@ -411,10 +416,16 @@ async fn proxy_with_redirects(
}));
}
- let backend_name = crate::backend::ensure_origin_backend(&scheme, host, parsed_url.port())?;
+ let backend_name = crate::backend::ensure_origin_backend(
+ &scheme,
+ host,
+ parsed_url.port(),
+ settings.proxy.certificate_check,
+ )?;
let mut proxy_req = Request::new(current_method.clone(), ¤t_url);
copy_proxy_forward_headers(req, &mut proxy_req);
+
if let Some(body_bytes) = body {
proxy_req.set_body(body_bytes.to_vec());
}
@@ -1086,6 +1097,28 @@ mod tests {
assert_eq!(err.current_context().status_code(), StatusCode::BAD_GATEWAY);
}
+ #[tokio::test]
+ async fn proxy_sign_preserves_non_standard_port() {
+ let settings = create_test_settings();
+ // Test with non-standard port (e.g., 9443)
+ let body = serde_json::json!({
+ "url": "https://cdn.example.com:9443/img/300x250.svg",
+ });
+ let mut req = Request::new(Method::POST, "https://edge.example/first-party/sign");
+ req.set_body(body.to_string());
+ let mut resp = handle_first_party_proxy_sign(&settings, req)
+ .await
+ .expect("sign ok");
+ assert_eq!(resp.get_status(), StatusCode::OK);
+ let json = resp.take_body_str();
+ // Port 9443 should be preserved (URL-encoded as %3A9443)
+ assert!(
+ json.contains("%3A9443"),
+ "Port should be preserved in signed URL: {}",
+ json
+ );
+ }
+
#[test]
fn proxy_request_config_supports_streaming_and_headers() {
let cfg = ProxyRequestConfig::new("https://example.com/asset")
@@ -1464,6 +1497,44 @@ mod tests {
assert_eq!(ct, "text/css; charset=utf-8");
}
+ #[test]
+ fn html_response_rewrite_preserves_non_standard_port() {
+ // Verify that HTML rewriting preserves non-standard ports in sub-resource URLs.
+ // This is the core test for the port preservation fix.
+ let settings = create_test_settings();
+
+ let html = r#"
+
+
+
+
+
+
+
+"#;
+
+ let beresp = Response::from_status(StatusCode::OK)
+ .with_header(header::CONTENT_TYPE, "text/html; charset=utf-8")
+ .with_body(html);
+
+ let req = Request::new(Method::GET, "https://edge.example/first-party/proxy");
+ let mut out = finalize(
+ &settings,
+ &req,
+ "https://cdn.example.com:9443/creatives/300x250.html",
+ beresp,
+ );
+
+ let body = out.take_body_str();
+
+ // Port 9443 should be preserved (URL-encoded as %3A9443)
+ assert!(
+ body.contains("cdn.example.com%3A9443"),
+ "Port 9443 should be preserved in rewritten URLs. Body:\n{}",
+ body
+ );
+ }
+
#[test]
fn image_accept_sets_generic_content_type_when_missing() {
let settings = create_test_settings();
diff --git a/crates/common/src/publisher.rs b/crates/common/src/publisher.rs
index 6041536..09911ab 100644
--- a/crates/common/src/publisher.rs
+++ b/crates/common/src/publisher.rs
@@ -3,7 +3,7 @@ use fastly::http::{header, StatusCode};
use fastly::{Body, Request, Response};
use crate::backend::ensure_backend_from_url;
-use crate::http_util::serve_static_with_etag;
+use crate::http_util::{serve_static_with_etag, RequestInfo};
use crate::constants::{HEADER_SYNTHETIC_TRUSTED_SERVER, HEADER_X_COMPRESS_HINT};
use crate::cookies::create_synthetic_cookie;
@@ -15,65 +15,6 @@ use crate::streaming_processor::{Compression, PipelineConfig, StreamProcessor, S
use crate::streaming_replacer::create_url_replacer;
use crate::synthetic::get_or_generate_synthetic_id;
-/// Detects the request scheme (HTTP or HTTPS) using Fastly SDK methods and headers.
-///
-/// Tries multiple methods in order of reliability:
-/// 1. Fastly SDK TLS detection methods (most reliable)
-/// 2. Forwarded header (RFC 7239)
-/// 3. X-Forwarded-Proto header
-/// 4. Fastly-SSL header (least reliable, can be spoofed)
-/// 5. Default to HTTP
-fn detect_request_scheme(req: &Request) -> String {
- // 1. First try Fastly SDK's built-in TLS detection methods
- // These are the most reliable as they check the actual connection
- if let Some(tls_protocol) = req.get_tls_protocol() {
- // If we have a TLS protocol, the connection is definitely HTTPS
- log::debug!("TLS protocol detected: {}", tls_protocol);
- return "https".to_string();
- }
-
- // Also check TLS cipher - if present, connection is HTTPS
- if req.get_tls_cipher_openssl_name().is_some() {
- log::debug!("TLS cipher detected, using HTTPS");
- return "https".to_string();
- }
-
- // 2. Try the Forwarded header (RFC 7239)
- if let Some(forwarded) = req.get_header("forwarded") {
- if let Ok(forwarded_str) = forwarded.to_str() {
- // Parse the Forwarded header
- // Format: Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43
- if forwarded_str.contains("proto=https") {
- return "https".to_string();
- } else if forwarded_str.contains("proto=http") {
- return "http".to_string();
- }
- }
- }
-
- // 3. Try X-Forwarded-Proto header
- if let Some(proto) = req.get_header("x-forwarded-proto") {
- if let Ok(proto_str) = proto.to_str() {
- let proto_lower = proto_str.to_lowercase();
- if proto_lower == "https" || proto_lower == "http" {
- return proto_lower;
- }
- }
- }
-
- // 4. Check Fastly-SSL header (can be spoofed by clients, use as last resort)
- if let Some(ssl) = req.get_header("fastly-ssl") {
- if let Ok(ssl_str) = ssl.to_str() {
- if ssl_str == "1" || ssl_str.to_lowercase() == "true" {
- return "https".to_string();
- }
- }
- }
-
- // Default to HTTP (changed from HTTPS based on your settings file)
- "http".to_string()
-}
-
/// Unified tsjs static serving: `/static/tsjs=`
/// Accepts: `tsjs-core(.min).js`, `tsjs-ext(.min).js`, `tsjs-creative(.min).js`
pub fn handle_tsjs_dynamic(
@@ -238,29 +179,20 @@ pub fn handle_publisher_request(
// Prebid.js requests are not intercepted here anymore. The HTML processor rewrites
// any Prebid script references to `/static/tsjs-ext.min.js` when auto-configure is enabled.
- // Extract the request host from the incoming request
- let request_host = req
- .get_header(header::HOST)
- .map(|h| h.to_str().unwrap_or_default())
- .unwrap_or_default()
- .to_string();
+ // Extract request host and scheme from headers (supports X-Forwarded-Host/Proto for chained proxies)
+ let request_info = RequestInfo::from_request(&req);
+ let request_host = &request_info.host;
+ let request_scheme = &request_info.scheme;
- // Detect the request scheme using multiple methods
- let request_scheme = detect_request_scheme(&req);
-
- // Log detection details for debugging
log::debug!(
- "Scheme detection - TLS Protocol: {:?}, TLS Cipher: {:?}, Forwarded: {:?}, X-Forwarded-Proto: {:?}, Fastly-SSL: {:?}, Result: {}",
- req.get_tls_protocol(),
- req.get_tls_cipher_openssl_name(),
- req.get_header("forwarded"),
+ "Request info: host={}, scheme={} (X-Forwarded-Host: {:?}, Host: {:?}, X-Forwarded-Proto: {:?})",
+ request_host,
+ request_scheme,
+ req.get_header("x-forwarded-host"),
+ req.get_header(header::HOST),
req.get_header("x-forwarded-proto"),
- req.get_header("fastly-ssl"),
- request_scheme
);
- log::debug!("Request host: {}, scheme: {}", request_host, request_scheme);
-
// Generate synthetic identifiers before the request body is consumed.
let synthetic_id = get_or_generate_synthetic_id(settings, &req)?;
let has_synthetic_cookie = req
@@ -279,7 +211,10 @@ pub fn handle_publisher_request(
has_synthetic_cookie
);
- let backend_name = ensure_backend_from_url(&settings.publisher.origin_url)?;
+ let backend_name = ensure_backend_from_url(
+ &settings.publisher.origin_url,
+ settings.proxy.certificate_check,
+ )?;
let origin_host = settings.publisher.origin_host();
log::debug!(
@@ -334,8 +269,8 @@ pub fn handle_publisher_request(
content_encoding: &content_encoding,
origin_host: &origin_host,
origin_url: &settings.publisher.origin_url,
- request_host: &request_host,
- request_scheme: &request_scheme,
+ request_host,
+ request_scheme,
settings,
content_type: &content_type,
integration_registry,
@@ -387,73 +322,6 @@ mod tests {
use crate::test_support::tests::create_test_settings;
use fastly::http::Method;
- #[test]
- fn test_detect_request_scheme() {
- // Note: In tests, we can't mock the TLS methods on Request, so we test header fallbacks
-
- // Test Forwarded header with HTTPS
- let mut req = Request::new(Method::GET, "https://test.example.com/page");
- req.set_header("forwarded", "for=192.0.2.60;proto=https;by=203.0.113.43");
- assert_eq!(detect_request_scheme(&req), "https");
-
- // Test Forwarded header with HTTP
- let mut req = Request::new(Method::GET, "http://test.example.com/page");
- req.set_header("forwarded", "for=192.0.2.60;proto=http;by=203.0.113.43");
- assert_eq!(detect_request_scheme(&req), "http");
-
- // Test X-Forwarded-Proto with HTTPS
- let mut req = Request::new(Method::GET, "https://test.example.com/page");
- req.set_header("x-forwarded-proto", "https");
- assert_eq!(detect_request_scheme(&req), "https");
-
- // Test X-Forwarded-Proto with HTTP
- let mut req = Request::new(Method::GET, "http://test.example.com/page");
- req.set_header("x-forwarded-proto", "http");
- assert_eq!(detect_request_scheme(&req), "http");
-
- // Test Fastly-SSL header
- let mut req = Request::new(Method::GET, "https://test.example.com/page");
- req.set_header("fastly-ssl", "1");
- assert_eq!(detect_request_scheme(&req), "https");
-
- // Test default to HTTP when no headers present
- let req = Request::new(Method::GET, "https://test.example.com/page");
- assert_eq!(detect_request_scheme(&req), "http");
-
- // Test priority: Forwarded takes precedence over X-Forwarded-Proto
- let mut req = Request::new(Method::GET, "https://test.example.com/page");
- req.set_header("forwarded", "proto=https");
- req.set_header("x-forwarded-proto", "http");
- assert_eq!(detect_request_scheme(&req), "https");
- }
-
- #[test]
- fn test_handle_publisher_request_extracts_headers() {
- // Test that the function correctly extracts host and scheme from request headers
- let mut req = Request::new(Method::GET, "https://test.example.com/page");
- req.set_header("host", "test.example.com");
- req.set_header("x-forwarded-proto", "https");
-
- // Extract headers like the function does
- let request_host = req
- .get_header("host")
- .map(|h| h.to_str().unwrap_or_default())
- .unwrap_or_default()
- .to_string();
-
- let request_scheme = req
- .get_header("x-forwarded-proto")
- .and_then(|h| h.to_str().ok())
- .unwrap_or("https")
- .to_string();
-
- assert_eq!(request_host, "test.example.com");
- assert_eq!(request_scheme, "https");
- }
-
- // Note: test_handle_publisher_request_default_https_scheme and test_handle_publisher_request_http_scheme
- // were removed as they're redundant with test_detect_request_scheme which covers all scheme detection cases
-
#[test]
fn test_content_type_detection() {
// Test which content types should be processed
diff --git a/crates/common/src/settings.rs b/crates/common/src/settings.rs
index 4a41b1e..2a2880a 100644
--- a/crates/common/src/settings.rs
+++ b/crates/common/src/settings.rs
@@ -259,6 +259,28 @@ fn default_request_signing_enabled() -> bool {
false
}
+/// Proxy settings for `/first-party/proxy` endpoint
+#[derive(Debug, Deserialize, Serialize)]
+pub struct Proxy {
+ /// Enable TLS certificate verification when proxying to HTTPS origins.
+ /// Defaults to true for secure production use.
+ /// Set to false for local development with self-signed certificates.
+ #[serde(default = "default_certificate_check")]
+ pub certificate_check: bool,
+}
+
+fn default_certificate_check() -> bool {
+ true
+}
+
+impl Default for Proxy {
+ fn default() -> Self {
+ Self {
+ certificate_check: default_certificate_check(),
+ }
+ }
+}
+
#[derive(Debug, Default, Deserialize, Serialize, Validate)]
pub struct Settings {
#[validate(nested)]
@@ -277,6 +299,8 @@ pub struct Settings {
#[serde(default)]
#[validate(nested)]
pub rewrite: Rewrite,
+ #[serde(default)]
+ pub proxy: Proxy,
}
#[allow(unused)]
diff --git a/crates/common/src/synthetic.rs b/crates/common/src/synthetic.rs
index d84a95e..b60736c 100644
--- a/crates/common/src/synthetic.rs
+++ b/crates/common/src/synthetic.rs
@@ -14,6 +14,7 @@ use sha2::Sha256;
use crate::constants::{HEADER_SYNTHETIC_PUB_USER_ID, HEADER_SYNTHETIC_TRUSTED_SERVER};
use crate::cookies::handle_request_cookies;
use crate::error::TrustedServerError;
+use crate::http_util::RequestInfo;
use crate::settings::Settings;
type HmacSha256 = Hmac;
@@ -41,9 +42,13 @@ pub fn generate_synthetic_id(
let auth_user_id = req
.get_header(HEADER_SYNTHETIC_PUB_USER_ID)
.map(|h| h.to_str().unwrap_or("anonymous"));
- let publisher_domain = req
- .get_header(header::HOST)
- .map(|h| h.to_str().unwrap_or("unknown"));
+ // Use RequestInfo for consistent host extraction (respects X-Forwarded-Host)
+ let request_info = RequestInfo::from_request(req);
+ let publisher_domain = if request_info.host.is_empty() {
+ None
+ } else {
+ Some(request_info.host.as_str())
+ };
let client_ip = req.get_client_ip_addr().map(|ip| ip.to_string());
let accept_language = req
.get_header(header::ACCEPT_LANGUAGE)
diff --git a/crates/js/Cargo.toml b/crates/js/Cargo.toml
index 1ebd755..3e16e47 100644
--- a/crates/js/Cargo.toml
+++ b/crates/js/Cargo.toml
@@ -15,6 +15,7 @@ repository = "https://example.invalid/trusted-server"
readme = "README.md"
[build-dependencies]
+build-print = { workspace = true }
which = { workspace = true }
[dependencies]
diff --git a/crates/js/build.rs b/crates/js/build.rs
index 26d12a1..4058960 100644
--- a/crates/js/build.rs
+++ b/crates/js/build.rs
@@ -3,6 +3,8 @@ use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
+use build_print::{error, info, warn};
+
const UNIFIED_BUNDLE: &str = "tsjs-unified.js";
fn main() {
@@ -32,7 +34,7 @@ fn main() {
// If Node/npm is absent, keep going if dist exists
let npm = which::which("npm").ok();
if npm.is_none() {
- println!("cargo:warning=tsjs: npm not found; will use existing dist if available");
+ warn!("tsjs: npm not found; will use existing dist if available");
}
// Install deps if node_modules missing
@@ -44,9 +46,7 @@ fn main() {
.current_dir(&ts_dir)
.status();
if !status.as_ref().map(|s| s.success()).unwrap_or(false) {
- println!(
- "cargo:warning=tsjs: npm install failed; using existing dist if available"
- );
+ error!("tsjs: npm install failed; using existing dist if available");
}
}
}
@@ -60,24 +60,24 @@ fn main() {
.status();
}
- // Build unified bundle
+ // Build unified bundle (includes Prebid.js)
if !skip {
if let Some(npm_path) = npm.clone() {
- println!("cargo:warning=tsjs: Building unified bundle");
+ info!("tsjs: Building unified bundle");
let js_modules = env::var("TSJS_MODULES").unwrap_or("".to_string());
let status = Command::new(&npm_path)
.env("TSJS_MODULES", js_modules)
- .args(["run", "build:custom"])
+ .args(["run", "build"])
.current_dir(&ts_dir)
.status();
if !status.as_ref().map(|s| s.success()).unwrap_or(false) {
- panic!("tsjs: npm run build:custom failed - refusing to use stale bundle");
+ panic!("tsjs: npm run build failed - refusing to use stale bundle");
}
}
}
- // Copy unified bundle into OUT_DIR for include_str!
+ // Copy bundle into OUT_DIR for include_str!
copy_bundle(UNIFIED_BUNDLE, true, &crate_dir, &dist_dir, &out_dir);
}
diff --git a/crates/js/lib/package-lock.json b/crates/js/lib/package-lock.json
index 83411a3..cac5ded 100644
--- a/crates/js/lib/package-lock.json
+++ b/crates/js/lib/package-lock.json
@@ -7,12 +7,16 @@
"": {
"name": "tsjs",
"version": "0.1.0",
+ "dependencies": {
+ "prebid.js": "^10.18.0"
+ },
"devDependencies": {
"@eslint/js": "^9.13.0",
"@types/jsdom": "^27.0.0",
"@types/node": "^24.10.0",
"@typescript-eslint/eslint-plugin": "^8.6.0",
"@typescript-eslint/parser": "^8.6.0",
+ "baseline-browser-mapping": "^2.9.16",
"eslint": "^9.10.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.29.1",
@@ -26,58 +30,1655 @@
"vitest": "^4.0.8"
}
},
- "node_modules/@acemir/cssom": {
- "version": "0.9.23",
- "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.23.tgz",
- "integrity": "sha512-2kJ1HxBKzPLbmhZpxBiTZggjtgCwKg1ma5RHShxvd6zgqhDEdEkzpiwe7jLkI2p2BrZvFCXIihdoMkl1H39VnA==",
- "dev": true,
- "license": "MIT"
+ "node_modules/@acemir/cssom": {
+ "version": "0.9.23",
+ "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.23.tgz",
+ "integrity": "sha512-2kJ1HxBKzPLbmhZpxBiTZggjtgCwKg1ma5RHShxvd6zgqhDEdEkzpiwe7jLkI2p2BrZvFCXIihdoMkl1H39VnA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@asamuzakjp/css-color": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.0.tgz",
+ "integrity": "sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/css-calc": "^2.1.4",
+ "@csstools/css-color-parser": "^3.1.0",
+ "@csstools/css-parser-algorithms": "^3.0.5",
+ "@csstools/css-tokenizer": "^3.0.4",
+ "lru-cache": "^11.2.2"
+ }
+ },
+ "node_modules/@asamuzakjp/dom-selector": {
+ "version": "6.7.4",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.4.tgz",
+ "integrity": "sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@asamuzakjp/nwsapi": "^2.3.9",
+ "bidi-js": "^1.0.3",
+ "css-tree": "^3.1.0",
+ "is-potential-custom-element-name": "^1.0.1",
+ "lru-cache": "^11.2.2"
+ }
+ },
+ "node_modules/@asamuzakjp/nwsapi": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz",
+ "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz",
+ "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz",
+ "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz",
+ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/generator": "^7.28.6",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6",
+ "@jridgewell/remapping": "^2.3.5",
+ "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/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "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",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz",
+ "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.27.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
+ "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.27.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-validator-option": "^7.27.1",
+ "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/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==",
+ "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",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz",
+ "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.27.3",
+ "@babel/helper-member-expression-to-functions": "^7.28.5",
+ "@babel/helper-optimise-call-expression": "^7.27.1",
+ "@babel/helper-replace-supers": "^7.28.6",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+ "@babel/traverse": "^7.28.6",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-create-regexp-features-plugin": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz",
+ "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.27.3",
+ "regexpu-core": "^6.3.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-define-polyfill-provider": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz",
+ "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.27.2",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "debug": "^4.4.1",
+ "lodash.debounce": "^4.0.8",
+ "resolve": "^1.22.10"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz",
+ "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.28.5",
+ "@babel/types": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz",
+ "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-remap-async-to-generator": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz",
+ "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.27.1",
+ "@babel/helper-wrap-function": "^7.27.1",
+ "@babel/traverse": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz",
+ "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.28.5",
+ "@babel/helper-optimise-call-expression": "^7.27.1",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz",
+ "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-wrap-function": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz",
+ "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
+ "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz",
+ "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.6"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz",
+ "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/traverse": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz",
+ "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz",
+ "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz",
+ "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+ "@babel/plugin-transform-optional-chaining": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.13.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz",
+ "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-private-property-in-object": {
+ "version": "7.21.0-placeholder-for-preset-env.2",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
+ "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-assertions": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz",
+ "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-attributes": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz",
+ "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz",
+ "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz",
+ "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-unicode-sets-regex": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
+ "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+ "@babel/helper-plugin-utils": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-arrow-functions": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz",
+ "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-generator-functions": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.6.tgz",
+ "integrity": "sha512-9knsChgsMzBV5Yh3kkhrZNxH3oCYAfMBkNNaVN4cP2RVlFPe8wYdwwcnOsAbkdDoV9UjFtOXWrWB52M8W4jNeA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/helper-remap-async-to-generator": "^7.27.1",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-to-generator": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz",
+ "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/helper-remap-async-to-generator": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz",
+ "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoping": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz",
+ "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-properties": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz",
+ "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-static-block": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz",
+ "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.12.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-classes": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz",
+ "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.27.3",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/helper-replace-supers": "^7.28.6",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-computed-properties": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz",
+ "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/template": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-destructuring": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz",
+ "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/traverse": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dotall-regex": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz",
+ "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.28.5",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-duplicate-keys": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz",
+ "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.28.6.tgz",
+ "integrity": "sha512-5suVoXjC14lUN6ZL9OLKIHCNVWCrqGqlmEp/ixdXjvgnEl/kauLvvMO/Xw9NyMc95Joj1AeLVPVMvibBgSoFlA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.28.5",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dynamic-import": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz",
+ "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-explicit-resource-management": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz",
+ "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/plugin-transform-destructuring": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz",
+ "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-export-namespace-from": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz",
+ "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-for-of": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz",
+ "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-function-name": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz",
+ "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/traverse": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-json-strings": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz",
+ "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-literals": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz",
+ "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-logical-assignment-operators": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz",
+ "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-member-expression-literals": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz",
+ "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-amd": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz",
+ "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-commonjs": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz",
+ "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-systemjs": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz",
+ "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.28.3",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-umd": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz",
+ "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz",
+ "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-new-target": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz",
+ "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz",
+ "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-numeric-separator": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz",
+ "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-rest-spread": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz",
+ "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/plugin-transform-destructuring": "^7.28.5",
+ "@babel/plugin-transform-parameters": "^7.27.7",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-super": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz",
+ "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/helper-replace-supers": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-catch-binding": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz",
+ "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-chaining": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz",
+ "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-parameters": {
+ "version": "7.27.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz",
+ "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-methods": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz",
+ "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-property-in-object": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz",
+ "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.27.3",
+ "@babel/helper-create-class-features-plugin": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-property-literals": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz",
+ "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regenerator": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.6.tgz",
+ "integrity": "sha512-eZhoEZHYQLL5uc1gS5e9/oTknS0sSSAtd5TkKMUp3J+S/CaUjagc0kOUPsEbDmMeva0nC3WWl4SxVY6+OBuxfw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regexp-modifiers": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz",
+ "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.28.5",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-reserved-words": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz",
+ "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-runtime": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.5.tgz",
+ "integrity": "sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "babel-plugin-polyfill-corejs2": "^0.4.14",
+ "babel-plugin-polyfill-corejs3": "^0.13.0",
+ "babel-plugin-polyfill-regenerator": "^0.6.5",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-runtime/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
},
- "node_modules/@asamuzakjp/css-color": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.0.tgz",
- "integrity": "sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==",
- "dev": true,
+ "node_modules/@babel/plugin-transform-shorthand-properties": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz",
+ "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==",
"license": "MIT",
"dependencies": {
- "@csstools/css-calc": "^2.1.4",
- "@csstools/css-color-parser": "^3.1.0",
- "@csstools/css-parser-algorithms": "^3.0.5",
- "@csstools/css-tokenizer": "^3.0.4",
- "lru-cache": "^11.2.2"
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
}
},
- "node_modules/@asamuzakjp/dom-selector": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.4.tgz",
- "integrity": "sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==",
- "dev": true,
+ "node_modules/@babel/plugin-transform-spread": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz",
+ "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==",
"license": "MIT",
"dependencies": {
- "@asamuzakjp/nwsapi": "^2.3.9",
- "bidi-js": "^1.0.3",
- "css-tree": "^3.1.0",
- "is-potential-custom-element-name": "^1.0.1",
- "lru-cache": "^11.2.2"
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
}
},
- "node_modules/@asamuzakjp/nwsapi": {
- "version": "2.3.9",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz",
- "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==",
- "dev": true,
- "license": "MIT"
+ "node_modules/@babel/plugin-transform-sticky-regex": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz",
+ "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
},
- "node_modules/@babel/helper-validator-identifier": {
+ "node_modules/@babel/plugin-transform-template-literals": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz",
+ "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typeof-symbol": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz",
+ "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typescript": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz",
+ "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.27.3",
+ "@babel/helper-create-class-features-plugin": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+ "@babel/plugin-syntax-typescript": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-escapes": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz",
+ "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-property-regex": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz",
+ "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.28.5",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-regex": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz",
+ "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-sets-regex": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz",
+ "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.28.5",
+ "@babel/helper-plugin-utils": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/preset-env": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.6.tgz",
+ "integrity": "sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "@babel/helper-validator-option": "^7.27.1",
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5",
+ "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1",
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1",
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1",
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6",
+ "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
+ "@babel/plugin-syntax-import-assertions": "^7.28.6",
+ "@babel/plugin-syntax-import-attributes": "^7.28.6",
+ "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
+ "@babel/plugin-transform-arrow-functions": "^7.27.1",
+ "@babel/plugin-transform-async-generator-functions": "^7.28.6",
+ "@babel/plugin-transform-async-to-generator": "^7.28.6",
+ "@babel/plugin-transform-block-scoped-functions": "^7.27.1",
+ "@babel/plugin-transform-block-scoping": "^7.28.6",
+ "@babel/plugin-transform-class-properties": "^7.28.6",
+ "@babel/plugin-transform-class-static-block": "^7.28.6",
+ "@babel/plugin-transform-classes": "^7.28.6",
+ "@babel/plugin-transform-computed-properties": "^7.28.6",
+ "@babel/plugin-transform-destructuring": "^7.28.5",
+ "@babel/plugin-transform-dotall-regex": "^7.28.6",
+ "@babel/plugin-transform-duplicate-keys": "^7.27.1",
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.28.6",
+ "@babel/plugin-transform-dynamic-import": "^7.27.1",
+ "@babel/plugin-transform-explicit-resource-management": "^7.28.6",
+ "@babel/plugin-transform-exponentiation-operator": "^7.28.6",
+ "@babel/plugin-transform-export-namespace-from": "^7.27.1",
+ "@babel/plugin-transform-for-of": "^7.27.1",
+ "@babel/plugin-transform-function-name": "^7.27.1",
+ "@babel/plugin-transform-json-strings": "^7.28.6",
+ "@babel/plugin-transform-literals": "^7.27.1",
+ "@babel/plugin-transform-logical-assignment-operators": "^7.28.6",
+ "@babel/plugin-transform-member-expression-literals": "^7.27.1",
+ "@babel/plugin-transform-modules-amd": "^7.27.1",
+ "@babel/plugin-transform-modules-commonjs": "^7.28.6",
+ "@babel/plugin-transform-modules-systemjs": "^7.28.5",
+ "@babel/plugin-transform-modules-umd": "^7.27.1",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1",
+ "@babel/plugin-transform-new-target": "^7.27.1",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6",
+ "@babel/plugin-transform-numeric-separator": "^7.28.6",
+ "@babel/plugin-transform-object-rest-spread": "^7.28.6",
+ "@babel/plugin-transform-object-super": "^7.27.1",
+ "@babel/plugin-transform-optional-catch-binding": "^7.28.6",
+ "@babel/plugin-transform-optional-chaining": "^7.28.6",
+ "@babel/plugin-transform-parameters": "^7.27.7",
+ "@babel/plugin-transform-private-methods": "^7.28.6",
+ "@babel/plugin-transform-private-property-in-object": "^7.28.6",
+ "@babel/plugin-transform-property-literals": "^7.27.1",
+ "@babel/plugin-transform-regenerator": "^7.28.6",
+ "@babel/plugin-transform-regexp-modifiers": "^7.28.6",
+ "@babel/plugin-transform-reserved-words": "^7.27.1",
+ "@babel/plugin-transform-shorthand-properties": "^7.27.1",
+ "@babel/plugin-transform-spread": "^7.28.6",
+ "@babel/plugin-transform-sticky-regex": "^7.27.1",
+ "@babel/plugin-transform-template-literals": "^7.27.1",
+ "@babel/plugin-transform-typeof-symbol": "^7.27.1",
+ "@babel/plugin-transform-unicode-escapes": "^7.27.1",
+ "@babel/plugin-transform-unicode-property-regex": "^7.28.6",
+ "@babel/plugin-transform-unicode-regex": "^7.27.1",
+ "@babel/plugin-transform-unicode-sets-regex": "^7.28.6",
+ "@babel/preset-modules": "0.1.6-no-external-plugins",
+ "babel-plugin-polyfill-corejs2": "^0.4.14",
+ "babel-plugin-polyfill-corejs3": "^0.13.0",
+ "babel-plugin-polyfill-regenerator": "^0.6.5",
+ "core-js-compat": "^3.43.0",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/preset-env/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/preset-modules": {
+ "version": "0.1.6-no-external-plugins",
+ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
+ "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/types": "^7.4.4",
+ "esutils": "^2.0.2"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/@babel/preset-typescript": {
"version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
- "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
- "dev": true,
+ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz",
+ "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/helper-validator-option": "^7.27.1",
+ "@babel/plugin-syntax-jsx": "^7.27.1",
+ "@babel/plugin-transform-modules-commonjs": "^7.27.1",
+ "@babel/plugin-transform-typescript": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
+ "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/template": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz",
+ "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/generator": "^7.28.6",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.6",
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.28.6",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz",
+ "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
"node_modules/@csstools/color-helpers": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
@@ -925,13 +2526,51 @@
"url": "https://github.com/sponsors/nzakas"
}
},
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "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/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1298,6 +2937,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@socket.io/component-emitter": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
+ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
+ "license": "MIT"
+ },
"node_modules/@standard-schema/spec": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
@@ -1316,6 +2961,15 @@
"assertion-error": "^2.0.1"
}
},
+ "node_modules/@types/cors": {
+ "version": "2.8.19",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
+ "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/deep-eql": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
@@ -1346,7 +3000,6 @@
"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": {
@@ -1360,7 +3013,6 @@
"version": "24.10.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
@@ -1720,6 +3372,19 @@
"url": "https://opencollective.com/vitest"
}
},
+ "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/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
@@ -1771,11 +3436,70 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/ajv-formats": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT"
+ },
+ "node_modules/ansi-colors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-wrap": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
@@ -1787,6 +3511,28 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/ansi-wrap": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+ "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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==",
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/are-docs-informative": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz",
@@ -1804,6 +3550,24 @@
"dev": true,
"license": "Python-2.0"
},
+ "node_modules/arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/array-buffer-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
@@ -1821,6 +3585,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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-includes": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
@@ -1936,6 +3706,15 @@
"node": ">=12"
}
},
+ "node_modules/assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/async-function": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
@@ -1962,18 +3741,73 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/babel-plugin-polyfill-corejs2": {
+ "version": "0.4.14",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz",
+ "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.27.7",
+ "@babel/helper-define-polyfill-provider": "^0.6.5",
+ "semver": "^6.3.1"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-corejs3": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz",
+ "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-define-polyfill-provider": "^0.6.5",
+ "core-js-compat": "^3.43.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-regenerator": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz",
+ "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-define-polyfill-provider": "^0.6.5"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.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==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/base64id": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+ "license": "MIT",
+ "engines": {
+ "node": "^4.5.0 || >= 5.9"
+ }
+ },
"node_modules/baseline-browser-mapping": {
- "version": "2.8.30",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.30.tgz",
- "integrity": "sha512-aTUKW4ptQhS64+v2d6IkPzymEzzhw+G0bA1g3uBRV3+ntkH+svttKseW5IOR4Ed6NUVKqnY7qT3dKvzQ7io4AA==",
- "dev": true,
+ "version": "2.9.16",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.16.tgz",
+ "integrity": "sha512-KeUZdBuxngy825i8xvzaK1Ncnkx0tBmb3k8DkEuqjKRkmtvNTjey2ZsNeh8Dw4lfKvbCOu9oeNx2TKm2vHqcRw==",
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
@@ -1989,6 +3823,75 @@
"require-from-string": "^2.0.2"
}
},
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "license": "MIT"
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.4",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
+ "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==",
+ "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.1",
+ "iconv-lite": "~0.4.24",
+ "on-finished": "~2.4.1",
+ "qs": "~6.14.0",
+ "raw-body": "~2.5.3",
+ "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/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/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": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
@@ -2003,7 +3906,6 @@
"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"
@@ -2016,7 +3918,6 @@
"version": "4.28.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz",
"integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -2047,6 +3948,41 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/bufferstreams": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/bufferstreams/-/bufferstreams-1.0.1.tgz",
+ "integrity": "sha512-LZmiIfQprMLS6/k42w/PTc7awhU8AdNNcUerxTgr01WlP9agR2SgMv0wjlYYFD6eDOi8WvofrTX8RayjR/AeUQ==",
+ "dependencies": {
+ "readable-stream": "^1.0.33"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/bufferstreams/node_modules/isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
+ "license": "MIT"
+ },
+ "node_modules/bufferstreams/node_modules/readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "node_modules/bufferstreams/node_modules/string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
+ "license": "MIT"
+ },
"node_modules/builtin-modules": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz",
@@ -2060,6 +3996,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "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/call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
@@ -2083,7 +4028,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -2097,7 +4041,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -2124,7 +4067,6 @@
"version": "1.0.30001756",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001756.tgz",
"integrity": "sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -2175,6 +4117,42 @@
"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==",
+ "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==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/ci-info": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz",
@@ -2214,11 +4192,21 @@
"node": ">=0.8.0"
}
},
+ "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==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.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==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
@@ -2231,7 +4219,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
"license": "MIT"
},
"node_modules/comment-parser": {
@@ -2248,14 +4235,156 @@
"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/connect": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "finalhandler": "1.1.2",
+ "parseurl": "~1.3.3",
+ "utils-merge": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/connect/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/connect/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/connect/node_modules/finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/connect/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/connect/node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/connect/node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/consolidate": {
+ "version": "0.15.1",
+ "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz",
+ "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==",
+ "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog",
+ "license": "MIT",
+ "dependencies": {
+ "bluebird": "^3.1.1"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "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/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==",
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
+ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
+ "license": "MIT"
+ },
+ "node_modules/core-js": {
+ "version": "3.47.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz",
+ "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
"node_modules/core-js-compat": {
"version": "3.47.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz",
"integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.28.0"
@@ -2265,6 +4394,25 @@
"url": "https://opencollective.com/core-js"
}
},
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2280,6 +4428,12 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+ "license": "MIT"
+ },
"node_modules/css-tree": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
@@ -2309,6 +4463,12 @@
"node": ">=20"
}
},
+ "node_modules/custom-event": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
+ "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==",
+ "license": "MIT"
+ },
"node_modules/data-urls": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz",
@@ -2377,11 +4537,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/date-format": {
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
+ "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -2445,6 +4613,37 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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/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/di": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
+ "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==",
+ "license": "MIT"
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "license": "MIT"
+ },
"node_modules/doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -2458,11 +4657,31 @@
"node": ">=0.10.0"
}
},
+ "node_modules/dom-serialize": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
+ "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==",
+ "license": "MIT",
+ "dependencies": {
+ "custom-event": "~1.0.0",
+ "ent": "~2.2.0",
+ "extend": "^3.0.0",
+ "void-elements": "^2.0.0"
+ }
+ },
+ "node_modules/dset": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
+ "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
@@ -2473,13 +4692,83 @@
"node": ">= 0.4"
}
},
+ "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/electron-to-chromium": {
"version": "1.5.259",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.259.tgz",
"integrity": "sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ==",
- "dev": true,
"license": "ISC"
},
+ "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/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/engine.io": {
+ "version": "6.6.5",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz",
+ "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/cors": "^2.8.12",
+ "@types/node": ">=10.0.0",
+ "accepts": "~1.3.4",
+ "base64id": "2.0.0",
+ "cookie": "~0.7.2",
+ "cors": "~2.8.5",
+ "debug": "~4.4.1",
+ "engine.io-parser": "~5.2.1",
+ "ws": "~8.18.3"
+ },
+ "engines": {
+ "node": ">=10.2.0"
+ }
+ },
+ "node_modules/engine.io-parser": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
+ "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/ent": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz",
+ "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "punycode": "^1.4.1",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ent/node_modules/punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
+ "license": "MIT"
+ },
"node_modules/entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
@@ -2566,7 +4855,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -2576,7 +4864,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -2593,7 +4880,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@@ -2649,6 +4935,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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==",
+ "license": "MIT"
+ },
"node_modules/esbuild": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
@@ -2695,12 +4987,17 @@
"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",
@@ -3105,6 +5402,19 @@
"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==",
+ "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",
@@ -3155,12 +5465,26 @@
"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==",
+ "license": "MIT"
+ },
"node_modules/expect-type": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
@@ -3171,11 +5495,90 @@
"node": ">=12.0.0"
}
},
+ "node_modules/express": {
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
+ "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
+ "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.12",
+ "proxy-addr": "~2.0.7",
+ "qs": "~6.14.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"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "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/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "license": "MIT"
+ },
+ "node_modules/extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.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-glob": {
@@ -3222,6 +5625,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
+ "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
"node_modules/fastq": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
@@ -3249,7 +5668,6 @@
"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"
@@ -3258,6 +5676,39 @@
"node": ">=8"
}
},
+ "node_modules/finalhandler": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
+ "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
+ "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.2",
+ "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",
@@ -3306,9 +5757,28 @@
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
- "dev": true,
"license": "ISC"
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
+ "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.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@@ -3325,11 +5795,57 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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/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==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/fs-readfile-promise": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/fs-readfile-promise/-/fs-readfile-promise-3.0.1.tgz",
+ "integrity": "sha512-LsSxMeaJdYH27XrW7Dmq0Gx63mioULCRel63B5VeELYLavi1wF5s0XfsIdKDFdCL9hsfQ2qBvXJszQtQJ9h17A==",
+ "license": "ISC",
+ "dependencies": {
+ "graceful-fs": "^4.1.11"
+ }
+ },
+ "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==",
+ "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,
@@ -3340,11 +5856,19 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/fun-hooks": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fun-hooks/-/fun-hooks-1.1.0.tgz",
+ "integrity": "sha512-LTpm8ayq0ZgrrK0D/Fk+2cgCgkpLppsGKtQIdZBg/5ncKXTGPKuYz8DBG+z8FVCDsJM1DtnYGy4FfSYRLnWbsQ==",
+ "license": "MIT",
+ "dependencies": {
+ "typescript-tuple": "^2.2.1"
+ }
+ },
"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==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -3391,11 +5915,28 @@
"node": ">= 0.4"
}
},
+ "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==",
+ "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==",
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -3420,7 +5961,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
@@ -3448,6 +5988,27 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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",
+ "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/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -3461,6 +6022,28 @@
"node": ">=10.13.0"
}
},
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
@@ -3495,22 +6078,107 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "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/gulp-babel": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0.tgz",
+ "integrity": "sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ==",
+ "license": "MIT",
+ "dependencies": {
+ "plugin-error": "^1.0.1",
+ "replace-ext": "^1.0.0",
+ "through2": "^2.0.0",
+ "vinyl-sourcemaps-apply": "^0.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/gulp-wrap": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/gulp-wrap/-/gulp-wrap-0.15.0.tgz",
+ "integrity": "sha512-f17zkGObA+hE/FThlg55gfA0nsXbdmHK1WqzjjB2Ytq1TuhLR7JiCBJ3K4AlMzCyoFaCjfowos+VkToUNE0WTQ==",
+ "dependencies": {
+ "consolidate": "^0.15.1",
+ "es6-promise": "^4.2.6",
+ "fs-readfile-promise": "^3.0.1",
+ "js-yaml": "^3.13.0",
+ "lodash": "^4.17.11",
+ "node.extend": "2.0.2",
+ "plugin-error": "^1.0.1",
+ "through2": "^3.0.1",
+ "tryit": "^1.0.1",
+ "vinyl-bufferstream": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=6.14",
+ "npm": ">=1.4.3"
+ }
+ },
+ "node_modules/gulp-wrap/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/gulp-wrap/node_modules/js-yaml": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/gulp-wrap/node_modules/through2": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+ "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "readable-stream": "2 || 3"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
+ "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
"license": "MIT",
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">= 0.4.0"
}
},
- "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/has-bigints": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
@@ -3567,7 +6235,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -3580,7 +6247,6 @@
"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"
@@ -3596,7 +6262,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -3635,6 +6300,40 @@
],
"license": "MIT"
},
+ "node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "license": "MIT",
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/http-proxy-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
@@ -3663,6 +6362,36 @@
"node": ">= 14"
}
},
+ "node_modules/iab-adcom": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/iab-adcom/-/iab-adcom-1.0.6.tgz",
+ "integrity": "sha512-XAJdidfrFgZNKmHqcXD3Zhqik2rdSmOs+PGgeVfPWgthxvzNBQxkZnKkW3QAau6mrLjtJc8yOQC6awcEv7gryA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/iab-native": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/iab-native/-/iab-native-1.0.0.tgz",
+ "integrity": "sha512-AxGYpKGRcyG5pbEAqj+ssxNwZAfxC0pRwyKc0MYoKjm0UeOoUNCWrZV0HGimcQii6ebe6MRqBQEeENyHM4qTdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/iab-openrtb": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/iab-openrtb/-/iab-openrtb-1.0.1.tgz",
+ "integrity": "sha512-egawJx6+pMh/6uA/hak1y+R2+XCSH2jxteSkWlY98/XdQQftaMUMllUFNMKrHwq9lgCI70Me06g4JCCnV6E62g==",
+ "license": "MIT",
+ "dependencies": {
+ "iab-adcom": "1.0.6"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -3726,6 +6455,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "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.",
+ "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/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -3741,6 +6487,24 @@
"node": ">= 0.4"
}
},
+ "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": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/is/-/is-3.3.2.tgz",
+ "integrity": "sha512-a2xr4E3s1PjDS8ORcGgXpWx6V+liNs+O3JRD2mb9aeugD7rtkkZ0zgLdYgw0tWsKhsdiezGYptSiMlVazCBTuQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -3795,6 +6559,18 @@
"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==",
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-boolean-object": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
@@ -3845,7 +6621,6 @@
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
@@ -3892,11 +6667,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "license": "MIT",
+ "dependencies": {
+ "is-plain-object": "^2.0.4"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"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"
@@ -3918,6 +6704,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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-generator-function": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
@@ -3942,7 +6737,6 @@
"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"
@@ -3981,7 +6775,6 @@
"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"
@@ -4004,6 +6797,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-potential-custom-element-name": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
@@ -4015,7 +6820,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
@@ -4163,6 +6967,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/isbinaryfile": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz",
+ "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/gjtorikian/"
+ }
+ },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -4170,6 +6986,21 @@
"dev": true,
"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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.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.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
@@ -4250,7 +7081,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
- "dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
@@ -4293,6 +7123,84 @@
"json5": "lib/cli.js"
}
},
+ "node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "license": "MIT",
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/karma": {
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz",
+ "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==",
+ "license": "MIT",
+ "dependencies": {
+ "@colors/colors": "1.5.0",
+ "body-parser": "^1.19.0",
+ "braces": "^3.0.2",
+ "chokidar": "^3.5.1",
+ "connect": "^3.7.0",
+ "di": "^0.0.1",
+ "dom-serialize": "^2.2.1",
+ "glob": "^7.1.7",
+ "graceful-fs": "^4.2.6",
+ "http-proxy": "^1.18.1",
+ "isbinaryfile": "^4.0.8",
+ "lodash": "^4.17.21",
+ "log4js": "^6.4.1",
+ "mime": "^2.5.2",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.5",
+ "qjobs": "^1.2.0",
+ "range-parser": "^1.2.1",
+ "rimraf": "^3.0.2",
+ "socket.io": "^4.7.2",
+ "source-map": "^0.6.1",
+ "tmp": "^0.2.1",
+ "ua-parser-js": "^0.7.30",
+ "yargs": "^16.1.1"
+ },
+ "bin": {
+ "karma": "bin/karma"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/karma-safarinative-launcher": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/karma-safarinative-launcher/-/karma-safarinative-launcher-1.1.0.tgz",
+ "integrity": "sha512-vdMjdQDHkSUbOZc8Zq2K5bBC0yJGFEgfrKRJTqt0Um0SC1Rt8drS2wcN6UA3h4LgsL3f1pMcmRSvKucbJE8Qdg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "karma": ">=0.9"
+ }
+ },
+ "node_modules/karma/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/karma/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -4303,6 +7211,15 @@
"json-buffer": "3.0.1"
}
},
+ "node_modules/klona": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
+ "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -4317,6 +7234,28 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/live-connect-common": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/live-connect-common/-/live-connect-common-4.1.0.tgz",
+ "integrity": "sha512-sRklgbe13377aR+G0qCBiZPayQw5oZZozkuxKEoyipxscLbVzwe9gtA7CPpbmo6UcOdQxdCE6A7J1tI0wTSmqw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/live-connect-js": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-7.2.0.tgz",
+ "integrity": "sha512-oZY4KqwrG1C+CDKApcsdDdMG4j2d44lhmvbNy4ZE6sPFr+W8R3m0+V+JxXB8p6tgSePJ8X/uhzAGos0lDg/MAg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "live-connect-common": "^v4.1.0",
+ "tiny-hashes": "1.0.1"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -4333,6 +7272,18 @@
"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==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "license": "MIT"
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -4340,6 +7291,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/log4js": {
+ "version": "6.9.1",
+ "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz",
+ "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "date-format": "^4.0.14",
+ "debug": "^4.3.4",
+ "flatted": "^3.2.7",
+ "rfdc": "^1.3.0",
+ "streamroller": "^3.1.5"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
"node_modules/lru-cache": {
"version": "11.2.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
@@ -4364,7 +7331,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -4377,6 +7343,24 @@
"dev": true,
"license": "CC0-1.0"
},
+ "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/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/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -4387,6 +7371,15 @@
"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",
@@ -4401,6 +7394,39 @@
"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==",
+ "license": "MIT",
+ "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==",
+ "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/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
@@ -4421,17 +7447,27 @@
"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/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
"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==",
- "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -4453,19 +7489,58 @@
"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/node-releases": {
- "version": "2.0.27",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
- "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
- "dev": true,
- "license": "MIT"
+ "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.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/node-releases": {
+ "version": "2.0.27",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
+ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
+ "license": "MIT"
+ },
+ "node_modules/node.extend": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz",
+ "integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==",
+ "license": "(MIT OR GPL-2.0)",
+ "dependencies": {
+ "has": "^1.0.3",
+ "is": "^3.2.1"
+ },
+ "engines": {
+ "node": ">=0.4.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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
"node_modules/object-deep-merge": {
"version": "2.0.0",
@@ -4478,7 +7553,6 @@
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -4571,6 +7645,27 @@
"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==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -4682,6 +7777,15 @@
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
+ "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",
@@ -4692,6 +7796,15 @@
"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==",
+ "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",
@@ -4706,7 +7819,12 @@
"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-to-regexp": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
},
"node_modules/pathe": {
@@ -4720,14 +7838,12 @@
"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"
@@ -4736,6 +7852,21 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/plugin-error": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
+ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-colors": "^1.0.1",
+ "arr-diff": "^4.0.0",
+ "arr-union": "^3.1.0",
+ "extend-shallow": "^3.0.2"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/pluralize": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
@@ -4785,6 +7916,42 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/prebid.js": {
+ "version": "10.20.0",
+ "resolved": "https://registry.npmjs.org/prebid.js/-/prebid.js-10.20.0.tgz",
+ "integrity": "sha512-k+tBZos6n9zPyb74B4UtQRJAd78gh0JZ56PUJaMcJ9c3mOM6LNaadLgeNp/o2pjEWYyGzYg48mf4L67bh/RL+g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@babel/core": "^7.28.4",
+ "@babel/plugin-transform-runtime": "^7.18.9",
+ "@babel/preset-env": "^7.27.2",
+ "@babel/preset-typescript": "^7.26.0",
+ "@babel/runtime": "^7.28.3",
+ "core-js": "^3.45.1",
+ "crypto-js": "^4.2.0",
+ "dlv": "^1.1.3",
+ "dset": "^3.1.4",
+ "express": "^4.15.4",
+ "fun-hooks": "^1.1.0",
+ "gulp-babel": "^8.0.0",
+ "gulp-wrap": "^0.15.0",
+ "iab-adcom": "^1.0.6",
+ "iab-native": "^1.0.0",
+ "iab-openrtb": "^1.0.1",
+ "karma-safarinative-launcher": "^1.1.0",
+ "klona": "^2.0.6",
+ "live-connect-js": "^7.2.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "^2.3.2"
+ },
+ "peerDependencies": {
+ "schema-utils": "^4.3.2"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -4811,6 +7978,25 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
+ "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==",
+ "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/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -4821,6 +8007,30 @@
"node": ">=6"
}
},
+ "node_modules/qjobs": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
+ "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.9"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
+ "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "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",
@@ -4842,6 +8052,81 @@
],
"license": "MIT"
},
+ "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.3",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
+ "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "~3.1.2",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.4.24",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/raw-body/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/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "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/readable-stream/node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "license": "MIT"
+ },
+ "node_modules/readable-stream/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==",
+ "license": "MIT"
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -4865,6 +8150,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/regenerate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+ "license": "MIT"
+ },
+ "node_modules/regenerate-unicode-properties": {
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz",
+ "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==",
+ "license": "MIT",
+ "dependencies": {
+ "regenerate": "^1.4.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/regexp-tree": {
"version": "0.1.27",
"resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
@@ -4896,11 +8199,33 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/regexpu-core": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz",
+ "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==",
+ "license": "MIT",
+ "dependencies": {
+ "regenerate": "^1.4.2",
+ "regenerate-unicode-properties": "^10.2.2",
+ "regjsgen": "^0.8.0",
+ "regjsparser": "^0.13.0",
+ "unicode-match-property-ecmascript": "^2.0.0",
+ "unicode-match-property-value-ecmascript": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regjsgen": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz",
+ "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==",
+ "license": "MIT"
+ },
"node_modules/regjsparser": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz",
"integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==",
- "dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"jsesc": "~3.1.0"
@@ -4909,16 +8234,39 @@
"regjsparser": "bin/parser"
}
},
+ "node_modules/replace-ext": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
+ "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "license": "MIT"
+ },
"node_modules/reserved-identifiers": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/reserved-identifiers/-/reserved-identifiers-1.2.0.tgz",
@@ -4936,7 +8284,6 @@
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.1",
@@ -4974,6 +8321,28 @@
"node": ">=0.10.0"
}
},
+ "node_modules/rfdc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
+ "license": "MIT"
+ },
+ "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",
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/rollup": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
@@ -5060,6 +8429,26 @@
"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-push-apply": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
@@ -5081,7 +8470,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
@@ -5099,33 +8487,152 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/saxes": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=v12.22.7"
+ }
+ },
+ "node_modules/schema-utils": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
+ "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/schema-utils/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/schema-utils/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/schema-utils/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
+ "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "~0.5.2",
+ "http-errors": "~2.0.1",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "~2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "~2.0.2"
+ },
+ "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/saxes": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
- "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "xmlchars": "^2.2.0"
+ "node_modules/send/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": ">=v12.22.7"
+ "node": ">=4"
}
},
- "node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
+ "node_modules/serve-static": {
+ "version": "1.16.3",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
+ "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "~0.19.1"
},
"engines": {
- "node": ">=10"
+ "node": ">= 0.8.0"
}
},
"node_modules/set-function-length": {
@@ -5177,6 +8684,12 @@
"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/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -5204,7 +8717,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -5224,7 +8736,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -5241,7 +8752,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
@@ -5260,7 +8770,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
@@ -5283,6 +8792,56 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/socket.io": {
+ "version": "4.8.3",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz",
+ "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "~1.3.4",
+ "base64id": "~2.0.0",
+ "cors": "~2.8.5",
+ "debug": "~4.4.1",
+ "engine.io": "~6.6.0",
+ "socket.io-adapter": "~2.5.2",
+ "socket.io-parser": "~4.2.4"
+ },
+ "engines": {
+ "node": ">=10.2.0"
+ }
+ },
+ "node_modules/socket.io-adapter": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz",
+ "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "~4.4.1",
+ "ws": "~8.18.3"
+ }
+ },
+ "node_modules/socket.io-parser": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz",
+ "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.4.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "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==",
+ "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",
@@ -5318,6 +8877,12 @@
"dev": true,
"license": "CC0-1.0"
},
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/stackback": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
@@ -5325,6 +8890,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/std-env": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
@@ -5346,6 +8920,49 @@
"node": ">= 0.4"
}
},
+ "node_modules/streamroller": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz",
+ "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==",
+ "license": "MIT",
+ "dependencies": {
+ "date-format": "^4.0.14",
+ "debug": "^4.3.4",
+ "fs-extra": "^8.1.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string_decoder/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==",
+ "license": "MIT"
+ },
+ "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/string.prototype.trim": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
@@ -5405,6 +9022,18 @@
"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-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
@@ -5458,7 +9087,6 @@
"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"
@@ -5474,6 +9102,22 @@
"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==",
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/tiny-hashes": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tiny-hashes/-/tiny-hashes-1.0.1.tgz",
+ "integrity": "sha512-knIN5zj4fl7kW4EBU5sLP20DWUvi/rVouvJezV0UAym2DkQaqm365Nyc8F3QEiOvunNDMxR8UhcXd1d5g+Wg1g==",
+ "license": "MIT"
+ },
"node_modules/tinybench": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
@@ -5567,11 +9211,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/tmp": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
+ "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
"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"
@@ -5597,6 +9249,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "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/tough-cookie": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz",
@@ -5623,6 +9284,12 @@
"node": ">=20"
}
},
+ "node_modules/tryit": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz",
+ "integrity": "sha512-6C5h3CE+0qjGp+YKYTs74xR0k/Nw/ePtl/Lp6CCf44hqBQ66qnH1sDFR5mV/Gc48EsrHLB53lCFSffQCkka3kg==",
+ "license": "MIT"
+ },
"node_modules/ts-api-utils": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
@@ -5662,6 +9329,19 @@
"node": ">= 0.8.0"
}
},
+ "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.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
@@ -5755,6 +9435,15 @@
"node": ">=14.17"
}
},
+ "node_modules/typescript-compare": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
+ "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
+ "license": "MIT",
+ "dependencies": {
+ "typescript-logic": "^0.0.0"
+ }
+ },
"node_modules/typescript-eslint": {
"version": "8.47.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.47.0.tgz",
@@ -5779,6 +9468,47 @@
"typescript": ">=4.8.4 <6.0.0"
}
},
+ "node_modules/typescript-logic": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
+ "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==",
+ "license": "MIT"
+ },
+ "node_modules/typescript-tuple": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
+ "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "typescript-compare": "^0.0.2"
+ }
+ },
+ "node_modules/ua-parser-js": {
+ "version": "0.7.41",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz",
+ "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ua-parser-js"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/faisalman"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/faisalman"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "ua-parser-js": "script/cli.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/unbox-primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
@@ -5802,14 +9532,70 @@
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/unicode-canonical-property-names-ecmascript": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
+ "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-ecmascript": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
+ "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "unicode-canonical-property-names-ecmascript": "^2.0.0",
+ "unicode-property-aliases-ecmascript": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-value-ecmascript": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz",
+ "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-property-aliases-ecmascript": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz",
+ "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4.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/update-browserslist-db": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz",
"integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -5846,6 +9632,56 @@
"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==",
+ "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/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/vinyl-bufferstream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vinyl-bufferstream/-/vinyl-bufferstream-1.0.1.tgz",
+ "integrity": "sha512-yCCIoTf26Q9SQ0L9cDSavSL7Nt6wgQw8TU1B/bb9b9Z4A3XTypXCGdc5BvXl4ObQvVY8JrDkFnWa/UqBqwM2IA==",
+ "dependencies": {
+ "bufferstreams": "1.0.1"
+ }
+ },
+ "node_modules/vinyl-sourcemaps-apply": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz",
+ "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==",
+ "license": "ISC",
+ "dependencies": {
+ "source-map": "^0.5.1"
+ }
+ },
+ "node_modules/vinyl-sourcemaps-apply/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/vite": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz",
@@ -6049,6 +9885,15 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/void-elements": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
+ "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/w3c-xmlserializer": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
@@ -6241,11 +10086,33 @@
"node": ">=0.10.0"
}
},
+ "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==",
+ "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/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@@ -6280,6 +10147,57 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "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==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "license": "ISC"
+ },
+ "node_modules/yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "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/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==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/crates/js/lib/package.json b/crates/js/lib/package.json
index 93164d3..d6b9316 100644
--- a/crates/js/lib/package.json
+++ b/crates/js/lib/package.json
@@ -6,7 +6,6 @@
"description": "Trusted Server tsjs TypeScript library with queue and simple banner rendering.",
"scripts": {
"build": "vite build",
- "build:custom": "vite build",
"dev": "vite build --watch",
"test": "vitest run",
"test:watch": "vitest",
@@ -15,12 +14,16 @@
"format": "prettier --check \"**/*.{ts,tsx,js,json,css,md}\"",
"format:write": "prettier --write \"**/*.{ts,tsx,js,json,css,md}\""
},
+ "dependencies": {
+ "prebid.js": "^10.18.0"
+ },
"devDependencies": {
"@eslint/js": "^9.13.0",
"@types/jsdom": "^27.0.0",
"@types/node": "^24.10.0",
"@typescript-eslint/eslint-plugin": "^8.6.0",
"@typescript-eslint/parser": "^8.6.0",
+ "baseline-browser-mapping": "^2.9.16",
"eslint": "^9.10.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.29.1",
diff --git a/crates/js/lib/src/core/config.ts b/crates/js/lib/src/core/config.ts
index c06f081..b0fdbf9 100644
--- a/crates/js/lib/src/core/config.ts
+++ b/crates/js/lib/src/core/config.ts
@@ -1,9 +1,26 @@
// Global configuration storage for the tsjs runtime (mode, logging, etc.).
import { log, LogLevel } from './log';
-import type { Config } from './types';
-import { RequestMode } from './types';
+import type { Config, GamConfig } from './types';
-let CONFIG: Config = { mode: RequestMode.FirstParty };
+let CONFIG: Config = { mode: 'render' };
+
+// Lazy import to avoid circular dependencies - GAM integration may not be present
+let setGamConfigFn: ((cfg: GamConfig) => void) | null | undefined = undefined;
+
+function getSetGamConfig(): ((cfg: GamConfig) => void) | null {
+ if (setGamConfigFn === undefined) {
+ try {
+ // Dynamic import path - bundler will include if gam integration is present
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ const gam = require('../integrations/gam/index');
+ setGamConfigFn = gam.setGamConfig || null;
+ } catch {
+ // GAM integration not available
+ setGamConfigFn = null;
+ }
+ }
+ return setGamConfigFn ?? null;
+}
// Merge publisher-provided config and adjust the log level accordingly.
export function setConfig(cfg: Config): void {
@@ -12,6 +29,15 @@ export function setConfig(cfg: Config): void {
const l = cfg.logLevel as LogLevel | undefined;
if (typeof l === 'string') log.setLevel(l);
else if (debugFlag === true) log.setLevel('debug');
+
+ // Forward GAM config to the GAM integration if present
+ if (cfg.gam) {
+ const setGam = getSetGamConfig();
+ if (setGam) {
+ setGam(cfg.gam);
+ }
+ }
+
log.info('setConfig:', cfg);
}
diff --git a/crates/js/lib/src/core/global.d.ts b/crates/js/lib/src/core/global.d.ts
index c7c8b08..ea91f97 100644
--- a/crates/js/lib/src/core/global.d.ts
+++ b/crates/js/lib/src/core/global.d.ts
@@ -3,7 +3,9 @@ import type { TsjsApi } from './types';
declare global {
interface Window {
tsjs?: TsjsApi;
- pbjs?: TsjsApi;
+ // pbjs is Prebid.js which has its own types
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ pbjs?: any;
}
}
diff --git a/crates/js/lib/src/core/index.ts b/crates/js/lib/src/core/index.ts
index 227b1a3..41c8270 100644
--- a/crates/js/lib/src/core/index.ts
+++ b/crates/js/lib/src/core/index.ts
@@ -1,12 +1,8 @@
-// Public tsjs core bundle: sets up the global API, queue, and default methods.
-export type { AdUnit, TsjsApi } from './types';
+// Public tsjs core bundle: sets up the global API.
+export type { TsjsApi } from './types';
import type { TsjsApi } from './types';
-import { addAdUnits } from './registry';
-import { renderAdUnit, renderAllAdUnits } from './render';
import { log } from './log';
import { setConfig, getConfig } from './config';
-import { requestAds } from './request';
-import { installQueue } from './queue';
const VERSION = '0.1.0';
@@ -15,45 +11,12 @@ const w: Window & { tsjs?: TsjsApi } =
tsjs?: TsjsApi;
}) || ({} as Window & { tsjs?: TsjsApi });
-// Collect existing tsjs queued fns before we overwrite
-const pending: Array<() => void> = Array.isArray(w.tsjs?.que) ? [...w.tsjs.que] : [];
-
// Create API and attach methods
const api: TsjsApi = (w.tsjs ??= {} as TsjsApi);
api.version = VERSION;
-api.addAdUnits = addAdUnits;
-api.renderAdUnit = renderAdUnit;
-api.renderAllAdUnits = () => renderAllAdUnits();
api.log = log;
api.setConfig = setConfig;
api.getConfig = getConfig;
-// Provide core requestAds API
-api.requestAds = requestAds;
-// Point global tsjs
w.tsjs = api;
-// Single shared queue
-installQueue(api, w);
-
-// Flush prior queued callbacks
-for (const fn of pending) {
- try {
- if (typeof fn === 'function') {
- fn.call(api);
- log.debug('queue: flushed callback');
- }
- } catch {
- /* ignore queued callback error */
- }
-}
-
-log.info('tsjs initialized', {
- methods: [
- 'setConfig',
- 'getConfig',
- 'requestAds',
- 'addAdUnits',
- 'renderAdUnit',
- 'renderAllAdUnits',
- ],
-});
+log.info('tsjs initialized', { version: VERSION });
diff --git a/crates/js/lib/src/core/queue.ts b/crates/js/lib/src/core/queue.ts
deleted file mode 100644
index 73c2741..0000000
--- a/crates/js/lib/src/core/queue.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-// Minimal Prebid-style queue shim that executes callbacks immediately.
-import { log } from './log';
-
-// Replace the legacy Prebid-style queue with an immediate executor so queued work runs in order.
-export function installQueue void> }>(
- target: T,
- w: Window & { tsjs?: T }
-) {
- const q: Array<() => void> = [];
- q.push = ((fn: () => void) => {
- if (typeof fn === 'function') {
- try {
- fn.call(target);
- log.debug('queue: push executed immediately');
- } catch {
- /* ignore queued fn error */
- }
- }
- return q.length;
- }) as typeof q.push;
- target.que = q;
- if (w.tsjs) w.tsjs.que = q;
-}
diff --git a/crates/js/lib/src/core/registry.ts b/crates/js/lib/src/core/registry.ts
deleted file mode 100644
index ea77937..0000000
--- a/crates/js/lib/src/core/registry.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-// In-memory registry for ad units registered via tsjs (used by core + extensions).
-import type { AdUnit, Size } from './types';
-import { toArray } from './util';
-import { log } from './log';
-
-const registry = new Map();
-
-// Merge ad unit definitions into the in-memory registry (supports array or single unit).
-export function addAdUnits(units: AdUnit | AdUnit[]): void {
- for (const u of toArray(units)) {
- if (!u || !u.code) continue;
- registry.set(u.code, { ...registry.get(u.code), ...u });
- }
- log.info('addAdUnits:', { count: toArray(units).length });
-}
-
-// Convenience helper to grab the first banner size off an ad unit.
-export function firstSize(unit: AdUnit): Size | null {
- const sizes = unit.mediaTypes?.banner?.sizes;
- return sizes && sizes.length ? sizes[0] : null;
-}
-
-// Return a snapshot array of all registered ad units.
-export function getAllUnits(): AdUnit[] {
- return Array.from(registry.values());
-}
-
-// Look up a unit by its code.
-export function getUnit(code: string): AdUnit | undefined {
- return registry.get(code);
-}
-
-// Extract just the ad unit codes for quick iteration.
-export function getAllCodes(): string[] {
- return Array.from(registry.keys());
-}
diff --git a/crates/js/lib/src/core/render.ts b/crates/js/lib/src/core/render.ts
deleted file mode 100644
index 5464eb5..0000000
--- a/crates/js/lib/src/core/render.ts
+++ /dev/null
@@ -1,176 +0,0 @@
-// Rendering utilities for Trusted Server demo placements: find slots, seed placeholders,
-// and inject creatives into sandboxed iframes.
-import { log } from './log';
-import type { AdUnit } from './types';
-import { getUnit, getAllUnits, firstSize } from './registry';
-import NORMALIZE_CSS from './styles/normalize.css?inline';
-import IFRAME_TEMPLATE from './templates/iframe.html?raw';
-
-function normalizeId(raw: string): string {
- const s = String(raw ?? '').trim();
- return s.startsWith('#') ? s.slice(1) : s;
-}
-
-// Locate an ad slot element by id, tolerating funky selectors provided by tag managers.
-export function findSlot(id: string): HTMLElement | null {
- const nid = normalizeId(id);
- // Fast path
- const byId = document.getElementById(nid) as HTMLElement | null;
- if (byId) return byId;
- // Fallback for odd IDs (special chars) or if provided with quotes/etc.
- try {
- const selector = `[id="${nid.replace(/"/g, '\\"')}"]`;
- const byAttr = document.querySelector(selector) as HTMLElement | null;
- if (byAttr) return byAttr;
- } catch {
- // Ignore selector errors (e.g., invalid characters)
- }
- return null;
-}
-
-function ensureSlot(id: string): HTMLElement {
- const nid = normalizeId(id);
- let el = document.getElementById(nid) as HTMLElement | null;
- if (el) return el;
- el = document.createElement('div');
- el.id = nid;
- const body: HTMLElement | null = typeof document !== 'undefined' ? document.body : null;
- if (body && typeof body.appendChild === 'function') {
- body.appendChild(el);
- } else {
- // DOM not ready — attach once available
- const element = el;
- const onReady = () => {
- const readyBody = document.body;
- if (readyBody && !document.getElementById(nid) && element) readyBody.appendChild(element);
- };
- document.addEventListener('DOMContentLoaded', onReady, { once: true });
- }
- return el;
-}
-
-// Drop a placeholder message into the slot so pages don't sit empty pre-render.
-export function renderAdUnit(codeOrUnit: string | AdUnit): void {
- const code = typeof codeOrUnit === 'string' ? codeOrUnit : codeOrUnit?.code;
- if (!code) return;
- const unit = typeof codeOrUnit === 'string' ? getUnit(code) : codeOrUnit;
- const size = (unit && firstSize(unit)) || [300, 250];
- const el = ensureSlot(code);
- try {
- el.textContent = `Trusted Server — ${size[0]}x${size[1]}`;
- log.info('renderAdUnit: rendered placeholder', { code, size });
- } catch {
- log.warn('renderAdUnit: failed', { code });
- }
-}
-
-// Render placeholders for every registered ad unit (used in simple publisher demos).
-export function renderAllAdUnits(): void {
- try {
- const parentReady =
- typeof document !== 'undefined' && (document.body || document.documentElement);
- if (!parentReady) {
- log.warn('renderAllAdUnits: DOM not ready; skipping');
- return;
- }
- const units = getAllUnits();
- for (const u of units) {
- renderAdUnit(u);
- }
- log.info('renderAllAdUnits: rendered all placeholders', { count: units.length });
- } catch (e) {
- log.warn('renderAllAdUnits: failed', e as unknown);
- }
-}
-
-// Swap the slot contents for a creative iframe and write HTML into it safely.
-export function renderCreativeIntoSlot(slotId: string, html: string): void {
- const el = findSlot(slotId);
- if (!el) {
- log.warn('renderCreativeIntoSlot: slot not found; skipping render', { slotId });
- return;
- }
- try {
- // Clear previous content
- el.innerHTML = '';
- // Determine size if available
- const unit = getUnit(slotId);
- const sz = (unit && firstSize(unit)) || [300, 250];
- const iframe = createAdIframe(el, {
- name: `tsjs_iframe_${slotId}`,
- title: 'Ad content',
- width: sz[0],
- height: sz[1],
- });
- writeHtmlToIframe(iframe, html);
- log.info('renderCreativeIntoSlot: rendered', { slotId, width: sz[0], height: sz[1] });
- } catch (err) {
- log.warn('renderCreativeIntoSlot: failed', { slotId, err });
- }
-}
-
-type IframeOptions = { name?: string; title?: string; width?: number; height?: number };
-
-// Construct a sandboxed iframe sized for the ad so we can render arbitrary HTML.
-export function createAdIframe(
- container: HTMLElement,
- opts: IframeOptions = {}
-): HTMLIFrameElement {
- const iframe = document.createElement('iframe');
- // Attributes
- iframe.scrolling = 'no';
- iframe.frameBorder = '0';
- iframe.setAttribute('marginwidth', '0');
- iframe.setAttribute('marginheight', '0');
- if (opts.name) iframe.name = String(opts.name);
- iframe.title = opts.title || 'Ad content';
- iframe.setAttribute('aria-label', 'Advertisement');
- // Sandbox permissions for creatives
- try {
- iframe.sandbox.add(
- 'allow-forms',
- 'allow-popups',
- 'allow-popups-to-escape-sandbox',
- 'allow-same-origin',
- 'allow-scripts',
- 'allow-top-navigation-by-user-activation'
- );
- } catch (err) {
- log.debug('createAdIframe: sandbox add failed', err);
- }
- // Sizing + style
- const w = Math.max(0, Number(opts.width ?? 0) | 0);
- const h = Math.max(0, Number(opts.height ?? 0) | 0);
- if (w > 0) iframe.width = String(w);
- if (h > 0) iframe.height = String(h);
- const s = iframe.style;
- s.setProperty('border', '0');
- s.setProperty('margin', '0');
- s.setProperty('overflow', 'hidden');
- s.setProperty('display', 'block');
- if (w > 0) s.setProperty('width', `${w}px`);
- if (h > 0) s.setProperty('height', `${h}px`);
- // Insert into container
- container.appendChild(iframe);
- return iframe;
-}
-
-function writeHtmlToIframe(iframe: HTMLIFrameElement, creativeHtml: string): void {
- try {
- const doc = (iframe.contentDocument || iframe.contentWindow?.document) as Document | undefined;
- if (!doc) return;
- const html = buildIframeDocument(creativeHtml);
- doc.open();
- doc.write(html);
- doc.close();
- } catch (err) {
- log.warn('renderCreativeIntoSlot: iframe write failed', { err });
- }
-}
-
-function buildIframeDocument(creativeHtml: string): string {
- return IFRAME_TEMPLATE.replace('%NORMALIZE_CSS%', NORMALIZE_CSS).replace(
- '%CREATIVE_HTML%',
- creativeHtml
- );
-}
diff --git a/crates/js/lib/src/core/request.ts b/crates/js/lib/src/core/request.ts
deleted file mode 100644
index 98e04a3..0000000
--- a/crates/js/lib/src/core/request.ts
+++ /dev/null
@@ -1,156 +0,0 @@
-// Request orchestration for tsjs: fires first-party iframe loads or third-party fetches.
-import { delay } from '../shared/async';
-
-import { log } from './log';
-import { getAllUnits, firstSize } from './registry';
-import { renderCreativeIntoSlot, renderAllAdUnits, createAdIframe, findSlot } from './render';
-import { getConfig } from './config';
-import { RequestMode } from './types';
-import type { RequestAdsCallback, RequestAdsOptions } from './types';
-
-// getHighestCpmBids is provided by the Prebid extension (shim) to mirror Prebid's API
-
-// Entry point matching Prebid's requestBids signature; decides first/third-party mode.
-export function requestAds(
- callbackOrOpts?: RequestAdsCallback | RequestAdsOptions,
- maybeOpts?: RequestAdsOptions
-): void {
- let callback: RequestAdsCallback | undefined;
- let opts: RequestAdsOptions | undefined;
- if (typeof callbackOrOpts === 'function') {
- callback = callbackOrOpts as RequestAdsCallback;
- opts = maybeOpts;
- } else {
- opts = callbackOrOpts as RequestAdsOptions | undefined;
- callback = opts?.bidsBackHandler;
- }
-
- const mode: RequestMode = (getConfig().mode as RequestMode | undefined) ?? RequestMode.FirstParty;
- log.info('requestAds: called', { hasCallback: typeof callback === 'function', mode });
- try {
- const adUnits = getAllUnits();
- const payload = { adUnits, config: {} };
- log.debug('requestAds: payload', { units: adUnits.length });
- if (mode === RequestMode.FirstParty) void requestAdsFirstParty(adUnits);
- else requestAdsThirdParty(payload);
- // Synchronously invoke callback to match test expectations
- try {
- if (callback) callback();
- } catch {
- /* ignore callback errors */
- }
- // network handled in requestAdsThirdParty; no-op here
- } catch {
- log.warn('requestAds: failed to initiate');
- }
-}
-
-// Create per-slot first-party iframe requests served directly from the edge.
-async function requestAdsFirstParty(adUnits: ReadonlyArray<{ code: string }>) {
- for (const unit of adUnits) {
- const size = (firstSize(unit) ?? [300, 250]) as readonly [number, number];
- const slotId = unit.code;
-
- const attemptInsert = async (attemptsRemaining: number): Promise => {
- const container = findSlot(slotId) as HTMLElement | null;
- if (container) {
- const iframe = createAdIframe(container, {
- name: `tsjs_iframe_${slotId}`,
- title: 'Ad content',
- width: size[0],
- height: size[1],
- });
- iframe.src = `/first-party/ad?slot=${encodeURIComponent(slotId)}&w=${encodeURIComponent(String(size[0]))}&h=${encodeURIComponent(String(size[1]))}`;
- return;
- }
-
- if (attemptsRemaining <= 0) {
- log.warn('requestAds(firstParty): slot not found; skipping iframe', { slotId });
- return;
- }
-
- if (typeof document !== 'undefined' && document.readyState === 'loading') {
- document.addEventListener(
- 'DOMContentLoaded',
- () => {
- void attemptInsert(attemptsRemaining - 1);
- },
- { once: true }
- );
- return;
- }
-
- await delay(50);
- await attemptInsert(attemptsRemaining - 1);
- };
-
- void attemptInsert(10);
- }
-}
-
-// Fire a JSON POST to the third-party ad endpoint and render returned creatives.
-function requestAdsThirdParty(payload: { adUnits: unknown[]; config: unknown }) {
- // Render simple placeholders immediately so pages have content
- renderAllAdUnits();
- if (typeof fetch !== 'function') {
- log.warn('requestAds: fetch not available; nothing to render');
- return;
- }
- log.info('requestAds: sending request to /third-party/ad', {
- units: (payload.adUnits || []).length,
- });
- void fetch('/third-party/ad', {
- method: 'POST',
- headers: { 'content-type': 'application/json' },
- credentials: 'same-origin',
- body: JSON.stringify(payload),
- keepalive: true,
- })
- .then(async (res) => {
- log.debug('requestAds: sent');
- try {
- const ct = res.headers.get('content-type') || '';
- if (res.ok && ct.includes('application/json')) {
- const data: unknown = await res.json();
- for (const bid of parseSeatBids(data)) {
- if (bid.impid && bid.adm) renderCreativeIntoSlot(String(bid.impid), bid.adm);
- }
- log.info('requestAds: rendered creatives from response');
- return;
- }
- log.warn('requestAds: unexpected response', { ok: res.ok, status: res.status, ct });
- } catch (err) {
- log.warn('requestAds: failed to process response', err);
- }
- })
- .catch((e) => {
- log.warn('requestAds: failed', e);
- });
-}
-
-// Local minimal OpenRTB typing to keep core decoupled from Prebid extension types
-type RtBid = { impid?: string; adm?: string };
-type RtSeatBid = { bid?: RtBid[] | null };
-type RtResponse = { seatbid?: RtSeatBid[] | null };
-
-function isSeatBidArray(x: unknown): x is RtSeatBid[] {
- return Array.isArray(x);
-}
-
-// Minimal OpenRTB seatbid parser—just enough to render adm by impid.
-function parseSeatBids(data: unknown): RtBid[] {
- const out: RtBid[] = [];
- const resp = data as Partial;
- const seatbids = resp && resp.seatbid;
- if (!seatbids || !isSeatBidArray(seatbids)) return out;
- for (const sb of seatbids) {
- const bids = sb && sb.bid;
- if (!Array.isArray(bids)) continue;
- for (const b of bids) {
- const impid = typeof b?.impid === 'string' ? b!.impid : undefined;
- const adm = typeof b?.adm === 'string' ? b!.adm : undefined;
- out.push({ impid, adm });
- }
- }
- return out;
-}
diff --git a/crates/js/lib/src/core/styles/normalize.css b/crates/js/lib/src/core/styles/normalize.css
deleted file mode 100644
index da77bad..0000000
--- a/crates/js/lib/src/core/styles/normalize.css
+++ /dev/null
@@ -1,169 +0,0 @@
-/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
-button,
-hr,
-input {
- overflow: visible;
-}
-
-progress,
-sub,
-sup {
- vertical-align: baseline;
-}
-
-[type='checkbox'],
-[type='radio'],
-legend {
- box-sizing: border-box;
- padding: 0;
-}
-
-html {
- line-height: 1.15;
- -webkit-text-size-adjust: 100%;
-}
-
-body {
- margin: 0;
-}
-
-details,
-main {
- display: block;
-}
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-hr {
- box-sizing: content-box;
- height: 0;
-}
-
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-a {
- background-color: transparent;
-}
-
-abbr[title] {
- border-bottom: none;
- text-decoration: underline dotted;
-}
-
-b,
-strong {
- font-weight: bolder;
-}
-
-small {
- font-size: 80%;
-}
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-sup {
- top: -0.5em;
-}
-
-img {
- border-style: none;
-}
-
-button,
-input,
-optgroup,
-select,
-textarea {
- font-family: inherit;
- font-size: 100%;
- line-height: 1.15;
- margin: 0;
-}
-
-button,
-select {
- text-transform: none;
-}
-
-[type='button'],
-[type='reset'],
-[type='submit'],
-button {
- -webkit-appearance: button;
-}
-
-[type='button']::-moz-focus-inner,
-[type='reset']::-moz-focus-inner,
-[type='submit']::-moz-focus-inner,
-button::-moz-focus-inner {
- border-style: none;
- padding: 0;
-}
-
-[type='button']:-moz-focusring,
-[type='reset']:-moz-focusring,
-[type='submit']:-moz-focusring,
-button:-moz-focusring {
- outline: 1px dotted ButtonText;
-}
-
-fieldset {
- padding: 0.35em 0.75em 0.625em;
-}
-
-legend {
- color: inherit;
- display: table;
- max-width: 100%;
- white-space: normal;
-}
-
-textarea {
- overflow: auto;
-}
-
-[type='number']::-webkit-inner-spin-button,
-[type='number']::-webkit-outer-spin-button {
- height: auto;
-}
-
-[type='search'] {
- -webkit-appearance: textfield;
- outline-offset: -2px;
-}
-
-[type='search']::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-::-webkit-file-upload-button {
- -webkit-appearance: button;
- font: inherit;
-}
-
-summary {
- display: list-item;
-}
-
-[hidden],
-template {
- display: none;
-}
diff --git a/crates/js/lib/src/core/templates/iframe.html b/crates/js/lib/src/core/templates/iframe.html
deleted file mode 100644
index 55af0d5..0000000
--- a/crates/js/lib/src/core/templates/iframe.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
- %CREATIVE_HTML%
-
diff --git a/crates/js/lib/src/core/types.ts b/crates/js/lib/src/core/types.ts
index 3bf1b49..acbbc6a 100644
--- a/crates/js/lib/src/core/types.ts
+++ b/crates/js/lib/src/core/types.ts
@@ -1,75 +1,37 @@
-// Shared TypeScript types for the tsjs core API and extensions.
-export type Size = readonly [number, number];
+// Shared TypeScript types for the tsjs core API.
-export interface Banner {
- sizes: ReadonlyArray;
-}
+export type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'debug';
-export interface MediaTypes {
- banner?: Banner;
+export interface GamConfig {
+ /** Enable the GAM interceptor. Defaults to false. */
+ enabled?: boolean;
+ /** Only intercept bids from these bidders. Empty array = all bidders. */
+ bidders?: string[];
+ /** Force render Prebid creative even if GAM returned a line item. Defaults to false. */
+ forceRender?: boolean;
}
-export interface AdUnit {
- code: string;
- mediaTypes?: MediaTypes;
+export interface Config {
+ debug?: boolean;
+ logLevel?: LogLevel;
+ /** Select ad serving mode: 'render' or 'auction'. */
+ mode?: 'render' | 'auction';
+ /** GAM interceptor configuration. */
+ gam?: GamConfig;
+ // Extendable for future fields
+ [key: string]: unknown;
}
export interface TsjsApi {
version: string;
- que: Array<() => void>;
- addAdUnits(units: AdUnit | AdUnit[]): void;
- renderAdUnit(codeOrUnit: string | AdUnit): void;
- renderAllAdUnits(): void;
- setConfig?(cfg: Config): void;
- getConfig?(): Config;
- // Core API: requestAds; accepts same signatures as Prebid's requestBids
- requestAds?(opts?: RequestAdsOptions): void;
- requestAds?(callback: RequestAdsCallback, opts?: RequestAdsOptions): void;
- getHighestCpmBids?(adUnitCodes?: string | string[]): ReadonlyArray;
- log?: {
- setLevel(l: 'silent' | 'error' | 'warn' | 'info' | 'debug'): void;
- getLevel(): 'silent' | 'error' | 'warn' | 'info' | 'debug';
+ setConfig(cfg: Config): void;
+ getConfig(): Config;
+ log: {
+ setLevel(l: LogLevel): void;
+ getLevel(): LogLevel;
info(...args: unknown[]): void;
warn(...args: unknown[]): void;
error(...args: unknown[]): void;
debug(...args: unknown[]): void;
};
}
-
-export enum RequestMode {
- FirstParty = 'firstParty',
- ThirdParty = 'thirdParty',
-}
-
-export interface Config {
- debug?: boolean;
- logLevel?: 'silent' | 'error' | 'warn' | 'info' | 'debug';
- /** Select ad serving mode. Default is RequestMode.FirstParty. */
- mode?: RequestMode;
- // Extendable for future fields
- [key: string]: unknown;
-}
-
-// Core-neutral request types
-export type RequestAdsCallback = () => void;
-export interface RequestAdsOptions {
- bidsBackHandler?: RequestAdsCallback;
- timeout?: number;
-}
-
-// Back-compat aliases for Prebid-style naming (used by the extension shim)
-export type RequestBidsCallback = RequestAdsCallback;
-
-export interface HighestCpmBid {
- adUnitCode: string;
- width: number;
- height: number;
- cpm: number;
- currency: string;
- bidderCode: string;
- creativeId: string;
- adserverTargeting: Record;
-}
-
-// Minimal OpenRTB response typing
-// OpenRTB response typing is specific to the Prebid extension and lives in src/ext/types.ts
diff --git a/crates/js/lib/src/core/util.ts b/crates/js/lib/src/core/util.ts
deleted file mode 100644
index be9a855..0000000
--- a/crates/js/lib/src/core/util.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-// Tiny shared helpers used across core modules.
-export function isArray(v: unknown): v is T[] {
- return Array.isArray(v);
-}
-
-// Normalise a single value into an array for simple iteration helpers.
-export function toArray(v: T | T[]): T[] {
- return isArray(v) ? v : [v];
-}
diff --git a/crates/js/lib/src/index.ts b/crates/js/lib/src/index.ts
index bfe6e69..9a5a505 100644
--- a/crates/js/lib/src/index.ts
+++ b/crates/js/lib/src/index.ts
@@ -35,7 +35,7 @@ for (const [moduleName, moduleExports] of Object.entries(modules)) {
}
// Re-export core types for convenience
-export type { AdUnit, TsjsApi } from './core/types';
+export type { TsjsApi } from './core/types';
// Export the modules object for advanced use cases
export { modules };
diff --git a/crates/js/lib/src/integrations/ext/index.ts b/crates/js/lib/src/integrations/ext/index.ts
deleted file mode 100644
index 2cf7971..0000000
--- a/crates/js/lib/src/integrations/ext/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { installPrebidJsShim } from './prebidjs';
-
-// Execute immediately on import; safe no-op if pbjs is not present.
-void installPrebidJsShim();
diff --git a/crates/js/lib/src/integrations/ext/prebidjs.ts b/crates/js/lib/src/integrations/ext/prebidjs.ts
deleted file mode 100644
index 242ebc0..0000000
--- a/crates/js/lib/src/integrations/ext/prebidjs.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-// Prebid.js compatibility shim: exposes tsjs API through the legacy pbjs global.
-import type {
- TsjsApi,
- HighestCpmBid,
- RequestAdsCallback,
- RequestAdsOptions,
-} from '../../core/types';
-import { log } from '../../core/log';
-import { installQueue } from '../../core/queue';
-import { getAllCodes, getAllUnits, firstSize } from '../../core/registry';
-import { resolvePrebidWindow, PrebidWindow } from '../../shared/globals';
-type RequestBidsFunction = (
- callbackOrOpts?: RequestAdsCallback | RequestAdsOptions,
- opts?: RequestAdsOptions
-) => void;
-
-/**
- * Shim implementation for pbjs.getHighestCpmBids that returns synthetic
- * placeholder bids derived from the registered core ad units.
- */
-function getHighestCpmBidsShim(adUnitCodes?: string | string[]): ReadonlyArray {
- const codes: string[] =
- typeof adUnitCodes === 'string' ? [adUnitCodes] : (adUnitCodes ?? getAllCodes());
- const results: HighestCpmBid[] = [];
- for (const code of codes) {
- const unit = getAllUnits().find((u) => u.code === code);
- if (!unit) continue;
- const size = (firstSize(unit) ?? [300, 250]) as readonly [number, number];
- results.push({
- adUnitCode: code,
- width: size[0],
- height: size[1],
- cpm: 0,
- currency: 'USD',
- bidderCode: 'tsjs',
- creativeId: 'tsjs-placeholder',
- adserverTargeting: {},
- });
- }
- return results;
-}
-
-/**
- * Shim implementation for pbjs.requestBids that forwards to core requestAds.
- */
-function requestBidsShim(api: TsjsApi): RequestBidsFunction {
- return (callbackOrOpts?: RequestAdsCallback | RequestAdsOptions, opts?: RequestAdsOptions) => {
- const requestAds = api.requestAds as
- | ((options?: RequestAdsOptions) => void)
- | ((callback: RequestAdsCallback, options?: RequestAdsOptions) => void)
- | undefined;
- if (!requestAds) return;
- if (typeof callbackOrOpts === 'function') {
- requestAds(callbackOrOpts, opts);
- } else {
- requestAds(callbackOrOpts);
- }
- };
-}
-
-// Guarantee a tsjs API stub exists so we can alias pbjs onto it.
-function ensureTsjsApi(win: PrebidWindow): TsjsApi {
- if (win.tsjs) return win.tsjs;
- const stub: TsjsApi = {
- version: '0.0.0',
- que: [],
- addAdUnits: () => undefined,
- renderAdUnit: () => undefined,
- renderAllAdUnits: () => undefined,
- };
- win.tsjs = stub;
- return stub;
-}
-
-// Bridge the minimal tsjs API onto the legacy pbjs global so existing tags keep working.
-export function installPrebidJsShim(): boolean {
- const w = resolvePrebidWindow();
-
- // Ensure core exists
- const api = ensureTsjsApi(w);
-
- // Capture any queued pbjs callbacks before aliasing
- const pending: Array<() => void> = Array.isArray(w.pbjs?.que) ? [...(w.pbjs?.que ?? [])] : [];
-
- // Core provides requestAds/getHighestCpmBids; extension aliases pbjs and shims requestBids → requestAds
-
- // Alias pbjs to tsjs and ensure a single shared queue
- w.pbjs = api;
- if (!Array.isArray(api.que)) {
- installQueue(api, w);
- }
- const pbjsApi = w.pbjs as TsjsApi & { requestBids?: RequestBidsFunction };
- // Make sure both globals share the same queue
- if (Array.isArray(api.que)) {
- pbjsApi.que = api.que;
- }
- // Shim Prebid-style API surface
- pbjsApi.requestBids = requestBidsShim(api);
- pbjsApi.getHighestCpmBids = getHighestCpmBidsShim;
-
- // Flush previously queued pbjs callbacks
- for (const fn of pending) {
- try {
- if (typeof fn === 'function') {
- fn.call(api);
- log.debug('prebidjs extension: flushed callback');
- }
- } catch (err) {
- log.debug('prebidjs extension: queued callback failed', err);
- }
- }
-
- log.info('prebidjs extension installed', {
- hasRequestBids: typeof pbjsApi.requestBids === 'function',
- hasGetHighestCpmBids: typeof pbjsApi.getHighestCpmBids === 'function',
- });
-
- return true;
-}
-
-export default installPrebidJsShim;
diff --git a/crates/js/lib/src/integrations/ext/types.ts b/crates/js/lib/src/integrations/ext/types.ts
deleted file mode 100644
index a83a499..0000000
--- a/crates/js/lib/src/integrations/ext/types.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-// Minimal OpenRTB response typing (used by the Prebid extension)
-export interface OpenRtbBid {
- impid?: string;
- adm?: string;
- [key: string]: unknown;
-}
-export interface OpenRtbSeatBid {
- bid?: OpenRtbBid[] | null;
-}
-export interface OpenRtbBidResponse {
- seatbid?: OpenRtbSeatBid[] | null;
-}
diff --git a/crates/js/lib/src/integrations/gam/index.ts b/crates/js/lib/src/integrations/gam/index.ts
new file mode 100644
index 0000000..2832067
--- /dev/null
+++ b/crates/js/lib/src/integrations/gam/index.ts
@@ -0,0 +1,396 @@
+// GAM (Google Ad Manager) Interceptor - forces Prebid creatives to render when
+// GAM doesn't have matching line items configured.
+//
+// This integration intercepts GPT's slotRenderEnded event and replaces GAM's
+// creative with the Prebid winning bid when:
+// 1. A Prebid bid exists for the slot (hb_adid targeting is set)
+// 2. The bid meets the configured criteria (specific bidder or any bidder)
+//
+// Configuration options:
+// - enabled: boolean (default: false) - Master switch for the interceptor
+// - bidders: string[] (default: []) - Only intercept for these bidders. Empty = all bidders
+// - forceRender: boolean (default: false) - Render even if GAM has a line item
+//
+// Usage:
+// window.tsGamConfig = { enabled: true, bidders: ['mocktioneer'] };
+// // or via tsjs.setConfig({ gam: { enabled: true, bidders: ['mocktioneer'] } })
+
+import { log } from '../../core/log';
+
+export interface TsGamConfig {
+ /** Enable the GAM interceptor. Defaults to false. */
+ enabled?: boolean;
+ /** Only intercept bids from these bidders. Empty array = all bidders. */
+ bidders?: string[];
+ /** Force render Prebid creative even if GAM returned a line item. Defaults to false. */
+ forceRender?: boolean;
+}
+
+export interface TsGamApi {
+ setConfig(cfg: TsGamConfig): void;
+ getConfig(): TsGamConfig;
+ getStats(): GamInterceptStats;
+}
+
+interface GamInterceptStats {
+ intercepted: number;
+ rendered: Array<{
+ slotId: string;
+ adId: string;
+ bidder: string;
+ method: string;
+ timestamp: number;
+ }>;
+}
+
+type GamWindow = Window & {
+ googletag?: {
+ pubads?: () => {
+ addEventListener: (event: string, callback: (e: SlotRenderEndedEvent) => void) => void;
+ getSlots?: () => GptSlot[];
+ };
+ };
+ pbjs?: {
+ getBidResponsesForAdUnitCode?: (code: string) => { bids?: PrebidBid[] };
+ renderAd?: (doc: Document, adId: string) => void;
+ };
+ tsGamConfig?: TsGamConfig;
+ __tsGamInstalled?: boolean;
+};
+
+interface SlotRenderEndedEvent {
+ slot: GptSlot;
+ isEmpty: boolean;
+ lineItemId: number | null;
+}
+
+interface GptSlot {
+ getSlotElementId(): string;
+ getTargeting(key: string): string[];
+ getTargetingKeys(): string[];
+}
+
+interface PrebidBid {
+ adId?: string;
+ ad?: string;
+ adUrl?: string;
+ bidder?: string;
+ cpm?: number;
+}
+
+interface IframeAttrs {
+ src: string;
+ width?: string;
+ height?: string;
+}
+
+/**
+ * Extract iframe attributes from a creative that is just an iframe wrapper.
+ * Returns null if the creative is not a simple iframe tag.
+ * Exported for testing.
+ */
+export function extractIframeAttrs(html: string): IframeAttrs | null {
+ const trimmed = html.trim();
+ // Check if it's a simple iframe tag (possibly with whitespace/newline after)
+ if (!trimmed.toLowerCase().startsWith('