diff --git a/.agents/skills/supabase-postgres-best-practices/AGENTS.md b/.agents/skills/supabase-postgres-best-practices/AGENTS.md new file mode 100644 index 00000000..a7baf445 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/AGENTS.md @@ -0,0 +1,68 @@ +# Supabase Postgres Best Practices + +## Structure + +``` +supabase-postgres-best-practices/ + SKILL.md # Main skill file - read this first + AGENTS.md # This navigation guide + CLAUDE.md # Symlink to AGENTS.md + references/ # Detailed reference files +``` + +## Usage + +1. Read `SKILL.md` for the main skill instructions +2. Browse `references/` for detailed documentation on specific topics +3. Reference files are loaded on-demand - read only what you need + +Comprehensive performance optimization guide for Postgres, maintained by Supabase. Contains rules across 8 categories, prioritized by impact to guide automated query optimization and schema design. + +## When to Apply + +Reference these guidelines when: +- Writing SQL queries or designing schemas +- Implementing indexes or query optimization +- Reviewing database performance issues +- Configuring connection pooling or scaling +- Optimizing for Postgres-specific features +- Working with Row-Level Security (RLS) + +## Rule Categories by Priority + +| Priority | Category | Impact | Prefix | +|----------|----------|--------|--------| +| 1 | Query Performance | CRITICAL | `query-` | +| 2 | Connection Management | CRITICAL | `conn-` | +| 3 | Security & RLS | CRITICAL | `security-` | +| 4 | Schema Design | HIGH | `schema-` | +| 5 | Concurrency & Locking | MEDIUM-HIGH | `lock-` | +| 6 | Data Access Patterns | MEDIUM | `data-` | +| 7 | Monitoring & Diagnostics | LOW-MEDIUM | `monitor-` | +| 8 | Advanced Features | LOW | `advanced-` | + +## How to Use + +Read individual rule files for detailed explanations and SQL examples: + +``` +references/query-missing-indexes.md +references/schema-partial-indexes.md +references/_sections.md +``` + +Each rule file contains: +- Brief explanation of why it matters +- Incorrect SQL example with explanation +- Correct SQL example with explanation +- Optional EXPLAIN output or metrics +- Additional context and references +- Supabase-specific notes (when applicable) + +## References + +- https://www.postgresql.org/docs/current/ +- https://supabase.com/docs +- https://wiki.postgresql.org/wiki/Performance_Optimization +- https://supabase.com/docs/guides/database/overview +- https://supabase.com/docs/guides/auth/row-level-security diff --git a/.agents/skills/supabase-postgres-best-practices/CLAUDE.md b/.agents/skills/supabase-postgres-best-practices/CLAUDE.md new file mode 100644 index 00000000..a7baf445 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/CLAUDE.md @@ -0,0 +1,68 @@ +# Supabase Postgres Best Practices + +## Structure + +``` +supabase-postgres-best-practices/ + SKILL.md # Main skill file - read this first + AGENTS.md # This navigation guide + CLAUDE.md # Symlink to AGENTS.md + references/ # Detailed reference files +``` + +## Usage + +1. Read `SKILL.md` for the main skill instructions +2. Browse `references/` for detailed documentation on specific topics +3. Reference files are loaded on-demand - read only what you need + +Comprehensive performance optimization guide for Postgres, maintained by Supabase. Contains rules across 8 categories, prioritized by impact to guide automated query optimization and schema design. + +## When to Apply + +Reference these guidelines when: +- Writing SQL queries or designing schemas +- Implementing indexes or query optimization +- Reviewing database performance issues +- Configuring connection pooling or scaling +- Optimizing for Postgres-specific features +- Working with Row-Level Security (RLS) + +## Rule Categories by Priority + +| Priority | Category | Impact | Prefix | +|----------|----------|--------|--------| +| 1 | Query Performance | CRITICAL | `query-` | +| 2 | Connection Management | CRITICAL | `conn-` | +| 3 | Security & RLS | CRITICAL | `security-` | +| 4 | Schema Design | HIGH | `schema-` | +| 5 | Concurrency & Locking | MEDIUM-HIGH | `lock-` | +| 6 | Data Access Patterns | MEDIUM | `data-` | +| 7 | Monitoring & Diagnostics | LOW-MEDIUM | `monitor-` | +| 8 | Advanced Features | LOW | `advanced-` | + +## How to Use + +Read individual rule files for detailed explanations and SQL examples: + +``` +references/query-missing-indexes.md +references/schema-partial-indexes.md +references/_sections.md +``` + +Each rule file contains: +- Brief explanation of why it matters +- Incorrect SQL example with explanation +- Correct SQL example with explanation +- Optional EXPLAIN output or metrics +- Additional context and references +- Supabase-specific notes (when applicable) + +## References + +- https://www.postgresql.org/docs/current/ +- https://supabase.com/docs +- https://wiki.postgresql.org/wiki/Performance_Optimization +- https://supabase.com/docs/guides/database/overview +- https://supabase.com/docs/guides/auth/row-level-security diff --git a/.agents/skills/supabase-postgres-best-practices/README.md b/.agents/skills/supabase-postgres-best-practices/README.md new file mode 100644 index 00000000..f1a374e1 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/README.md @@ -0,0 +1,116 @@ +# Supabase Postgres Best Practices - Contributor Guide + +This skill contains Postgres performance optimization references optimized for +AI agents and LLMs. It follows the [Agent Skills Open Standard](https://agentskills.io/). + +## Quick Start + +```bash +# From repository root +npm install + +# Validate existing references +npm run validate + +# Build AGENTS.md +npm run build +``` + +## Creating a New Reference + +1. **Choose a section prefix** based on the category: + - `query-` Query Performance (CRITICAL) + - `conn-` Connection Management (CRITICAL) + - `security-` Security & RLS (CRITICAL) + - `schema-` Schema Design (HIGH) + - `lock-` Concurrency & Locking (MEDIUM-HIGH) + - `data-` Data Access Patterns (MEDIUM) + - `monitor-` Monitoring & Diagnostics (LOW-MEDIUM) + - `advanced-` Advanced Features (LOW) + +2. **Copy the template**: + ```bash + cp references/_template.md references/query-your-reference-name.md + ``` + +3. **Fill in the content** following the template structure + +4. **Validate and build**: + ```bash + npm run validate + npm run build + ``` + +5. **Review** the generated `AGENTS.md` + +## Skill Structure + +``` +skills/supabase-postgres-best-practices/ +├── SKILL.md # Agent-facing skill manifest (Agent Skills spec) +├── AGENTS.md # [GENERATED] Compiled references document +├── README.md # This file +└── references/ + ├── _template.md # Reference template + ├── _sections.md # Section definitions + ├── _contributing.md # Writing guidelines + └── *.md # Individual references + +packages/skills-build/ +├── src/ # Generic build system source +└── package.json # NPM scripts +``` + +## Reference File Structure + +See `references/_template.md` for the complete template. Key elements: + +````markdown +--- +title: Clear, Action-Oriented Title +impact: CRITICAL|HIGH|MEDIUM-HIGH|MEDIUM|LOW-MEDIUM|LOW +impactDescription: Quantified benefit (e.g., "10-100x faster") +tags: relevant, keywords +--- + +## [Title] + +[1-2 sentence explanation] + +**Incorrect (description):** + +```sql +-- Comment explaining what's wrong +[Bad SQL example] +``` +```` + +**Correct (description):** + +```sql +-- Comment explaining why this is better +[Good SQL example] +``` + +``` +## Writing Guidelines + +See `references/_contributing.md` for detailed guidelines. Key principles: + +1. **Show concrete transformations** - "Change X to Y", not abstract advice +2. **Error-first structure** - Show the problem before the solution +3. **Quantify impact** - Include specific metrics (10x faster, 50% smaller) +4. **Self-contained examples** - Complete, runnable SQL +5. **Semantic naming** - Use meaningful names (users, email), not (table1, col1) + +## Impact Levels + +| Level | Improvement | Examples | +|-------|-------------|----------| +| CRITICAL | 10-100x | Missing indexes, connection exhaustion | +| HIGH | 5-20x | Wrong index types, poor partitioning | +| MEDIUM-HIGH | 2-5x | N+1 queries, RLS optimization | +| MEDIUM | 1.5-3x | Redundant indexes, stale statistics | +| LOW-MEDIUM | 1.2-2x | VACUUM tuning, config tweaks | +| LOW | Incremental | Advanced patterns, edge cases | +``` diff --git a/.agents/skills/supabase-postgres-best-practices/SKILL.md b/.agents/skills/supabase-postgres-best-practices/SKILL.md new file mode 100644 index 00000000..f80be156 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/SKILL.md @@ -0,0 +1,64 @@ +--- +name: supabase-postgres-best-practices +description: Postgres performance optimization and best practices from Supabase. Use this skill when writing, reviewing, or optimizing Postgres queries, schema designs, or database configurations. +license: MIT +metadata: + author: supabase + version: "1.1.0" + organization: Supabase + date: January 2026 + abstract: Comprehensive Postgres performance optimization guide for developers using Supabase and Postgres. Contains performance rules across 8 categories, prioritized by impact from critical (query performance, connection management) to incremental (advanced features). Each rule includes detailed explanations, incorrect vs. correct SQL examples, query plan analysis, and specific performance metrics to guide automated optimization and code generation. +--- + +# Supabase Postgres Best Practices + +Comprehensive performance optimization guide for Postgres, maintained by Supabase. Contains rules across 8 categories, prioritized by impact to guide automated query optimization and schema design. + +## When to Apply + +Reference these guidelines when: +- Writing SQL queries or designing schemas +- Implementing indexes or query optimization +- Reviewing database performance issues +- Configuring connection pooling or scaling +- Optimizing for Postgres-specific features +- Working with Row-Level Security (RLS) + +## Rule Categories by Priority + +| Priority | Category | Impact | Prefix | +|----------|----------|--------|--------| +| 1 | Query Performance | CRITICAL | `query-` | +| 2 | Connection Management | CRITICAL | `conn-` | +| 3 | Security & RLS | CRITICAL | `security-` | +| 4 | Schema Design | HIGH | `schema-` | +| 5 | Concurrency & Locking | MEDIUM-HIGH | `lock-` | +| 6 | Data Access Patterns | MEDIUM | `data-` | +| 7 | Monitoring & Diagnostics | LOW-MEDIUM | `monitor-` | +| 8 | Advanced Features | LOW | `advanced-` | + +## How to Use + +Read individual rule files for detailed explanations and SQL examples: + +``` +references/query-missing-indexes.md +references/schema-partial-indexes.md +references/_sections.md +``` + +Each rule file contains: +- Brief explanation of why it matters +- Incorrect SQL example with explanation +- Correct SQL example with explanation +- Optional EXPLAIN output or metrics +- Additional context and references +- Supabase-specific notes (when applicable) + +## References + +- https://www.postgresql.org/docs/current/ +- https://supabase.com/docs +- https://wiki.postgresql.org/wiki/Performance_Optimization +- https://supabase.com/docs/guides/database/overview +- https://supabase.com/docs/guides/auth/row-level-security diff --git a/.agents/skills/supabase-postgres-best-practices/references/_contributing.md b/.agents/skills/supabase-postgres-best-practices/references/_contributing.md new file mode 100644 index 00000000..10de8ecb --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/_contributing.md @@ -0,0 +1,171 @@ +# Writing Guidelines for Postgres References + +This document provides guidelines for creating effective Postgres best +practice references that work well with AI agents and LLMs. + +## Key Principles + +### 1. Concrete Transformation Patterns + +Show exact SQL rewrites. Avoid philosophical advice. + +**Good:** "Use `WHERE id = ANY(ARRAY[...])` instead of +`WHERE id IN (SELECT ...)`" **Bad:** "Design good schemas" + +### 2. Error-First Structure + +Always show the problematic pattern first, then the solution. This trains agents +to recognize anti-patterns. + +```markdown +**Incorrect (sequential queries):** [bad example] + +**Correct (batched query):** [good example] +``` + +### 3. Quantified Impact + +Include specific metrics. Helps agents prioritize fixes. + +**Good:** "10x faster queries", "50% smaller index", "Eliminates N+1" +**Bad:** "Faster", "Better", "More efficient" + +### 4. Self-Contained Examples + +Examples should be complete and runnable (or close to it). Include `CREATE TABLE` +if context is needed. + +```sql +-- Include table definition when needed for clarity +CREATE TABLE users ( + id bigint PRIMARY KEY, + email text NOT NULL, + deleted_at timestamptz +); + +-- Now show the index +CREATE INDEX users_active_email_idx ON users(email) WHERE deleted_at IS NULL; +``` + +### 5. Semantic Naming + +Use meaningful table/column names. Names carry intent for LLMs. + +**Good:** `users`, `email`, `created_at`, `is_active` +**Bad:** `table1`, `col1`, `field`, `flag` + +--- + +## Code Example Standards + +### SQL Formatting + +```sql +-- Use lowercase keywords, clear formatting +CREATE INDEX CONCURRENTLY users_email_idx + ON users(email) + WHERE deleted_at IS NULL; + +-- Not cramped or ALL CAPS +CREATE INDEX CONCURRENTLY USERS_EMAIL_IDX ON USERS(EMAIL) WHERE DELETED_AT IS NULL; +``` + +### Comments + +- Explain _why_, not _what_ +- Highlight performance implications +- Point out common pitfalls + +### Language Tags + +- `sql` - Standard SQL queries +- `plpgsql` - Stored procedures/functions +- `typescript` - Application code (when needed) +- `python` - Application code (when needed) + +--- + +## When to Include Application Code + +**Default: SQL Only** + +Most references should focus on pure SQL patterns. This keeps examples portable. + +**Include Application Code When:** + +- Connection pooling configuration +- Transaction management in application context +- ORM anti-patterns (N+1 in Prisma/TypeORM) +- Prepared statement usage + +**Format for Mixed Examples:** + +````markdown +**Incorrect (N+1 in application):** + +```typescript +for (const user of users) { + const posts = await db.query("SELECT * FROM posts WHERE user_id = $1", [ + user.id, + ]); +} +``` +```` + +**Correct (batch query):** + +```typescript +const posts = await db.query("SELECT * FROM posts WHERE user_id = ANY($1)", [ + userIds, +]); +``` + +--- + +## Impact Level Guidelines + +| Level | Improvement | Use When | +|-------|-------------|----------| +| **CRITICAL** | 10-100x | Missing indexes, connection exhaustion, sequential scans on large tables | +| **HIGH** | 5-20x | Wrong index types, poor partitioning, missing covering indexes | +| **MEDIUM-HIGH** | 2-5x | N+1 queries, inefficient pagination, RLS optimization | +| **MEDIUM** | 1.5-3x | Redundant indexes, query plan instability | +| **LOW-MEDIUM** | 1.2-2x | VACUUM tuning, configuration tweaks | +| **LOW** | Incremental | Advanced patterns, edge cases | + +--- + +## Reference Standards + +**Primary Sources:** + +- Official Postgres documentation +- Supabase documentation +- Postgres wiki +- Established blogs (2ndQuadrant, Crunchy Data) + +**Format:** + +```markdown +Reference: +[Postgres Indexes](https://www.postgresql.org/docs/current/indexes.html) +``` + +--- + +## Review Checklist + +Before submitting a reference: + +- [ ] Title is clear and action-oriented +- [ ] Impact level matches the performance gain +- [ ] impactDescription includes quantification +- [ ] Explanation is concise (1-2 sentences) +- [ ] Has at least 1 **Incorrect** SQL example +- [ ] Has at least 1 **Correct** SQL example +- [ ] SQL uses semantic naming +- [ ] Comments explain _why_, not _what_ +- [ ] Trade-offs mentioned if applicable +- [ ] Reference links included +- [ ] `npm run validate` passes +- [ ] `npm run build` generates correct output diff --git a/.agents/skills/supabase-postgres-best-practices/references/_sections.md b/.agents/skills/supabase-postgres-best-practices/references/_sections.md new file mode 100644 index 00000000..8ba57c23 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/_sections.md @@ -0,0 +1,39 @@ +# Section Definitions + +This file defines the rule categories for Postgres best practices. Rules are automatically assigned to sections based on their filename prefix. + +Take the examples below as pure demonstrative. Replace each section with the actual rule categories for Postgres best practices. + +--- + +## 1. Query Performance (query) +**Impact:** CRITICAL +**Description:** Slow queries, missing indexes, inefficient query plans. The most common source of Postgres performance issues. + +## 2. Connection Management (conn) +**Impact:** CRITICAL +**Description:** Connection pooling, limits, and serverless strategies. Critical for applications with high concurrency or serverless deployments. + +## 3. Security & RLS (security) +**Impact:** CRITICAL +**Description:** Row-Level Security policies, privilege management, and authentication patterns. + +## 4. Schema Design (schema) +**Impact:** HIGH +**Description:** Table design, index strategies, partitioning, and data type selection. Foundation for long-term performance. + +## 5. Concurrency & Locking (lock) +**Impact:** MEDIUM-HIGH +**Description:** Transaction management, isolation levels, deadlock prevention, and lock contention patterns. + +## 6. Data Access Patterns (data) +**Impact:** MEDIUM +**Description:** N+1 query elimination, batch operations, cursor-based pagination, and efficient data fetching. + +## 7. Monitoring & Diagnostics (monitor) +**Impact:** LOW-MEDIUM +**Description:** Using pg_stat_statements, EXPLAIN ANALYZE, metrics collection, and performance diagnostics. + +## 8. Advanced Features (advanced) +**Impact:** LOW +**Description:** Full-text search, JSONB optimization, PostGIS, extensions, and advanced Postgres features. diff --git a/.agents/skills/supabase-postgres-best-practices/references/_template.md b/.agents/skills/supabase-postgres-best-practices/references/_template.md new file mode 100644 index 00000000..91ace90e --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/_template.md @@ -0,0 +1,34 @@ +--- +title: Clear, Action-Oriented Title (e.g., "Use Partial Indexes for Filtered Queries") +impact: MEDIUM +impactDescription: 5-20x query speedup for filtered queries +tags: indexes, query-optimization, performance +--- + +## [Rule Title] + +[1-2 sentence explanation of the problem and why it matters. Focus on performance impact.] + +**Incorrect (describe the problem):** + +```sql +-- Comment explaining what makes this slow/problematic +CREATE INDEX users_email_idx ON users(email); + +SELECT * FROM users WHERE email = 'user@example.com' AND deleted_at IS NULL; +-- This scans deleted records unnecessarily +``` + +**Correct (describe the solution):** + +```sql +-- Comment explaining why this is better +CREATE INDEX users_active_email_idx ON users(email) WHERE deleted_at IS NULL; + +SELECT * FROM users WHERE email = 'user@example.com' AND deleted_at IS NULL; +-- Only indexes active users, 10x smaller index, faster queries +``` + +[Optional: Additional context, edge cases, or trade-offs] + +Reference: [Postgres Docs](https://www.postgresql.org/docs/current/) diff --git a/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md b/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md new file mode 100644 index 00000000..582cbeaa --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md @@ -0,0 +1,55 @@ +--- +title: Use tsvector for Full-Text Search +impact: MEDIUM +impactDescription: 100x faster than LIKE, with ranking support +tags: full-text-search, tsvector, gin, search +--- + +## Use tsvector for Full-Text Search + +LIKE with wildcards can't use indexes. Full-text search with tsvector is orders of magnitude faster. + +**Incorrect (LIKE pattern matching):** + +```sql +-- Cannot use index, scans all rows +select * from articles where content like '%postgresql%'; + +-- Case-insensitive makes it worse +select * from articles where lower(content) like '%postgresql%'; +``` + +**Correct (full-text search with tsvector):** + +```sql +-- Add tsvector column and index +alter table articles add column search_vector tsvector + generated always as (to_tsvector('english', coalesce(title,'') || ' ' || coalesce(content,''))) stored; + +create index articles_search_idx on articles using gin (search_vector); + +-- Fast full-text search +select * from articles +where search_vector @@ to_tsquery('english', 'postgresql & performance'); + +-- With ranking +select *, ts_rank(search_vector, query) as rank +from articles, to_tsquery('english', 'postgresql') query +where search_vector @@ query +order by rank desc; +``` + +Search multiple terms: + +```sql +-- AND: both terms required +to_tsquery('postgresql & performance') + +-- OR: either term +to_tsquery('postgresql | mysql') + +-- Prefix matching +to_tsquery('post:*') +``` + +Reference: [Full Text Search](https://supabase.com/docs/guides/database/full-text-search) diff --git a/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md b/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md new file mode 100644 index 00000000..e3d261ea --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md @@ -0,0 +1,49 @@ +--- +title: Index JSONB Columns for Efficient Querying +impact: MEDIUM +impactDescription: 10-100x faster JSONB queries with proper indexing +tags: jsonb, gin, indexes, json +--- + +## Index JSONB Columns for Efficient Querying + +JSONB queries without indexes scan the entire table. Use GIN indexes for containment queries. + +**Incorrect (no index on JSONB):** + +```sql +create table products ( + id bigint primary key, + attributes jsonb +); + +-- Full table scan for every query +select * from products where attributes @> '{"color": "red"}'; +select * from products where attributes->>'brand' = 'Nike'; +``` + +**Correct (GIN index for JSONB):** + +```sql +-- GIN index for containment operators (@>, ?, ?&, ?|) +create index products_attrs_gin on products using gin (attributes); + +-- Now containment queries use the index +select * from products where attributes @> '{"color": "red"}'; + +-- For specific key lookups, use expression index +create index products_brand_idx on products ((attributes->>'brand')); +select * from products where attributes->>'brand' = 'Nike'; +``` + +Choose the right operator class: + +```sql +-- jsonb_ops (default): supports all operators, larger index +create index idx1 on products using gin (attributes); + +-- jsonb_path_ops: only @> operator, but 2-3x smaller index +create index idx2 on products using gin (attributes jsonb_path_ops); +``` + +Reference: [JSONB Indexes](https://www.postgresql.org/docs/current/datatype-json.html#JSON-INDEXING) diff --git a/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md b/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md new file mode 100644 index 00000000..40b9cc50 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md @@ -0,0 +1,46 @@ +--- +title: Configure Idle Connection Timeouts +impact: HIGH +impactDescription: Reclaim 30-50% of connection slots from idle clients +tags: connections, timeout, idle, resource-management +--- + +## Configure Idle Connection Timeouts + +Idle connections waste resources. Configure timeouts to automatically reclaim them. + +**Incorrect (connections held indefinitely):** + +```sql +-- No timeout configured +show idle_in_transaction_session_timeout; -- 0 (disabled) + +-- Connections stay open forever, even when idle +select pid, state, state_change, query +from pg_stat_activity +where state = 'idle in transaction'; +-- Shows transactions idle for hours, holding locks +``` + +**Correct (automatic cleanup of idle connections):** + +```sql +-- Terminate connections idle in transaction after 30 seconds +alter system set idle_in_transaction_session_timeout = '30s'; + +-- Terminate completely idle connections after 10 minutes +alter system set idle_session_timeout = '10min'; + +-- Reload configuration +select pg_reload_conf(); +``` + +For pooled connections, configure at the pooler level: + +```ini +# pgbouncer.ini +server_idle_timeout = 60 +client_idle_timeout = 300 +``` + +Reference: [Connection Timeouts](https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-IDLE-IN-TRANSACTION-SESSION-TIMEOUT) diff --git a/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md b/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md new file mode 100644 index 00000000..cb3e400c --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md @@ -0,0 +1,44 @@ +--- +title: Set Appropriate Connection Limits +impact: CRITICAL +impactDescription: Prevent database crashes and memory exhaustion +tags: connections, max-connections, limits, stability +--- + +## Set Appropriate Connection Limits + +Too many connections exhaust memory and degrade performance. Set limits based on available resources. + +**Incorrect (unlimited or excessive connections):** + +```sql +-- Default max_connections = 100, but often increased blindly +show max_connections; -- 500 (way too high for 4GB RAM) + +-- Each connection uses 1-3MB RAM +-- 500 connections * 2MB = 1GB just for connections! +-- Out of memory errors under load +``` + +**Correct (calculate based on resources):** + +```sql +-- Formula: max_connections = (RAM in MB / 5MB per connection) - reserved +-- For 4GB RAM: (4096 / 5) - 10 = ~800 theoretical max +-- But practically, 100-200 is better for query performance + +-- Recommended settings for 4GB RAM +alter system set max_connections = 100; + +-- Also set work_mem appropriately +-- work_mem * max_connections should not exceed 25% of RAM +alter system set work_mem = '8MB'; -- 8MB * 100 = 800MB max +``` + +Monitor connection usage: + +```sql +select count(*), state from pg_stat_activity group by state; +``` + +Reference: [Database Connections](https://supabase.com/docs/guides/platform/performance#connection-management) diff --git a/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md b/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md new file mode 100644 index 00000000..e2ebd581 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md @@ -0,0 +1,41 @@ +--- +title: Use Connection Pooling for All Applications +impact: CRITICAL +impactDescription: Handle 10-100x more concurrent users +tags: connection-pooling, pgbouncer, performance, scalability +--- + +## Use Connection Pooling for All Applications + +Postgres connections are expensive (1-3MB RAM each). Without pooling, applications exhaust connections under load. + +**Incorrect (new connection per request):** + +```sql +-- Each request creates a new connection +-- Application code: db.connect() per request +-- Result: 500 concurrent users = 500 connections = crashed database + +-- Check current connections +select count(*) from pg_stat_activity; -- 487 connections! +``` + +**Correct (connection pooling):** + +```sql +-- Use a pooler like PgBouncer between app and database +-- Application connects to pooler, pooler reuses a small pool to Postgres + +-- Configure pool_size based on: (CPU cores * 2) + spindle_count +-- Example for 4 cores: pool_size = 10 + +-- Result: 500 concurrent users share 10 actual connections +select count(*) from pg_stat_activity; -- 10 connections +``` + +Pool modes: + +- **Transaction mode**: connection returned after each transaction (best for most apps) +- **Session mode**: connection held for entire session (needed for prepared statements, temp tables) + +Reference: [Connection Pooling](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler) diff --git a/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md b/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md new file mode 100644 index 00000000..555547d8 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md @@ -0,0 +1,46 @@ +--- +title: Use Prepared Statements Correctly with Pooling +impact: HIGH +impactDescription: Avoid prepared statement conflicts in pooled environments +tags: prepared-statements, connection-pooling, transaction-mode +--- + +## Use Prepared Statements Correctly with Pooling + +Prepared statements are tied to individual database connections. In transaction-mode pooling, connections are shared, causing conflicts. + +**Incorrect (named prepared statements with transaction pooling):** + +```sql +-- Named prepared statement +prepare get_user as select * from users where id = $1; + +-- In transaction mode pooling, next request may get different connection +execute get_user(123); +-- ERROR: prepared statement "get_user" does not exist +``` + +**Correct (use unnamed statements or session mode):** + +```sql +-- Option 1: Use unnamed prepared statements (most ORMs do this automatically) +-- The query is prepared and executed in a single protocol message + +-- Option 2: Deallocate after use in transaction mode +prepare get_user as select * from users where id = $1; +execute get_user(123); +deallocate get_user; + +-- Option 3: Use session mode pooling (port 5432 vs 6543) +-- Connection is held for entire session, prepared statements persist +``` + +Check your driver settings: + +```sql +-- Many drivers use prepared statements by default +-- Node.js pg: { prepare: false } to disable +-- JDBC: prepareThreshold=0 to disable +``` + +Reference: [Prepared Statements with Pooling](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pool-modes) diff --git a/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md b/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md new file mode 100644 index 00000000..997947cb --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md @@ -0,0 +1,54 @@ +--- +title: Batch INSERT Statements for Bulk Data +impact: MEDIUM +impactDescription: 10-50x faster bulk inserts +tags: batch, insert, bulk, performance, copy +--- + +## Batch INSERT Statements for Bulk Data + +Individual INSERT statements have high overhead. Batch multiple rows in single statements or use COPY. + +**Incorrect (individual inserts):** + +```sql +-- Each insert is a separate transaction and round trip +insert into events (user_id, action) values (1, 'click'); +insert into events (user_id, action) values (1, 'view'); +insert into events (user_id, action) values (2, 'click'); +-- ... 1000 more individual inserts + +-- 1000 inserts = 1000 round trips = slow +``` + +**Correct (batch insert):** + +```sql +-- Multiple rows in single statement +insert into events (user_id, action) values + (1, 'click'), + (1, 'view'), + (2, 'click'), + -- ... up to ~1000 rows per batch + (999, 'view'); + +-- One round trip for 1000 rows +``` + +For large imports, use COPY: + +```sql +-- COPY is fastest for bulk loading +copy events (user_id, action, created_at) +from '/path/to/data.csv' +with (format csv, header true); + +-- Or from stdin in application +copy events (user_id, action) from stdin with (format csv); +1,click +1,view +2,click +\. +``` + +Reference: [COPY](https://www.postgresql.org/docs/current/sql-copy.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md b/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md new file mode 100644 index 00000000..2109186f --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md @@ -0,0 +1,53 @@ +--- +title: Eliminate N+1 Queries with Batch Loading +impact: MEDIUM-HIGH +impactDescription: 10-100x fewer database round trips +tags: n-plus-one, batch, performance, queries +--- + +## Eliminate N+1 Queries with Batch Loading + +N+1 queries execute one query per item in a loop. Batch them into a single query using arrays or JOINs. + +**Incorrect (N+1 queries):** + +```sql +-- First query: get all users +select id from users where active = true; -- Returns 100 IDs + +-- Then N queries, one per user +select * from orders where user_id = 1; +select * from orders where user_id = 2; +select * from orders where user_id = 3; +-- ... 97 more queries! + +-- Total: 101 round trips to database +``` + +**Correct (single batch query):** + +```sql +-- Collect IDs and query once with ANY +select * from orders where user_id = any(array[1, 2, 3, ...]); + +-- Or use JOIN instead of loop +select u.id, u.name, o.* +from users u +left join orders o on o.user_id = u.id +where u.active = true; + +-- Total: 1 round trip +``` + +Application pattern: + +```sql +-- Instead of looping in application code: +-- for user in users: db.query("SELECT * FROM orders WHERE user_id = $1", user.id) + +-- Pass array parameter: +select * from orders where user_id = any($1::bigint[]); +-- Application passes: [1, 2, 3, 4, 5, ...] +``` + +Reference: [N+1 Query Problem](https://supabase.com/docs/guides/database/query-optimization) diff --git a/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md b/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md new file mode 100644 index 00000000..633d8393 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md @@ -0,0 +1,50 @@ +--- +title: Use Cursor-Based Pagination Instead of OFFSET +impact: MEDIUM-HIGH +impactDescription: Consistent O(1) performance regardless of page depth +tags: pagination, cursor, keyset, offset, performance +--- + +## Use Cursor-Based Pagination Instead of OFFSET + +OFFSET-based pagination scans all skipped rows, getting slower on deeper pages. Cursor pagination is O(1). + +**Incorrect (OFFSET pagination):** + +```sql +-- Page 1: scans 20 rows +select * from products order by id limit 20 offset 0; + +-- Page 100: scans 2000 rows to skip 1980 +select * from products order by id limit 20 offset 1980; + +-- Page 10000: scans 200,000 rows! +select * from products order by id limit 20 offset 199980; +``` + +**Correct (cursor/keyset pagination):** + +```sql +-- Page 1: get first 20 +select * from products order by id limit 20; +-- Application stores last_id = 20 + +-- Page 2: start after last ID +select * from products where id > 20 order by id limit 20; +-- Uses index, always fast regardless of page depth + +-- Page 10000: same speed as page 1 +select * from products where id > 199980 order by id limit 20; +``` + +For multi-column sorting: + +```sql +-- Cursor must include all sort columns +select * from products +where (created_at, id) > ('2024-01-15 10:00:00', 12345) +order by created_at, id +limit 20; +``` + +Reference: [Pagination](https://supabase.com/docs/guides/database/pagination) diff --git a/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md b/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md new file mode 100644 index 00000000..bc95e230 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md @@ -0,0 +1,50 @@ +--- +title: Use UPSERT for Insert-or-Update Operations +impact: MEDIUM +impactDescription: Atomic operation, eliminates race conditions +tags: upsert, on-conflict, insert, update +--- + +## Use UPSERT for Insert-or-Update Operations + +Using separate SELECT-then-INSERT/UPDATE creates race conditions. Use INSERT ... ON CONFLICT for atomic upserts. + +**Incorrect (check-then-insert race condition):** + +```sql +-- Race condition: two requests check simultaneously +select * from settings where user_id = 123 and key = 'theme'; +-- Both find nothing + +-- Both try to insert +insert into settings (user_id, key, value) values (123, 'theme', 'dark'); +-- One succeeds, one fails with duplicate key error! +``` + +**Correct (atomic UPSERT):** + +```sql +-- Single atomic operation +insert into settings (user_id, key, value) +values (123, 'theme', 'dark') +on conflict (user_id, key) +do update set value = excluded.value, updated_at = now(); + +-- Returns the inserted/updated row +insert into settings (user_id, key, value) +values (123, 'theme', 'dark') +on conflict (user_id, key) +do update set value = excluded.value +returning *; +``` + +Insert-or-ignore pattern: + +```sql +-- Insert only if not exists (no update) +insert into page_views (page_id, user_id) +values (1, 123) +on conflict (page_id, user_id) do nothing; +``` + +Reference: [INSERT ON CONFLICT](https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT) diff --git a/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md b/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md new file mode 100644 index 00000000..572eaf0d --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md @@ -0,0 +1,56 @@ +--- +title: Use Advisory Locks for Application-Level Locking +impact: MEDIUM +impactDescription: Efficient coordination without row-level lock overhead +tags: advisory-locks, coordination, application-locks +--- + +## Use Advisory Locks for Application-Level Locking + +Advisory locks provide application-level coordination without requiring database rows to lock. + +**Incorrect (creating rows just for locking):** + +```sql +-- Creating dummy rows to lock on +create table resource_locks ( + resource_name text primary key +); + +insert into resource_locks values ('report_generator'); + +-- Lock by selecting the row +select * from resource_locks where resource_name = 'report_generator' for update; +``` + +**Correct (advisory locks):** + +```sql +-- Session-level advisory lock (released on disconnect or unlock) +select pg_advisory_lock(hashtext('report_generator')); +-- ... do exclusive work ... +select pg_advisory_unlock(hashtext('report_generator')); + +-- Transaction-level lock (released on commit/rollback) +begin; +select pg_advisory_xact_lock(hashtext('daily_report')); +-- ... do work ... +commit; -- Lock automatically released +``` + +Try-lock for non-blocking operations: + +```sql +-- Returns immediately with true/false instead of waiting +select pg_try_advisory_lock(hashtext('resource_name')); + +-- Use in application +if (acquired) { + -- Do work + select pg_advisory_unlock(hashtext('resource_name')); +} else { + -- Skip or retry later +} +``` + +Reference: [Advisory Locks](https://www.postgresql.org/docs/current/explicit-locking.html#ADVISORY-LOCKS) diff --git a/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md b/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md new file mode 100644 index 00000000..974da5ed --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md @@ -0,0 +1,68 @@ +--- +title: Prevent Deadlocks with Consistent Lock Ordering +impact: MEDIUM-HIGH +impactDescription: Eliminate deadlock errors, improve reliability +tags: deadlocks, locking, transactions, ordering +--- + +## Prevent Deadlocks with Consistent Lock Ordering + +Deadlocks occur when transactions lock resources in different orders. Always +acquire locks in a consistent order. + +**Incorrect (inconsistent lock ordering):** + +```sql +-- Transaction A -- Transaction B +begin; begin; +update accounts update accounts +set balance = balance - 100 set balance = balance - 50 +where id = 1; where id = 2; -- B locks row 2 + +update accounts update accounts +set balance = balance + 100 set balance = balance + 50 +where id = 2; -- A waits for B where id = 1; -- B waits for A + +-- DEADLOCK! Both waiting for each other +``` + +**Correct (lock rows in consistent order first):** + +```sql +-- Explicitly acquire locks in ID order before updating +begin; +select * from accounts where id in (1, 2) order by id for update; + +-- Now perform updates in any order - locks already held +update accounts set balance = balance - 100 where id = 1; +update accounts set balance = balance + 100 where id = 2; +commit; +``` + +Alternative: use a single statement to update atomically: + +```sql +-- Single statement acquires all locks atomically +begin; +update accounts +set balance = balance + case id + when 1 then -100 + when 2 then 100 +end +where id in (1, 2); +commit; +``` + +Detect deadlocks in logs: + +```sql +-- Check for recent deadlocks +select * from pg_stat_database where deadlocks > 0; + +-- Enable deadlock logging +set log_lock_waits = on; +set deadlock_timeout = '1s'; +``` + +Reference: +[Deadlocks](https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-DEADLOCKS) diff --git a/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md b/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md new file mode 100644 index 00000000..e6b8ef26 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md @@ -0,0 +1,50 @@ +--- +title: Keep Transactions Short to Reduce Lock Contention +impact: MEDIUM-HIGH +impactDescription: 3-5x throughput improvement, fewer deadlocks +tags: transactions, locking, contention, performance +--- + +## Keep Transactions Short to Reduce Lock Contention + +Long-running transactions hold locks that block other queries. Keep transactions as short as possible. + +**Incorrect (long transaction with external calls):** + +```sql +begin; +select * from orders where id = 1 for update; -- Lock acquired + +-- Application makes HTTP call to payment API (2-5 seconds) +-- Other queries on this row are blocked! + +update orders set status = 'paid' where id = 1; +commit; -- Lock held for entire duration +``` + +**Correct (minimal transaction scope):** + +```sql +-- Validate data and call APIs outside transaction +-- Application: response = await paymentAPI.charge(...) + +-- Only hold lock for the actual update +begin; +update orders +set status = 'paid', payment_id = $1 +where id = $2 and status = 'pending' +returning *; +commit; -- Lock held for milliseconds +``` + +Use `statement_timeout` to prevent runaway transactions: + +```sql +-- Abort queries running longer than 30 seconds +set statement_timeout = '30s'; + +-- Or per-session +set local statement_timeout = '5s'; +``` + +Reference: [Transaction Management](https://www.postgresql.org/docs/current/tutorial-transactions.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md b/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md new file mode 100644 index 00000000..77bdbb97 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md @@ -0,0 +1,54 @@ +--- +title: Use SKIP LOCKED for Non-Blocking Queue Processing +impact: MEDIUM-HIGH +impactDescription: 10x throughput for worker queues +tags: skip-locked, queue, workers, concurrency +--- + +## Use SKIP LOCKED for Non-Blocking Queue Processing + +When multiple workers process a queue, SKIP LOCKED allows workers to process different rows without waiting. + +**Incorrect (workers block each other):** + +```sql +-- Worker 1 and Worker 2 both try to get next job +begin; +select * from jobs where status = 'pending' order by created_at limit 1 for update; +-- Worker 2 waits for Worker 1's lock to release! +``` + +**Correct (SKIP LOCKED for parallel processing):** + +```sql +-- Each worker skips locked rows and gets the next available +begin; +select * from jobs +where status = 'pending' +order by created_at +limit 1 +for update skip locked; + +-- Worker 1 gets job 1, Worker 2 gets job 2 (no waiting) + +update jobs set status = 'processing' where id = $1; +commit; +``` + +Complete queue pattern: + +```sql +-- Atomic claim-and-update in one statement +update jobs +set status = 'processing', worker_id = $1, started_at = now() +where id = ( + select id from jobs + where status = 'pending' + order by created_at + limit 1 + for update skip locked +) +returning *; +``` + +Reference: [SELECT FOR UPDATE SKIP LOCKED](https://www.postgresql.org/docs/current/sql-select.html#SQL-FOR-UPDATE-SHARE) diff --git a/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md b/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md new file mode 100644 index 00000000..542978c3 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md @@ -0,0 +1,45 @@ +--- +title: Use EXPLAIN ANALYZE to Diagnose Slow Queries +impact: LOW-MEDIUM +impactDescription: Identify exact bottlenecks in query execution +tags: explain, analyze, diagnostics, query-plan +--- + +## Use EXPLAIN ANALYZE to Diagnose Slow Queries + +EXPLAIN ANALYZE executes the query and shows actual timings, revealing the true performance bottlenecks. + +**Incorrect (guessing at performance issues):** + +```sql +-- Query is slow, but why? +select * from orders where customer_id = 123 and status = 'pending'; +-- "It must be missing an index" - but which one? +``` + +**Correct (use EXPLAIN ANALYZE):** + +```sql +explain (analyze, buffers, format text) +select * from orders where customer_id = 123 and status = 'pending'; + +-- Output reveals the issue: +-- Seq Scan on orders (cost=0.00..25000.00 rows=50 width=100) (actual time=0.015..450.123 rows=50 loops=1) +-- Filter: ((customer_id = 123) AND (status = 'pending'::text)) +-- Rows Removed by Filter: 999950 +-- Buffers: shared hit=5000 read=15000 +-- Planning Time: 0.150 ms +-- Execution Time: 450.500 ms +``` + +Key things to look for: + +```sql +-- Seq Scan on large tables = missing index +-- Rows Removed by Filter = poor selectivity or missing index +-- Buffers: read >> hit = data not cached, needs more memory +-- Nested Loop with high loops = consider different join strategy +-- Sort Method: external merge = work_mem too low +``` + +Reference: [EXPLAIN](https://supabase.com/docs/guides/database/inspect) diff --git a/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md b/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md new file mode 100644 index 00000000..d7e82f1a --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md @@ -0,0 +1,55 @@ +--- +title: Enable pg_stat_statements for Query Analysis +impact: LOW-MEDIUM +impactDescription: Identify top resource-consuming queries +tags: pg-stat-statements, monitoring, statistics, performance +--- + +## Enable pg_stat_statements for Query Analysis + +pg_stat_statements tracks execution statistics for all queries, helping identify slow and frequent queries. + +**Incorrect (no visibility into query patterns):** + +```sql +-- Database is slow, but which queries are the problem? +-- No way to know without pg_stat_statements +``` + +**Correct (enable and query pg_stat_statements):** + +```sql +-- Enable the extension +create extension if not exists pg_stat_statements; + +-- Find slowest queries by total time +select + calls, + round(total_exec_time::numeric, 2) as total_time_ms, + round(mean_exec_time::numeric, 2) as mean_time_ms, + query +from pg_stat_statements +order by total_exec_time desc +limit 10; + +-- Find most frequent queries +select calls, query +from pg_stat_statements +order by calls desc +limit 10; + +-- Reset statistics after optimization +select pg_stat_statements_reset(); +``` + +Key metrics to monitor: + +```sql +-- Queries with high mean time (candidates for optimization) +select query, mean_exec_time, calls +from pg_stat_statements +where mean_exec_time > 100 -- > 100ms average +order by mean_exec_time desc; +``` + +Reference: [pg_stat_statements](https://supabase.com/docs/guides/database/extensions/pg_stat_statements) diff --git a/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md b/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md new file mode 100644 index 00000000..e0e8ea0b --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md @@ -0,0 +1,55 @@ +--- +title: Maintain Table Statistics with VACUUM and ANALYZE +impact: MEDIUM +impactDescription: 2-10x better query plans with accurate statistics +tags: vacuum, analyze, statistics, maintenance, autovacuum +--- + +## Maintain Table Statistics with VACUUM and ANALYZE + +Outdated statistics cause the query planner to make poor decisions. VACUUM reclaims space, ANALYZE updates statistics. + +**Incorrect (stale statistics):** + +```sql +-- Table has 1M rows but stats say 1000 +-- Query planner chooses wrong strategy +explain select * from orders where status = 'pending'; +-- Shows: Seq Scan (because stats show small table) +-- Actually: Index Scan would be much faster +``` + +**Correct (maintain fresh statistics):** + +```sql +-- Manually analyze after large data changes +analyze orders; + +-- Analyze specific columns used in WHERE clauses +analyze orders (status, created_at); + +-- Check when tables were last analyzed +select + relname, + last_vacuum, + last_autovacuum, + last_analyze, + last_autoanalyze +from pg_stat_user_tables +order by last_analyze nulls first; +``` + +Autovacuum tuning for busy tables: + +```sql +-- Increase frequency for high-churn tables +alter table orders set ( + autovacuum_vacuum_scale_factor = 0.05, -- Vacuum at 5% dead tuples (default 20%) + autovacuum_analyze_scale_factor = 0.02 -- Analyze at 2% changes (default 10%) +); + +-- Check autovacuum status +select * from pg_stat_progress_vacuum; +``` + +Reference: [VACUUM](https://supabase.com/docs/guides/database/database-size#vacuum-operations) diff --git a/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md b/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md new file mode 100644 index 00000000..fea64523 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md @@ -0,0 +1,44 @@ +--- +title: Create Composite Indexes for Multi-Column Queries +impact: HIGH +impactDescription: 5-10x faster multi-column queries +tags: indexes, composite-index, multi-column, query-optimization +--- + +## Create Composite Indexes for Multi-Column Queries + +When queries filter on multiple columns, a composite index is more efficient than separate single-column indexes. + +**Incorrect (separate indexes require bitmap scan):** + +```sql +-- Two separate indexes +create index orders_status_idx on orders (status); +create index orders_created_idx on orders (created_at); + +-- Query must combine both indexes (slower) +select * from orders where status = 'pending' and created_at > '2024-01-01'; +``` + +**Correct (composite index):** + +```sql +-- Single composite index (leftmost column first for equality checks) +create index orders_status_created_idx on orders (status, created_at); + +-- Query uses one efficient index scan +select * from orders where status = 'pending' and created_at > '2024-01-01'; +``` + +**Column order matters** - place equality columns first, range columns last: + +```sql +-- Good: status (=) before created_at (>) +create index idx on orders (status, created_at); + +-- Works for: WHERE status = 'pending' +-- Works for: WHERE status = 'pending' AND created_at > '2024-01-01' +-- Does NOT work for: WHERE created_at > '2024-01-01' (leftmost prefix rule) +``` + +Reference: [Multicolumn Indexes](https://www.postgresql.org/docs/current/indexes-multicolumn.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md b/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md new file mode 100644 index 00000000..9d2a4947 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md @@ -0,0 +1,40 @@ +--- +title: Use Covering Indexes to Avoid Table Lookups +impact: MEDIUM-HIGH +impactDescription: 2-5x faster queries by eliminating heap fetches +tags: indexes, covering-index, include, index-only-scan +--- + +## Use Covering Indexes to Avoid Table Lookups + +Covering indexes include all columns needed by a query, enabling index-only scans that skip the table entirely. + +**Incorrect (index scan + heap fetch):** + +```sql +create index users_email_idx on users (email); + +-- Must fetch name and created_at from table heap +select email, name, created_at from users where email = 'user@example.com'; +``` + +**Correct (index-only scan with INCLUDE):** + +```sql +-- Include non-searchable columns in the index +create index users_email_idx on users (email) include (name, created_at); + +-- All columns served from index, no table access needed +select email, name, created_at from users where email = 'user@example.com'; +``` + +Use INCLUDE for columns you SELECT but don't filter on: + +```sql +-- Searching by status, but also need customer_id and total +create index orders_status_idx on orders (status) include (customer_id, total); + +select status, customer_id, total from orders where status = 'shipped'; +``` + +Reference: [Index-Only Scans](https://www.postgresql.org/docs/current/indexes-index-only-scans.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md b/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md new file mode 100644 index 00000000..93b32590 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md @@ -0,0 +1,48 @@ +--- +title: Choose the Right Index Type for Your Data +impact: HIGH +impactDescription: 10-100x improvement with correct index type +tags: indexes, btree, gin, gist, brin, hash, index-types +--- + +## Choose the Right Index Type for Your Data + +Different index types excel at different query patterns. The default B-tree isn't always optimal. + +**Incorrect (B-tree for JSONB containment):** + +```sql +-- B-tree cannot optimize containment operators +create index products_attrs_idx on products (attributes); +select * from products where attributes @> '{"color": "red"}'; +-- Full table scan - B-tree doesn't support @> operator +``` + +**Correct (GIN for JSONB):** + +```sql +-- GIN supports @>, ?, ?&, ?| operators +create index products_attrs_idx on products using gin (attributes); +select * from products where attributes @> '{"color": "red"}'; +``` + +Index type guide: + +```sql +-- B-tree (default): =, <, >, BETWEEN, IN, IS NULL +create index users_created_idx on users (created_at); + +-- GIN: arrays, JSONB, full-text search +create index posts_tags_idx on posts using gin (tags); + +-- GiST: geometric data, range types, nearest-neighbor (KNN) queries +create index locations_idx on places using gist (location); + +-- BRIN: large time-series tables (10-100x smaller) +create index events_time_idx on events using brin (created_at); + +-- Hash: equality-only (slightly faster than B-tree for =) +create index sessions_token_idx on sessions using hash (token); +``` + +Reference: [Index Types](https://www.postgresql.org/docs/current/indexes-types.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md b/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md new file mode 100644 index 00000000..e6daace7 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md @@ -0,0 +1,43 @@ +--- +title: Add Indexes on WHERE and JOIN Columns +impact: CRITICAL +impactDescription: 100-1000x faster queries on large tables +tags: indexes, performance, sequential-scan, query-optimization +--- + +## Add Indexes on WHERE and JOIN Columns + +Queries filtering or joining on unindexed columns cause full table scans, which become exponentially slower as tables grow. + +**Incorrect (sequential scan on large table):** + +```sql +-- No index on customer_id causes full table scan +select * from orders where customer_id = 123; + +-- EXPLAIN shows: Seq Scan on orders (cost=0.00..25000.00 rows=100 width=85) +``` + +**Correct (index scan):** + +```sql +-- Create index on frequently filtered column +create index orders_customer_id_idx on orders (customer_id); + +select * from orders where customer_id = 123; + +-- EXPLAIN shows: Index Scan using orders_customer_id_idx (cost=0.42..8.44 rows=100 width=85) +``` + +For JOIN columns, always index the foreign key side: + +```sql +-- Index the referencing column +create index orders_customer_id_idx on orders (customer_id); + +select c.name, o.total +from customers c +join orders o on o.customer_id = c.id; +``` + +Reference: [Query Optimization](https://supabase.com/docs/guides/database/query-optimization) diff --git a/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md b/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md new file mode 100644 index 00000000..3e61a341 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md @@ -0,0 +1,45 @@ +--- +title: Use Partial Indexes for Filtered Queries +impact: HIGH +impactDescription: 5-20x smaller indexes, faster writes and queries +tags: indexes, partial-index, query-optimization, storage +--- + +## Use Partial Indexes for Filtered Queries + +Partial indexes only include rows matching a WHERE condition, making them smaller and faster when queries consistently filter on the same condition. + +**Incorrect (full index includes irrelevant rows):** + +```sql +-- Index includes all rows, even soft-deleted ones +create index users_email_idx on users (email); + +-- Query always filters active users +select * from users where email = 'user@example.com' and deleted_at is null; +``` + +**Correct (partial index matches query filter):** + +```sql +-- Index only includes active users +create index users_active_email_idx on users (email) +where deleted_at is null; + +-- Query uses the smaller, faster index +select * from users where email = 'user@example.com' and deleted_at is null; +``` + +Common use cases for partial indexes: + +```sql +-- Only pending orders (status rarely changes once completed) +create index orders_pending_idx on orders (created_at) +where status = 'pending'; + +-- Only non-null values +create index products_sku_idx on products (sku) +where sku is not null; +``` + +Reference: [Partial Indexes](https://www.postgresql.org/docs/current/indexes-partial.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md b/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md new file mode 100644 index 00000000..1d2ef8f9 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md @@ -0,0 +1,80 @@ +--- +title: Add Constraints Safely in Migrations +impact: HIGH +impactDescription: Prevents migration failures and enables idempotent schema changes +tags: constraints, migrations, schema, alter-table +--- + +## Add Constraints Safely in Migrations + +PostgreSQL does not support `ADD CONSTRAINT IF NOT EXISTS`. Migrations using this syntax will fail. + +**Incorrect (causes syntax error):** + +```sql +-- ERROR: syntax error at or near "not" (SQLSTATE 42601) +alter table public.profiles +add constraint if not exists profiles_birthchart_id_unique unique (birthchart_id); +``` + +**Correct (idempotent constraint creation):** + +```sql +-- Use DO block to check before adding +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'profiles_birthchart_id_unique' + and conrelid = 'public.profiles'::regclass + ) then + alter table public.profiles + add constraint profiles_birthchart_id_unique unique (birthchart_id); + end if; +end $$; +``` + +For all constraint types: + +```sql +-- Check constraints +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'check_age_positive' + ) then + alter table users add constraint check_age_positive check (age > 0); + end if; +end $$; + +-- Foreign keys +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'profiles_birthchart_id_fkey' + ) then + alter table profiles + add constraint profiles_birthchart_id_fkey + foreign key (birthchart_id) references birthcharts(id); + end if; +end $$; +``` + +Check if constraint exists: + +```sql +-- Query to check constraint existence +select conname, contype, pg_get_constraintdef(oid) +from pg_constraint +where conrelid = 'public.profiles'::regclass; + +-- contype values: +-- 'p' = PRIMARY KEY +-- 'f' = FOREIGN KEY +-- 'u' = UNIQUE +-- 'c' = CHECK +``` + +Reference: [Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md b/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md new file mode 100644 index 00000000..f253a581 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md @@ -0,0 +1,46 @@ +--- +title: Choose Appropriate Data Types +impact: HIGH +impactDescription: 50% storage reduction, faster comparisons +tags: data-types, schema, storage, performance +--- + +## Choose Appropriate Data Types + +Using the right data types reduces storage, improves query performance, and prevents bugs. + +**Incorrect (wrong data types):** + +```sql +create table users ( + id int, -- Will overflow at 2.1 billion + email varchar(255), -- Unnecessary length limit + created_at timestamp, -- Missing timezone info + is_active varchar(5), -- String for boolean + price varchar(20) -- String for numeric +); +``` + +**Correct (appropriate data types):** + +```sql +create table users ( + id bigint generated always as identity primary key, -- 9 quintillion max + email text, -- No artificial limit, same performance as varchar + created_at timestamptz, -- Always store timezone-aware timestamps + is_active boolean default true, -- 1 byte vs variable string length + price numeric(10,2) -- Exact decimal arithmetic +); +``` + +Key guidelines: + +```sql +-- IDs: use bigint, not int (future-proofing) +-- Strings: use text, not varchar(n) unless constraint needed +-- Time: use timestamptz, not timestamp +-- Money: use numeric, not float (precision matters) +-- Enums: use text with check constraint or create enum type +``` + +Reference: [Data Types](https://www.postgresql.org/docs/current/datatype.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md b/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md new file mode 100644 index 00000000..6c3d6ff6 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md @@ -0,0 +1,59 @@ +--- +title: Index Foreign Key Columns +impact: HIGH +impactDescription: 10-100x faster JOINs and CASCADE operations +tags: foreign-key, indexes, joins, schema +--- + +## Index Foreign Key Columns + +Postgres does not automatically index foreign key columns. Missing indexes cause slow JOINs and CASCADE operations. + +**Incorrect (unindexed foreign key):** + +```sql +create table orders ( + id bigint generated always as identity primary key, + customer_id bigint references customers(id) on delete cascade, + total numeric(10,2) +); + +-- No index on customer_id! +-- JOINs and ON DELETE CASCADE both require full table scan +select * from orders where customer_id = 123; -- Seq Scan +delete from customers where id = 123; -- Locks table, scans all orders +``` + +**Correct (indexed foreign key):** + +```sql +create table orders ( + id bigint generated always as identity primary key, + customer_id bigint references customers(id) on delete cascade, + total numeric(10,2) +); + +-- Always index the FK column +create index orders_customer_id_idx on orders (customer_id); + +-- Now JOINs and cascades are fast +select * from orders where customer_id = 123; -- Index Scan +delete from customers where id = 123; -- Uses index, fast cascade +``` + +Find missing FK indexes: + +```sql +select + conrelid::regclass as table_name, + a.attname as fk_column +from pg_constraint c +join pg_attribute a on a.attrelid = c.conrelid and a.attnum = any(c.conkey) +where c.contype = 'f' + and not exists ( + select 1 from pg_index i + where i.indrelid = c.conrelid and a.attnum = any(i.indkey) + ); +``` + +Reference: [Foreign Keys](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK) diff --git a/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md b/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md new file mode 100644 index 00000000..f0072940 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md @@ -0,0 +1,55 @@ +--- +title: Use Lowercase Identifiers for Compatibility +impact: MEDIUM +impactDescription: Avoid case-sensitivity bugs with tools, ORMs, and AI assistants +tags: naming, identifiers, case-sensitivity, schema, conventions +--- + +## Use Lowercase Identifiers for Compatibility + +PostgreSQL folds unquoted identifiers to lowercase. Quoted mixed-case identifiers require quotes forever and cause issues with tools, ORMs, and AI assistants that may not recognize them. + +**Incorrect (mixed-case identifiers):** + +```sql +-- Quoted identifiers preserve case but require quotes everywhere +CREATE TABLE "Users" ( + "userId" bigint PRIMARY KEY, + "firstName" text, + "lastName" text +); + +-- Must always quote or queries fail +SELECT "firstName" FROM "Users" WHERE "userId" = 1; + +-- This fails - Users becomes users without quotes +SELECT firstName FROM Users; +-- ERROR: relation "users" does not exist +``` + +**Correct (lowercase snake_case):** + +```sql +-- Unquoted lowercase identifiers are portable and tool-friendly +CREATE TABLE users ( + user_id bigint PRIMARY KEY, + first_name text, + last_name text +); + +-- Works without quotes, recognized by all tools +SELECT first_name FROM users WHERE user_id = 1; +``` + +Common sources of mixed-case identifiers: + +```sql +-- ORMs often generate quoted camelCase - configure them to use snake_case +-- Migrations from other databases may preserve original casing +-- Some GUI tools quote identifiers by default - disable this + +-- If stuck with mixed-case, create views as a compatibility layer +CREATE VIEW users AS SELECT "userId" AS user_id, "firstName" AS first_name FROM "Users"; +``` + +Reference: [Identifiers and Key Words](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS) diff --git a/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md b/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md new file mode 100644 index 00000000..13137a03 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md @@ -0,0 +1,55 @@ +--- +title: Partition Large Tables for Better Performance +impact: MEDIUM-HIGH +impactDescription: 5-20x faster queries and maintenance on large tables +tags: partitioning, large-tables, time-series, performance +--- + +## Partition Large Tables for Better Performance + +Partitioning splits a large table into smaller pieces, improving query performance and maintenance operations. + +**Incorrect (single large table):** + +```sql +create table events ( + id bigint generated always as identity, + created_at timestamptz, + data jsonb +); + +-- 500M rows, queries scan everything +select * from events where created_at > '2024-01-01'; -- Slow +vacuum events; -- Takes hours, locks table +``` + +**Correct (partitioned by time range):** + +```sql +create table events ( + id bigint generated always as identity, + created_at timestamptz not null, + data jsonb +) partition by range (created_at); + +-- Create partitions for each month +create table events_2024_01 partition of events + for values from ('2024-01-01') to ('2024-02-01'); + +create table events_2024_02 partition of events + for values from ('2024-02-01') to ('2024-03-01'); + +-- Queries only scan relevant partitions +select * from events where created_at > '2024-01-15'; -- Only scans events_2024_01+ + +-- Drop old data instantly +drop table events_2023_01; -- Instant vs DELETE taking hours +``` + +When to partition: + +- Tables > 100M rows +- Time-series data with date-based queries +- Need to efficiently drop old data + +Reference: [Table Partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html) diff --git a/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md b/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md new file mode 100644 index 00000000..fb0fbb16 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md @@ -0,0 +1,61 @@ +--- +title: Select Optimal Primary Key Strategy +impact: HIGH +impactDescription: Better index locality, reduced fragmentation +tags: primary-key, identity, uuid, serial, schema +--- + +## Select Optimal Primary Key Strategy + +Primary key choice affects insert performance, index size, and replication +efficiency. + +**Incorrect (problematic PK choices):** + +```sql +-- identity is the SQL-standard approach +create table users ( + id serial primary key -- Works, but IDENTITY is recommended +); + +-- Random UUIDs (v4) cause index fragmentation +create table orders ( + id uuid default gen_random_uuid() primary key -- UUIDv4 = random = scattered inserts +); +``` + +**Correct (optimal PK strategies):** + +```sql +-- Use IDENTITY for sequential IDs (SQL-standard, best for most cases) +create table users ( + id bigint generated always as identity primary key +); + +-- For distributed systems needing UUIDs, use UUIDv7 (time-ordered) +-- Requires pg_uuidv7 extension: create extension pg_uuidv7; +create table orders ( + id uuid default uuid_generate_v7() primary key -- Time-ordered, no fragmentation +); + +-- Alternative: time-prefixed IDs for sortable, distributed IDs (no extension needed) +create table events ( + id text default concat( + to_char(now() at time zone 'utc', 'YYYYMMDDHH24MISSMS'), + gen_random_uuid()::text + ) primary key +); +``` + +Guidelines: + +- Single database: `bigint identity` (sequential, 8 bytes, SQL-standard) +- Distributed/exposed IDs: UUIDv7 (requires pg_uuidv7) or ULID (time-ordered, no + fragmentation) +- `serial` works but `identity` is SQL-standard and preferred for new + applications +- Avoid random UUIDs (v4) as primary keys on large tables (causes index + fragmentation) + +Reference: +[Identity Columns](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-GENERATED-IDENTITY) diff --git a/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md b/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md new file mode 100644 index 00000000..448ec345 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md @@ -0,0 +1,54 @@ +--- +title: Apply Principle of Least Privilege +impact: MEDIUM +impactDescription: Reduced attack surface, better audit trail +tags: privileges, security, roles, permissions +--- + +## Apply Principle of Least Privilege + +Grant only the minimum permissions required. Never use superuser for application queries. + +**Incorrect (overly broad permissions):** + +```sql +-- Application uses superuser connection +-- Or grants ALL to application role +grant all privileges on all tables in schema public to app_user; +grant all privileges on all sequences in schema public to app_user; + +-- Any SQL injection becomes catastrophic +-- drop table users; cascades to everything +``` + +**Correct (minimal, specific grants):** + +```sql +-- Create role with no default privileges +create role app_readonly nologin; + +-- Grant only SELECT on specific tables +grant usage on schema public to app_readonly; +grant select on public.products, public.categories to app_readonly; + +-- Create role for writes with limited scope +create role app_writer nologin; +grant usage on schema public to app_writer; +grant select, insert, update on public.orders to app_writer; +grant usage on sequence orders_id_seq to app_writer; +-- No DELETE permission + +-- Login role inherits from these +create role app_user login password 'xxx'; +grant app_writer to app_user; +``` + +Revoke public defaults: + +```sql +-- Revoke default public access +revoke all on schema public from public; +revoke all on all tables in schema public from public; +``` + +Reference: [Roles and Privileges](https://supabase.com/blog/postgres-roles-and-privileges) diff --git a/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md b/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md new file mode 100644 index 00000000..c61e1a85 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md @@ -0,0 +1,50 @@ +--- +title: Enable Row Level Security for Multi-Tenant Data +impact: CRITICAL +impactDescription: Database-enforced tenant isolation, prevent data leaks +tags: rls, row-level-security, multi-tenant, security +--- + +## Enable Row Level Security for Multi-Tenant Data + +Row Level Security (RLS) enforces data access at the database level, ensuring users only see their own data. + +**Incorrect (application-level filtering only):** + +```sql +-- Relying only on application to filter +select * from orders where user_id = $current_user_id; + +-- Bug or bypass means all data is exposed! +select * from orders; -- Returns ALL orders +``` + +**Correct (database-enforced RLS):** + +```sql +-- Enable RLS on the table +alter table orders enable row level security; + +-- Create policy for users to see only their orders +create policy orders_user_policy on orders + for all + using (user_id = current_setting('app.current_user_id')::bigint); + +-- Force RLS even for table owners +alter table orders force row level security; + +-- Set user context and query +set app.current_user_id = '123'; +select * from orders; -- Only returns orders for user 123 +``` + +Policy for authenticated role: + +```sql +create policy orders_user_policy on orders + for all + to authenticated + using (user_id = auth.uid()); +``` + +Reference: [Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security) diff --git a/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md b/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md new file mode 100644 index 00000000..b32d92f7 --- /dev/null +++ b/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md @@ -0,0 +1,57 @@ +--- +title: Optimize RLS Policies for Performance +impact: HIGH +impactDescription: 5-10x faster RLS queries with proper patterns +tags: rls, performance, security, optimization +--- + +## Optimize RLS Policies for Performance + +Poorly written RLS policies can cause severe performance issues. Use subqueries and indexes strategically. + +**Incorrect (function called for every row):** + +```sql +create policy orders_policy on orders + using (auth.uid() = user_id); -- auth.uid() called per row! + +-- With 1M rows, auth.uid() is called 1M times +``` + +**Correct (wrap functions in SELECT):** + +```sql +create policy orders_policy on orders + using ((select auth.uid()) = user_id); -- Called once, cached + +-- 100x+ faster on large tables +``` + +Use security definer functions for complex checks: + +```sql +-- Create helper function (runs as definer, bypasses RLS) +create or replace function is_team_member(team_id bigint) +returns boolean +language sql +security definer +set search_path = '' +as $$ + select exists ( + select 1 from public.team_members + where team_id = $1 and user_id = (select auth.uid()) + ); +$$; + +-- Use in policy (indexed lookup, not per-row check) +create policy team_orders_policy on orders + using ((select is_team_member(team_id))); +``` + +Always add indexes on columns used in RLS policies: + +```sql +create index orders_user_id_idx on orders (user_id); +``` + +Reference: [RLS Performance](https://supabase.com/docs/guides/database/postgres/row-level-security#rls-performance-recommendations) diff --git a/.claude/worktrees/peaceful-northcutt b/.claude/worktrees/peaceful-northcutt new file mode 160000 index 00000000..0d5ee84c --- /dev/null +++ b/.claude/worktrees/peaceful-northcutt @@ -0,0 +1 @@ +Subproject commit 0d5ee84c2d2509c9e1543f417eec317992a5d00e diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..bb081927 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Shell scripts run in Linux containers; CRLF breaks shebangs (e.g. /bin/sh^M). +*.sh text eol=lf + +# Collapse the lockfile in PR diffs; reviewers don't need to scroll past it. +package-lock.json linguist-generated=true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..689504a3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,40 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + groups: + mesh-sdk: + patterns: + - "@meshsdk/*" + next: + patterns: + - "next" + - "next-*" + - "@next/*" + prisma: + patterns: + - "prisma" + - "@prisma/*" + trpc: + patterns: + - "@trpc/*" + types: + patterns: + - "@types/*" + update-types: + - "minor" + - "patch" + labels: + - "dependencies" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + labels: + - "dependencies" + - "ci" diff --git a/.github/workflows/ci-smoke-preprod.yml b/.github/workflows/ci-smoke-preprod.yml index 548202d6..d02869be 100644 --- a/.github/workflows/ci-smoke-preprod.yml +++ b/.github/workflows/ci-smoke-preprod.yml @@ -3,6 +3,7 @@ name: CI Smoke (Preprod) on: pull_request: branches: [main, preprod] + deployment_status: workflow_dispatch: env: @@ -17,8 +18,18 @@ jobs: smoke: runs-on: ubuntu-latest timeout-minutes: 15 + # For deployment_status triggers, only run when Railway reports a + # successful deploy to the preprod environment. Other events always run. + if: >- + github.event_name != 'deployment_status' || + (github.event.deployment_status.state == 'success' && + github.event.deployment.creator.login == 'railway-app[bot]' && + contains(github.event.deployment.environment, 'preprod')) steps: - uses: actions/checkout@v4 + with: + # On deployment_status, check out the exact SHA that was deployed. + ref: ${{ github.event.deployment.sha || github.sha }} - uses: actions/setup-node@v4 with: diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 00000000..6f9b268f --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,47 @@ +name: PR Checks + +on: + pull_request: + branches: [main] + push: + branches: [main] + +concurrency: + group: pr-checks-${{ github.ref }} + cancel-in-progress: true + +jobs: + checks: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Generate Prisma client + run: npx prisma generate + + # Lint stays non-blocking until the rule set is cleaned up; tracked separately. + - name: Lint + run: npm run lint + continue-on-error: true + + # Typecheck, test, and build are gates — failures must fail the PR. + - name: Type check + run: npx tsc --noEmit + + - name: Test + run: npm run test:ci + + - name: Build + run: npm run build + env: + SKIP_ENV_VALIDATION: 'true' diff --git a/.github/workflows/pr-multisig-v1-smoke.yml b/.github/workflows/pr-multisig-v1-smoke.yml new file mode 100644 index 00000000..cb34aea2 --- /dev/null +++ b/.github/workflows/pr-multisig-v1-smoke.yml @@ -0,0 +1,166 @@ +name: PR Multisig v1 Smoke + +on: + pull_request: + branches: + - main + - preprod + workflow_dispatch: + inputs: + required_signers: + description: "Required signatures for CI wallet threshold scripts" + required: false + default: "2" + type: string + sign_wallet_type: + description: "Which wallet type to sign in smoke" + required: false + default: "legacy" + type: choice + options: + - legacy + - hierarchical + - sdk + route_scenarios: + description: "Optional comma-separated scenario IDs for scripts/ci/cli/route-chain.ts" + required: false + default: "" + type: string + +jobs: + multisig-v1-smoke: + if: github.repository == 'MeshJS/multisig' + runs-on: ubuntu-latest + timeout-minutes: 120 + env: + CI_JWT_SECRET: ${{ secrets.CI_JWT_SECRET }} + CI_MNEMONIC_1: ${{ secrets.CI_MNEMONIC_1 }} + CI_MNEMONIC_2: ${{ secrets.CI_MNEMONIC_2 }} + CI_MNEMONIC_3: ${{ secrets.CI_MNEMONIC_3 }} + CI_BLOCKFROST_PREPROD_API_KEY: ${{ secrets.CI_BLOCKFROST_PREPROD_API_KEY }} + CI_NETWORK_ID: "0" + CI_NUM_REQUIRED_SIGNERS: ${{ github.event_name == 'workflow_dispatch' && inputs.required_signers || '2' }} + CI_WALLET_TYPES: "legacy,hierarchical,sdk" + CI_SIGN_WALLET_TYPE: ${{ github.event_name == 'workflow_dispatch' && inputs.sign_wallet_type || 'legacy' }} + SIGN_BROADCAST: "true" + CI_ROUTE_SCENARIOS: ${{ github.event_name == 'workflow_dispatch' && inputs.route_scenarios || '' }} + CI_CONTEXT_PATH: /tmp/ci-wallet-context.json + CI_DREP_ANCHOR_URL: ${{ secrets.CI_DREP_ANCHOR_URL }} + CI_DREP_ANCHOR_JSON: ${{ secrets.CI_DREP_ANCHOR_JSON }} + CI_STAKE_POOL_ID_HEX: ${{ secrets.CI_STAKE_POOL_ID_HEX }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Validate required CI secrets + shell: bash + run: | + missing=() + [[ -n "$CI_JWT_SECRET" ]] || missing+=("CI_JWT_SECRET") + [[ -n "$CI_MNEMONIC_1" ]] || missing+=("CI_MNEMONIC_1") + [[ -n "$CI_MNEMONIC_2" ]] || missing+=("CI_MNEMONIC_2") + [[ -n "$CI_MNEMONIC_3" ]] || missing+=("CI_MNEMONIC_3") + [[ -n "$CI_BLOCKFROST_PREPROD_API_KEY" ]] || missing+=("CI_BLOCKFROST_PREPROD_API_KEY") + + route_scenarios=",${CI_ROUTE_SCENARIOS//[[:space:]]/}," + default_route_chain=false + if [[ -z "${CI_ROUTE_SCENARIOS//[[:space:]]/}" ]]; then + default_route_chain=true + fi + + scenario_enabled() { + local scenario_id="$1" + [[ "$default_route_chain" == "true" || "$route_scenarios" == *",$scenario_id,"* ]] + } + + if scenario_enabled "scenario.drep-certificates" || scenario_enabled "scenario.proxy-full-lifecycle"; then + [[ -n "$CI_DREP_ANCHOR_URL" ]] || missing+=("CI_DREP_ANCHOR_URL") + fi + if scenario_enabled "scenario.drep-certificates"; then + [[ -n "$CI_DREP_ANCHOR_JSON" ]] || missing+=("CI_DREP_ANCHOR_JSON") + fi + if scenario_enabled "scenario.stake-certificates"; then + [[ -n "$CI_STAKE_POOL_ID_HEX" ]] || missing+=("CI_STAKE_POOL_ID_HEX") + fi + + if [[ "${#missing[@]}" -gt 0 ]]; then + echo "Missing required secrets: ${missing[*]}" + echo "Set these in repo settings before running PR multisig smoke workflow." + exit 1 + fi + + - name: Pull base image (with retry) + shell: bash + run: | + for i in 1 2 3; do + docker pull node:20-alpine && break + echo "Pull attempt $i failed, retrying in 30s..." + sleep 30 + done + + - name: Build CI containers + shell: bash + run: docker compose -f docker-compose.ci.yml build + + - name: Start Postgres + App containers + shell: bash + run: docker compose -f docker-compose.ci.yml up -d postgres app + + - name: Wait for app healthcheck + shell: bash + run: | + for i in {1..60}; do + status=$(docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$(docker compose -f docker-compose.ci.yml ps -q app)") + if [[ "$status" == "healthy" ]]; then + echo "App is healthy." + exit 0 + fi + sleep 2 + done + + echo "App failed to become healthy in time." + docker compose -f docker-compose.ci.yml ps + exit 1 + + - name: Run CI wallet bootstrap + v1 route-chain smoke + shell: bash + run: docker compose -f docker-compose.ci.yml --profile ci-test run --rm ci-runner + + - name: Dump container logs on failure + if: failure() + shell: bash + run: | + docker compose -f docker-compose.ci.yml logs --no-color \ + | sed -E 's/(Bearer )[A-Za-z0-9._-]+/\1[REDACTED]/g' \ + | sed -E 's/("token"[[:space:]]*:[[:space:]]*")[^"]+(")/\1[REDACTED]\2/g' \ + | sed -E 's/("secret"[[:space:]]*:[[:space:]]*")[^"]+(")/\1[REDACTED]\2/g' \ + | sed -E 's/("mnemonic([[:alnum:]_-]*)?"[[:space:]]*:[[:space:]]*")[^"]+(")/\1[REDACTED]\3/gI' \ + | sed -E 's/("private([[:alnum:]_-]*)?key([[:alnum:]_-]*)?"[[:space:]]*:[[:space:]]*")[^"]+(")/\1[REDACTED]\3/gI' \ + | sed -E 's/("signing([[:alnum:]_-]*)?key([[:alnum:]_-]*)?"[[:space:]]*:[[:space:]]*")[^"]+(")/\1[REDACTED]\3/gI' \ + | sed -E 's/("seed([[:alnum:]_-]*)?"[[:space:]]*:[[:space:]]*")[^"]+(")/\1[REDACTED]\3/gI' \ + | sed -E 's/("xprv([[:alnum:]_-]*)?"[[:space:]]*:[[:space:]]*")[^"]+(")/\1[REDACTED]\3/gI' \ + | sed -E 's/(ed25519e?_sk[[:alnum:]_]+)/[REDACTED]/gI' \ + | sed -E 's/(xprv[[:alnum:]]+)/[REDACTED]/gI' \ + > docker-compose-ci.log + + - name: Upload logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: docker-compose-ci-logs + path: docker-compose-ci.log + + - name: Upload route-chain report + if: always() + uses: actions/upload-artifact@v4 + with: + name: ci-route-chain-report + path: ci-artifacts/ci-route-chain-report.md + if-no-files-found: warn + + - name: Tear down CI containers + if: always() + shell: bash + run: docker compose -f docker-compose.ci.yml down -v --remove-orphans + diff --git a/.gitignore b/.gitignore index 4924b8ab..189ad92e 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,9 @@ yarn-debug.log* yarn-error.log* .pnpm-debug.log* +# CI local artifacts +/ci-artifacts/ + # local env files # do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables .env diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 00000000..6571769d --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "supabase": { + "type": "http", + "url": "https://mcp.supabase.com/mcp?project_ref=wzgemhfjyfnqmhxlvkqc&read_only=true" + } + } +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..f98c0c0c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,107 @@ +# Contributing + +Thanks for your interest in Mesh Multi-Sig. This document describes how we work on the project: filing issues, opening pull requests, and getting changes reviewed and merged. + +> **Contributions are accepted against the `preprod` branch.** All PRs — external and internal — should target `preprod`, not `main`. Changes graduate from `preprod` to `main` after they run clean in the preprod environment and pass smoke CI. The only exception is a critical hotfix, which may target `main` directly. + +## Who reviews what + +- Core maintainers: **Quirin** and **Andre**. +- Every PR is reviewed by the contributor who did not author it. If the author is external, either maintainer can review. +- Ownership per feature area is tracked in [ROADMAP.md](ROADMAP.md#task-ownership). The owner for a given area gets first look. + +## Filing an issue + +Before opening an issue, search open and closed issues — many things are already tracked. + +A good issue has: + +- **Title:** one line describing the symptom, not the guess at a cause +- **Steps to reproduce:** exact clicks, URLs, inputs +- **Expected vs actual:** what should happen, what does happen +- **Environment:** browser, network (preprod / mainnet), wallet, commit or deploy URL +- **Logs or screenshots** if the bug is visible + +Label the issue (`bug`, `enhancement`, `research`, etc.) and attach the relevant milestone from the [roadmap milestones](../../milestones) if one applies. + +## Branches + +- `main` — production. Only maintainers merge to `main`. +- `preprod` — integration branch deployed to the preprod environment and exercised by the smoke CI. +- Feature / fix branches use a short prefix matching intent: + - `feature/` — new user-facing capability + - `fix/` — bug fix + - `refactor/` — internal change, no behavior change + - `docs/` — docs only + - `chore/` — tooling, dependencies, build + +Branch off `preprod` by default. Branch off `main` only for hotfixes that need to ship immediately. + +## Commit messages + +We follow [Conventional Commits](https://www.conventionalcommits.org/): + +``` +: + + +``` + +Types in use: `feat`, `fix`, `refactor`, `chore`, `docs`, `test`. + +Keep the subject under 72 characters. Write the body when the "why" is non-obvious — a linked issue, a tradeoff, a constraint. Don't restate the diff. + +## Pull requests + +Open the PR against `preprod` unless it's a hotfix for `main`. + +Your PR description should include: + +- **What** the change does in one or two sentences +- **Why** — the issue, incident, or decision it addresses (link the issue: `Closes #123`) +- **How to test** — concrete steps a reviewer can run to verify, including any preprod URL +- **Screenshots or recordings** for UI changes +- **Risk** — anything a reviewer should look at closely (migrations, auth, on-chain behavior) + +Before requesting review: + +- [ ] Rebased on the latest target branch +- [ ] Type-check and lint pass locally (`npm run build`, `npm run lint`) +- [ ] New or changed logic is covered by tests where practical +- [ ] Smoke CI is green on the PR (or the failure is understood and unrelated) +- [ ] UI changes have been loaded in a browser, not just type-checked + +## Review + +Reviewers look for: + +1. Correctness — does the change actually do what it says? +2. Scope — no drive-by refactors, no unrelated cleanup, no half-finished migrations +3. Security — input validation at boundaries, no secrets committed, RLS intact, no new injection surface +4. Tests — is the happy path covered? The failure modes you'd expect a user to hit? +5. Docs — if behavior changed, did docs and examples move too? + +Review etiquette: + +- Comment with intent: `nit:` (optional), `question:` (clarify), `blocking:` (must address before merge) +- Prefer suggestions over prose when the change is mechanical +- Resolve your own threads after addressing feedback; don't resolve someone else's + +Two weak approvals do not substitute for one careful review. If a change touches unfamiliar territory, say so and ask the owner to take a pass. + +## Merging + +- Squash merge by default — keep `main` history linear and each commit a complete change. +- Only merge when: + - At least one approval from a maintainer who did not author the PR + - CI is green (or failure is documented and unrelated) + - All blocking comments resolved +- The author merges. If the author is external, the reviewing maintainer merges. + +## Security + +Don't open public issues for vulnerabilities. Email the maintainers directly and we'll coordinate a fix. + +## Questions + +If you're unsure whether something belongs in scope, open a draft PR or an issue with the `question` label — we'd rather discuss early than review a large change that needs to be redone. diff --git a/Dockerfile.ci b/Dockerfile.ci new file mode 100644 index 00000000..ee3f9965 --- /dev/null +++ b/Dockerfile.ci @@ -0,0 +1,17 @@ +FROM node:20-alpine + +# Install PostgreSQL client tools for readiness checks. +RUN apk add --no-cache postgresql-client + +WORKDIR /app + +# Install dependencies first for better layer caching. +COPY package.json package-lock.json* ./ +COPY prisma ./prisma +RUN npm ci + +# Copy full source for containerized CI runs. +COPY . . + +EXPOSE 3000 + diff --git a/ROADMAP.md b/ROADMAP.md index c32327ba..7374f8b1 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -27,6 +27,19 @@ | **Review and handle open external PRs** - Summon API routes and capability-based metadata from kanyuku | Quirin + Andre | PR #212, PR #208 | | Fix legacy wallet compatibility bug | Quirin + Andre | | +### Proof of completion + +Status of M1 tasks. Last updated 2026-04-23. + +| Task | Status | Evidence | +|------|--------|----------| +| Define review process for issues and PRs | Drafted | [`CONTRIBUTING.md`](CONTRIBUTING.md) covers issue template, branch/commit conventions, PR + review process, merge rules. Pending: team sign-off | +| Improve repository infrastructure — preprod + smoke CI | Done | `preprod` branch active; [PR #218](https://github.com/MeshJS/multisig/pull/218) merged; [`.github/workflows/ci-smoke-preprod.yml`](.github/workflows/ci-smoke-preprod.yml) landed | +| CI smoke tests on real chain (#213) | Landed, awaiting secrets | [PR #217](https://github.com/MeshJS/multisig/pull/217) merged (CI smoke system + VKey witness fix); `dc49af2` skips gracefully when secrets missing. All runs since have hit the skip path (~8s) because `SMOKE_*` repo secrets are not yet configured; [Issue #213](https://github.com/MeshJS/multisig/issues/213) stays open until the first real route-chain run is linked | +| Fix transaction loading bug (#211) | In review | [PR #227](https://github.com/MeshJS/multisig/pull/227) open: validates CBOR + JSON on `POST /api/v1/addTransaction` and renders a degraded "Unreadable transaction" card with Reject & Delete so already-poisoned wallets can free their UTxOs | +| Review and handle open external PRs (PR #212, PR #208) | Reviewed, awaiting author | Change requests left on [PR #212](https://github.com/MeshJS/multisig/pull/212) (rebase to `preprod`, drop non-null assertion in `useWalletBalances`, Summon `canVote` TODO) and [PR #208](https://github.com/MeshJS/multisig/pull/208) (superset of #212, recommended to close) | +| Fix legacy wallet compatibility bug | Done | [PR #210](https://github.com/MeshJS/multisig/pull/210) (legacy drep retirement) and [PR #225](https://github.com/MeshJS/multisig/pull/225) (drep deregistration fix, commit `4ae3d10`) merged; [Issue #223](https://github.com/MeshJS/multisig/issues/223) closed | + --- ## Months 2–3 — June–July 2026 @@ -119,3 +132,46 @@ - Final summary report in month 12 **GitHub milestones:** Created and issues assigned. View at [Milestones](../../milestones). + +--- + +## Task ownership + +Aggregated view of the 12-month roadmap split by contributor. Each task has a single owner; the other contributor reviews the PR. + +### Quirin + +- [M1] Define review process for issues and PRs +- [M1] Fix transaction loading bug (#211) +- [M1] Handle external PR — Summon API routes (PR #212) +- [M1] Fix legacy wallet compatibility bug +- [M2–3] Improved authentication — nonce-based auth, wallet connection fixes, registration flow (#135, #53) +- [M2–3] Full address verification (#196) +- [M2–3] Transaction pagination (#30) +- [M4–6] Aiken crowdfund integration (PR #164) +- [M4–6] Governance metadata fix (#122) +- [M4–6] Proxy voting polish and documentation +- [M4–6] FROST research kickoff (#220) +- [M7–9] dApp connector — external dApps request multi-sig transactions +- [M7–9] FROST research — deliver findings, PoC, go/no-go (#220) +- [M10–12] Vesting — time-locked multi-sig contracts (#81) +- [M10–12] Performance and UX audit +- [M10–12] Invite flow (PR #67) +- [M10–12] Final summary report + +### Andre + +- [M1] Improve repository infrastructure — preprod environment and comprehensive smoke CI +- [M1] CI smoke tests on real chain (#213) +- [M1] Handle external PR — capability-based metadata (PR #208) +- [M2–3] Summon migration — land API routes and wallet import (PR #212, PR #208) +- [M2–3] Collateral service — 22 ADA → 4 UTxOs for proxy collateral (#221) +- [M2–3] Better 404 page (#22) +- [M4–6] Wallet V2 — on-chain registration and discovery (#33) +- [M4–6] Pending transactions on homepage (#125) +- [M4–6] Backlog cleanup, dependency/security updates +- [M7–9] Hardware wallet support — Ledger/Trezor (#44) +- [M7–9] Bot platform v2 — SDK, webhooks, example bots +- [M7–9] API documentation and developer portal +- [M10–12] User profiles and contacts +- [M10–12] Discover page — browse wallets, DAOs, governance (#52) diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml new file mode 100644 index 00000000..57ca457a --- /dev/null +++ b/docker-compose.ci.yml @@ -0,0 +1,107 @@ +services: + postgres: + image: postgres:14-alpine + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: multisig + volumes: + - postgres-ci-data:/var/lib/postgresql/data + - ./docker/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 20 + networks: + - multisig-ci-network + + app: + build: + context: . + dockerfile: Dockerfile.ci + environment: + NODE_ENV: test + NEXT_TELEMETRY_DISABLED: "1" + SKIP_ENV_VALIDATION: "true" + DATABASE_URL: postgresql://postgres:postgres@postgres:5432/multisig + DIRECT_URL: postgresql://postgres:postgres@postgres:5432/multisig + JWT_SECRET: ${CI_JWT_SECRET} + NEXT_PUBLIC_BLOCKFROST_API_KEY_PREPROD: ${CI_BLOCKFROST_PREPROD_API_KEY:-} + NEXT_PUBLIC_BLOCKFROST_API_KEY_MAINNET: ${CI_BLOCKFROST_MAINNET_API_KEY:-} + BLOCKFROST_API_KEY_PREPROD: ${CI_BLOCKFROST_PREPROD_API_KEY:-} + depends_on: + postgres: + condition: service_healthy + networks: + - multisig-ci-network + command: > + sh -c " + echo 'Waiting for PostgreSQL to be ready...' && + until pg_isready -h postgres -p 5432 -U postgres; do sleep 1; done && + echo 'Running Prisma migrations...' && + npx prisma migrate deploy || npx prisma db push && + echo 'Starting application...' && + npm run dev -- --hostname 0.0.0.0 --port 3000 + " + healthcheck: + test: + - CMD-SHELL + - node -e "fetch('http://localhost:3000/api/swagger').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))" + interval: 5s + timeout: 5s + retries: 30 + + ci-runner: + build: + context: . + dockerfile: Dockerfile.ci + environment: + NODE_ENV: test + NEXT_TELEMETRY_DISABLED: "1" + SKIP_ENV_VALIDATION: "true" + DATABASE_URL: postgresql://postgres:postgres@postgres:5432/multisig + DIRECT_URL: postgresql://postgres:postgres@postgres:5432/multisig + API_BASE_URL: http://app:3000 + CI_NETWORK_ID: ${CI_NETWORK_ID:-0} + CI_NUM_REQUIRED_SIGNERS: ${CI_NUM_REQUIRED_SIGNERS:-2} + CI_JWT_SECRET: ${CI_JWT_SECRET} + CI_MNEMONIC_1: ${CI_MNEMONIC_1:-} + CI_MNEMONIC_2: ${CI_MNEMONIC_2:-} + CI_MNEMONIC_3: ${CI_MNEMONIC_3:-} + CI_BLOCKFROST_PREPROD_API_KEY: ${CI_BLOCKFROST_PREPROD_API_KEY:-} + CI_WALLET_TYPES: ${CI_WALLET_TYPES:-legacy,hierarchical,sdk} + CI_SIGN_WALLET_TYPE: ${CI_SIGN_WALLET_TYPE:-legacy} + SIGN_BROADCAST: ${SIGN_BROADCAST:-true} + CI_ROUTE_SCENARIOS: ${CI_ROUTE_SCENARIOS:-} + CI_ROUTE_CHAIN_REPORT_PATH: ${CI_ROUTE_CHAIN_REPORT_PATH:-/artifacts/ci-route-chain-report.md} + CI_CONTEXT_PATH: ${CI_CONTEXT_PATH:-/tmp/ci-wallet-context.json} + CI_DREP_ANCHOR_URL: ${CI_DREP_ANCHOR_URL:-} + CI_DREP_ANCHOR_JSON: ${CI_DREP_ANCHOR_JSON:-} + CI_STAKE_POOL_ID_HEX: ${CI_STAKE_POOL_ID_HEX:-} + depends_on: + app: + condition: service_healthy + networks: + - multisig-ci-network + volumes: + - ./ci-artifacts:/artifacts + profiles: + - ci-test + command: > + sh -c " + status=0; + npx --yes tsx scripts/ci/cli/bootstrap.ts || status=$$?; + if [ \"$$status\" -eq 0 ]; then npx --yes tsx scripts/ci/cli/wallet-status.ts || status=$$?; fi; + if [ \"$$status\" -eq 0 ]; then npx --yes tsx scripts/ci/cli/route-chain.ts || status=$$?; fi; + rm -f \"${CI_CONTEXT_PATH:-/tmp/ci-wallet-context.json}\"; + exit \"$$status\" + " + +volumes: + postgres-ci-data: + +networks: + multisig-ci-network: + driver: bridge + diff --git a/docker/init-db.sh b/docker/init-db.sh index 659312d0..69147448 100755 --- a/docker/init-db.sh +++ b/docker/init-db.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh set -e echo "Initializing database..." diff --git a/jest.config.mjs b/jest.config.mjs index 3cb3583f..bcc6511c 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -16,6 +16,10 @@ export default { }, moduleNameMapper: { '^@/(.*)$': '/src/$1', + // libsodium-wrappers-sumo ships an .mjs that does `import "./libsodium-sumo.mjs"`, + // but that file lives in the separate `libsodium-sumo` package. Node resolves it + // via package.json exports; Jest's ESM resolver does not. Redirect. + '^\\./libsodium-sumo\\.mjs$': '/node_modules/libsodium-sumo/dist/modules-sumo-esm/libsodium-sumo.mjs', }, collectCoverageFrom: [ 'src/**/*.{ts,tsx}', diff --git a/package-lock.json b/package-lock.json index 506f37ff..dfadd9cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,11 @@ "@auth/prisma-adapter": "^2.11.1", "@hookform/resolvers": "^3.9.0", "@jinglescode/nostr-chat-plugin": "^0.0.11", - "@meshsdk/core": "^1.9.0-beta.87", - "@meshsdk/core-csl": "^1.9.0-beta.87", - "@meshsdk/core-cst": "^1.9.0-beta.87", - "@meshsdk/provider": "^1.9.0-beta.86", - "@meshsdk/react": "^1.9.0-beta.87", + "@meshsdk/core": "1.9.0-beta.102", + "@meshsdk/core-csl": "1.9.0-beta.102", + "@meshsdk/core-cst": "1.9.0-beta.102", + "@meshsdk/provider": "1.9.0-beta.100", + "@meshsdk/react": "1.9.0-beta-40", "@octokit/core": "^6.1.2", "@prisma/client": "^6.17.1", "@radix-ui/react-accordion": "^1.2.0", @@ -116,6 +116,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -124,20 +125,26 @@ } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", - "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-14.0.1.tgz", + "integrity": "sha512-Oc96zvmxx1fqoSEdUmfmvvb59/KDOnUoJ7s2t7bISyAn0XEz57LCCw8k2Y4Pf3mwKaZLMciESALORLgfe2frCw==", + "license": "MIT", "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.6", - "call-me-maybe": "^1.0.1", + "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" } }, "node_modules/@apidevtools/openapi-schemas": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "license": "MIT", "engines": { "node": ">=10" } @@ -145,39 +152,79 @@ "node_modules/@apidevtools/swagger-methods": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", + "license": "MIT" }, "node_modules/@apidevtools/swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-12.1.0.tgz", + "integrity": "sha512-e5mJoswsnAX0jG+J09xHFYQXb/bUc5S3pLpMxUuRUA2H8T2kni3yEoyz2R3Dltw5f4A6j6rPNMpWTK+iVDFlng==", + "license": "MIT", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/json-schema-ref-parser": "14.0.1", + "@apidevtools/openapi-schemas": "^2.1.0", "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "call-me-maybe": "^1.0.1", - "z-schema": "^5.0.1" + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "call-me-maybe": "^1.0.2" }, "peerDependencies": { "openapi-types": ">=7" } }, + "node_modules/@apidevtools/swagger-parser/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "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/@apidevtools/swagger-parser/node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@apidevtools/swagger-parser/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/@auth/prisma-adapter": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@auth/prisma-adapter/-/prisma-adapter-2.11.1.tgz", - "integrity": "sha512-Ke7DXP0Fy0Mlmjz/ZJLXwQash2UkA4621xCM0rMtEczr1kppLc/njCbUkHkIQ/PnmILjqSPEKeTjDPsYruvkug==", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@auth/prisma-adapter/-/prisma-adapter-2.11.2.tgz", + "integrity": "sha512-GyNEUNtrPgDPs0M4xX6F5i7jTsCKwU6BXV9zutctcoo6K1Ud+juckrmQS11uyNgeWsw6sliextHbU/e+8lsizQ==", + "license": "ISC", "dependencies": { - "@auth/core": "0.41.1" + "@auth/core": "0.41.2" }, "peerDependencies": { "@prisma/client": ">=2.26.0 || >=3 || >=4 || >=5 || >=6" } }, "node_modules/@auth/prisma-adapter/node_modules/@auth/core": { - "version": "0.41.1", - "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.41.1.tgz", - "integrity": "sha512-t9cJ2zNYAdWMacGRMT6+r4xr1uybIdmYa49calBPeTqwgAFPV/88ac9TEvCR85pvATiSPt8VaNf+Gt24JIT/uw==", + "version": "0.41.2", + "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.41.2.tgz", + "integrity": "sha512-Hx5MNBxN2fJTbJKGUKAA0wca43D0Akl3TvufY54Gn8lop7F+34vU1zA1pn0vQfIoVuLIrpfc2nkyjwIaPJMW7w==", + "license": "ISC", "dependencies": { "@panva/hkdf": "^1.2.1", "jose": "^6.0.6", @@ -202,18 +249,31 @@ } } }, + "node_modules/@auth/prisma-adapter/node_modules/@simplewebauthn/browser": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-9.0.1.tgz", + "integrity": "sha512-wD2WpbkaEP4170s13/HUxPcAV5y4ZXaKo1TfNklS5zDefPinIgXOpgz1kpEvobAsaLPa2KeH7AKKX/od1mrBJw==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@simplewebauthn/types": "^9.0.1" + } + }, "node_modules/@auth/prisma-adapter/node_modules/jose": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz", - "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } }, "node_modules/@auth/prisma-adapter/node_modules/oauth4webapi": { - "version": "3.8.5", - "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.5.tgz", - "integrity": "sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg==", + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.6.tgz", + "integrity": "sha512-iwemM91xz8nryHti2yTmg5fhyEMVOkOXwHNqbvcATjyajb5oQxCQzrNOA6uElRHuMhQQTKUyFKV9y/CNyg25BQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } @@ -222,6 +282,7 @@ "version": "6.5.11", "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz", "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==", + "license": "MIT", "peerDependencies": { "preact": ">=10" } @@ -230,6 +291,8 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", @@ -240,9 +303,11 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -251,6 +316,8 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -276,10 +343,22 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { "version": "7.29.1", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", @@ -295,6 +374,8 @@ "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==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", @@ -306,10 +387,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -318,6 +411,8 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" @@ -330,6 +425,8 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", @@ -346,6 +443,8 @@ "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==", + "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -354,6 +453,8 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -362,6 +463,8 @@ "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, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -370,6 +473,8 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -378,6 +483,8 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" @@ -387,9 +494,11 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" }, @@ -405,6 +514,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -417,6 +527,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -429,6 +540,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -441,6 +553,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -451,22 +564,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.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==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, @@ -482,6 +585,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -494,6 +598,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -506,6 +611,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, @@ -521,6 +627,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -533,6 +640,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -545,6 +653,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -557,6 +666,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -569,6 +679,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -581,6 +692,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -593,6 +705,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -608,6 +721,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -623,6 +737,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, @@ -637,6 +752,7 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -645,6 +761,7 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.2.tgz", "integrity": "sha512-Lc94FOD5+0aXhdb0Tdg3RUtqT6yWbI/BbFWvlaSJ3gAb9Ks+99nHRDKADVqC37er4eCB0fHyWT+y+K3QOvJKbw==", + "license": "MIT", "dependencies": { "core-js-pure": "^3.48.0" }, @@ -656,6 +773,8 @@ "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==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", @@ -669,6 +788,8 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -686,6 +807,8 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" @@ -698,12 +821,14 @@ "version": "1.2.10", "resolved": "https://registry.npmjs.org/@basementuniverse/commonjs/-/commonjs-1.2.10.tgz", "integrity": "sha512-hmqEAGVCdsyQWJ5PwweFegOZ19gBm5Ppw48/l8mOexcjubyuhmgRt6SB8BoLF9C4lzRemG816hH77w7hJRrDMA==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info." + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" }, "node_modules/@basementuniverse/marble-identicons": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@basementuniverse/marble-identicons/-/marble-identicons-0.1.2.tgz", "integrity": "sha512-Z9w8lp4hwy3zwtl+ldVtN+Vr9BkD/NJCJZWLDjiWYLIkMPglhqUDy8ffXNDAB35UmKj7p/X+LKtSr+ApbMYhLA==", + "license": "MIT", "dependencies": { "@basementuniverse/commonjs": "^1.2.10", "seed-random": "^2.2.0" @@ -713,12 +838,14 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@biglup/is-cid": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@biglup/is-cid/-/is-cid-1.0.3.tgz", "integrity": "sha512-R0XPZ/IQhU2TtetSFI9vI+7kJOJYNiCncn5ixEBW+/LNaZCo2HK37Mq3pRNzrM4FryuAkyeqY7Ujmj3I3e3t9g==", + "license": "Apache-2.0", "dependencies": { "@multiformats/mafmt": "^12.1.6", "@multiformats/multiaddr": "^12.1.14", @@ -735,6 +862,7 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/@bitcoin-js/tiny-secp256k1-asmjs/-/tiny-secp256k1-asmjs-2.2.4.tgz", "integrity": "sha512-Lo62disBIDwPrYAmMsSjEmqak41yb0OFGQVLdktXmcQLgtC1BI5Sd1eHSxNREKZmxMUXevtsgEhGB1DvvatRmQ==", + "license": "MIT", "dependencies": { "uint8array-tools": "0.0.7" }, @@ -745,12 +873,14 @@ "node_modules/@bufbuild/protobuf": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.1.tgz", - "integrity": "sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==" + "integrity": "sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/@cardano-ogmios/client": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/@cardano-ogmios/client/-/client-6.9.0.tgz", "integrity": "sha512-IsoUVsaMXiYyhWrdVKYOA5PDlX0EZ2gaq4lfk4JelRw6mcWVxemUrMaU2ndvugO9LQ3SCM1nESPgMIU0xe5FWw==", + "license": "MPL-2.0", "dependencies": { "@cardano-ogmios/schema": "6.9.0", "@cardanosolutions/json-bigint": "^1.0.1", @@ -771,20 +901,22 @@ "version": "6.9.0", "resolved": "https://registry.npmjs.org/@cardano-ogmios/schema/-/schema-6.9.0.tgz", "integrity": "sha512-e7QVLF+dQMIv9p+p5CWQjMfBmkERYRa2wK2AjyehQZCJnecZ0gvTbRqewdX5VW4mVXf6KUfFyphsxWK46Pg6LA==", + "license": "MPL-2.0", "engines": { "node": ">=14" } }, "node_modules/@cardano-sdk/core": { - "version": "0.46.12", - "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.46.12.tgz", - "integrity": "sha512-yUA/xBUQMiMqIWiZPvIhM911pL3jNKg4PkZQ8qP9R7yU3NQ5x4RQkZ+zFDlVLxUt+gJiwIW2es0iPd8ObIKCxA==", + "version": "0.45.10", + "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.45.10.tgz", + "integrity": "sha512-PU/onQuPgsy0CtFKDlHcozGHMTHrigWztTmKq54tL0TdWRcClXbMh5Q63ALcP388ZouPC1nKomOAooVgyrrEfw==", + "license": "Apache-2.0", "dependencies": { "@biglup/is-cid": "^1.0.3", "@cardano-ogmios/client": "6.9.0", "@cardano-ogmios/schema": "6.9.0", - "@cardano-sdk/crypto": "~0.4.5", - "@cardano-sdk/util": "~0.17.1", + "@cardano-sdk/crypto": "~0.2.3", + "@cardano-sdk/util": "~0.16.0", "@foxglove/crc": "^0.0.3", "@scure/base": "^1.1.1", "fraction.js": "4.0.1", @@ -806,17 +938,36 @@ } } }, + "node_modules/@cardano-sdk/core/node_modules/@cardano-sdk/util": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.16.0.tgz", + "integrity": "sha512-f0tfX8oiauqAFCyyc/o2Ouezyk83QD4zqLl4DUjZNyCtITL8gBHh25Bkw7RUCGEZ+hf6Qms1n0ui0j3wVY7zRg==", + "license": "Apache-2.0", + "dependencies": { + "bech32": "^2.0.0", + "lodash": "^4.17.21", + "serialize-error": "^8", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "type-fest": "^2.19.0" + }, + "engines": { + "node": ">=16.20.2" + } + }, "node_modules/@cardano-sdk/crypto": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.4.5.tgz", - "integrity": "sha512-ymliqxdmen5dGVaiMVQ0VnhrwaYUjbPD3sHoMj8NI6MTuxrREp3pLJASREtWhwmv9k+QzDT6CoyuIXnlEQiWZQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.2.3.tgz", + "integrity": "sha512-jTl8rbocV1XO5DBR6+lGY6Owc/bP+wBg5eO3PttTeKhx/J7o99pyuTa5H36a/XTJwqDwKIXV922QxZR+rfjVbA==", + "license": "Apache-2.0", "dependencies": { - "@cardano-sdk/util": "~0.17.1", + "@cardano-sdk/util": "~0.16.0", "blake2b": "^2.1.4", "i": "^0.3.7", - "libsodium-wrappers-sumo": "0.7.10", + "libsodium-wrappers-sumo": "^0.7.5", "lodash": "^4.17.21", - "pbkdf2": "^3.1.3", + "npm": "^9.3.0", + "pbkdf2": "^3.1.2", "ts-custom-error": "^3.2.0", "ts-log": "^2.2.4" }, @@ -840,10 +991,28 @@ } } }, + "node_modules/@cardano-sdk/crypto/node_modules/@cardano-sdk/util": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.16.0.tgz", + "integrity": "sha512-f0tfX8oiauqAFCyyc/o2Ouezyk83QD4zqLl4DUjZNyCtITL8gBHh25Bkw7RUCGEZ+hf6Qms1n0ui0j3wVY7zRg==", + "license": "Apache-2.0", + "dependencies": { + "bech32": "^2.0.0", + "lodash": "^4.17.21", + "serialize-error": "^8", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "type-fest": "^2.19.0" + }, + "engines": { + "node": ">=16.20.2" + } + }, "node_modules/@cardano-sdk/dapp-connector": { "version": "0.13.26", "resolved": "https://registry.npmjs.org/@cardano-sdk/dapp-connector/-/dapp-connector-0.13.26.tgz", "integrity": "sha512-4GptUVsGmgZhzKs+yp3360dA+HNdMi8IW1r2n1H63PYOJDPj2bjopBeyOGFn8Dmkzt+64rm2KyVyZM2SlcUq9Q==", + "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "~0.46.12", "@cardano-sdk/crypto": "~0.4.5", @@ -856,74 +1025,300 @@ "node": ">=16.20.2" } }, - "node_modules/@cardano-sdk/input-selection": { - "version": "0.14.28", - "resolved": "https://registry.npmjs.org/@cardano-sdk/input-selection/-/input-selection-0.14.28.tgz", - "integrity": "sha512-pbysJUaIbbpesbv/f0XfFPKBb+bLjCmPcMfNJzpePSZBvr8bUcFpnfKtq28KthVdpe2mgL3k9ebTTcBSk7aERw==", + "node_modules/@cardano-sdk/dapp-connector/node_modules/@cardano-sdk/core": { + "version": "0.46.12", + "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.46.12.tgz", + "integrity": "sha512-yUA/xBUQMiMqIWiZPvIhM911pL3jNKg4PkZQ8qP9R7yU3NQ5x4RQkZ+zFDlVLxUt+gJiwIW2es0iPd8ObIKCxA==", + "license": "Apache-2.0", "dependencies": { - "@cardano-sdk/core": "~0.46.12", - "@cardano-sdk/key-management": "~0.29.12", + "@biglup/is-cid": "^1.0.3", + "@cardano-ogmios/client": "6.9.0", + "@cardano-ogmios/schema": "6.9.0", + "@cardano-sdk/crypto": "~0.4.5", "@cardano-sdk/util": "~0.17.1", - "bignumber.js": "^9.1.1", + "@foxglove/crc": "^0.0.3", + "@scure/base": "^1.1.1", + "fraction.js": "4.0.1", + "ip-address": "^9.0.5", "lodash": "^4.17.21", - "ts-custom-error": "^3.2.0" + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "web-encoding": "^1.1.5" }, "engines": { "node": ">=16.20.2" + }, + "peerDependencies": { + "rxjs": "^7.4.0" + }, + "peerDependenciesMeta": { + "rxjs": { + "optional": true + } } }, - "node_modules/@cardano-sdk/key-management": { - "version": "0.29.12", - "resolved": "https://registry.npmjs.org/@cardano-sdk/key-management/-/key-management-0.29.12.tgz", - "integrity": "sha512-bctIVPg0DBCECnECIPCBfHwnF3En+AVJzpUdje+Q2a+/kryolw99i5Y7le+rpjq1LRypWUG0sUAGLY8D850epA==", + "node_modules/@cardano-sdk/dapp-connector/node_modules/@cardano-sdk/crypto": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.4.5.tgz", + "integrity": "sha512-ymliqxdmen5dGVaiMVQ0VnhrwaYUjbPD3sHoMj8NI6MTuxrREp3pLJASREtWhwmv9k+QzDT6CoyuIXnlEQiWZQ==", + "license": "Apache-2.0", "dependencies": { - "@cardano-sdk/core": "~0.46.12", - "@cardano-sdk/crypto": "~0.4.5", - "@cardano-sdk/dapp-connector": "~0.13.26", "@cardano-sdk/util": "~0.17.1", - "@emurgo/cardano-message-signing-nodejs": "^1.0.1", - "bip39": "^3.0.4", - "chacha": "^2.1.0", - "get-random-values": "^2.0.0", + "blake2b": "^2.1.4", + "i": "^0.3.7", + "libsodium-wrappers-sumo": "0.7.10", "lodash": "^4.17.21", "pbkdf2": "^3.1.3", - "rxjs": "^7.4.0", "ts-custom-error": "^3.2.0", "ts-log": "^2.2.4" }, "engines": { "node": ">=16.20.2" - } - }, - "node_modules/@cardano-sdk/util": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.17.1.tgz", - "integrity": "sha512-TCYe+wRguW1WgRlbWqhGPhcSBkzVzdIcCVgDDN7wiQk2dew0EWVqjsKeqDZdfwzy/s2kr/ZOgXIGywBn/Bzu/Q==", - "dependencies": { - "bech32": "^2.0.0", - "lodash": "^4.17.21", - "serialize-error": "^8", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4" }, - "engines": { - "node": ">=16.20.2" + "peerDependencies": { + "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" + }, + "peerDependenciesMeta": { + "@dcspark/cardano-multiplatform-lib-asmjs": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-browser": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-nodejs": { + "optional": true + } + } + }, + "node_modules/@cardano-sdk/dapp-connector/node_modules/@cardano-sdk/util": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.17.1.tgz", + "integrity": "sha512-TCYe+wRguW1WgRlbWqhGPhcSBkzVzdIcCVgDDN7wiQk2dew0EWVqjsKeqDZdfwzy/s2kr/ZOgXIGywBn/Bzu/Q==", + "license": "Apache-2.0", + "dependencies": { + "bech32": "^2.0.0", + "lodash": "^4.17.21", + "serialize-error": "^8", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@cardano-sdk/input-selection": { + "version": "0.13.34", + "resolved": "https://registry.npmjs.org/@cardano-sdk/input-selection/-/input-selection-0.13.34.tgz", + "integrity": "sha512-/AidYTF9WesLoMc4PHoETxXgrfYEq8GECcikjvLwx1mygmKpok4Lp41Aio7sBasUCLvZ82/yTd3uXIAvec1aCA==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/core": "~0.43.0", + "@cardano-sdk/key-management": "~0.25.1", + "@cardano-sdk/util": "~0.15.5", + "bignumber.js": "^9.1.1", + "lodash": "^4.17.21", + "ts-custom-error": "^3.2.0" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@cardano-sdk/input-selection/node_modules/@cardano-sdk/core": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.43.0.tgz", + "integrity": "sha512-hPnZXjObJub0eXV2dDAG2/gEg/vw092RZ1VGMZfBSqavz18Tg/K6jGQ3cOpWZ9d+MqFzZTCB+s5ctdRkYt3idA==", + "license": "Apache-2.0", + "dependencies": { + "@biglup/is-cid": "^1.0.3", + "@cardano-ogmios/client": "6.9.0", + "@cardano-ogmios/schema": "6.9.0", + "@cardano-sdk/crypto": "~0.1.32", + "@cardano-sdk/util": "~0.15.5", + "@foxglove/crc": "^0.0.3", + "@scure/base": "^1.1.1", + "fraction.js": "4.0.1", + "ip-address": "^9.0.5", + "lodash": "^4.17.21", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "web-encoding": "^1.1.5" + }, + "engines": { + "node": ">=16.20.2" + }, + "peerDependencies": { + "rxjs": "^7.4.0" + }, + "peerDependenciesMeta": { + "rxjs": { + "optional": true + } + } + }, + "node_modules/@cardano-sdk/input-selection/node_modules/@cardano-sdk/crypto": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.1.32.tgz", + "integrity": "sha512-RCKFvkzD32QpKQ0jULADVRNmfBNkCwiZl2nlFbkZ3aCrfIex+6/2CizoagJ161fA7lL5/HGuzWfjOg3GX2ax6w==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/util": "~0.15.5", + "blake2b": "^2.1.4", + "i": "^0.3.7", + "libsodium-wrappers-sumo": "^0.7.5", + "lodash": "^4.17.21", + "npm": "^9.3.0", + "pbkdf2": "^3.1.2", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + }, + "peerDependencies": { + "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" + }, + "peerDependenciesMeta": { + "@dcspark/cardano-multiplatform-lib-asmjs": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-browser": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-nodejs": { + "optional": true + } + } + }, + "node_modules/@cardano-sdk/key-management": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@cardano-sdk/key-management/-/key-management-0.25.1.tgz", + "integrity": "sha512-D99XTIplI2aQnCZtVUKZdmH9wZJQC2WuZL6hTqGZHHFBAeju2zBzGWT21LlcPRlT0/2DP2/OdfIHoHCr2ORp4g==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/core": "~0.43.0", + "@cardano-sdk/crypto": "~0.1.32", + "@cardano-sdk/dapp-connector": "~0.13.1", + "@cardano-sdk/util": "~0.15.5", + "@emurgo/cardano-message-signing-nodejs": "^1.0.1", + "bip39": "^3.0.4", + "chacha": "^2.1.0", + "get-random-values": "^2.0.0", + "lodash": "^4.17.21", + "pbkdf2": "^3.1.2", + "rxjs": "^7.4.0", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@cardano-sdk/key-management/node_modules/@cardano-sdk/core": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.43.0.tgz", + "integrity": "sha512-hPnZXjObJub0eXV2dDAG2/gEg/vw092RZ1VGMZfBSqavz18Tg/K6jGQ3cOpWZ9d+MqFzZTCB+s5ctdRkYt3idA==", + "license": "Apache-2.0", + "dependencies": { + "@biglup/is-cid": "^1.0.3", + "@cardano-ogmios/client": "6.9.0", + "@cardano-ogmios/schema": "6.9.0", + "@cardano-sdk/crypto": "~0.1.32", + "@cardano-sdk/util": "~0.15.5", + "@foxglove/crc": "^0.0.3", + "@scure/base": "^1.1.1", + "fraction.js": "4.0.1", + "ip-address": "^9.0.5", + "lodash": "^4.17.21", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "web-encoding": "^1.1.5" + }, + "engines": { + "node": ">=16.20.2" + }, + "peerDependencies": { + "rxjs": "^7.4.0" + }, + "peerDependenciesMeta": { + "rxjs": { + "optional": true + } + } + }, + "node_modules/@cardano-sdk/key-management/node_modules/@cardano-sdk/crypto": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.1.32.tgz", + "integrity": "sha512-RCKFvkzD32QpKQ0jULADVRNmfBNkCwiZl2nlFbkZ3aCrfIex+6/2CizoagJ161fA7lL5/HGuzWfjOg3GX2ax6w==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/util": "~0.15.5", + "blake2b": "^2.1.4", + "i": "^0.3.7", + "libsodium-wrappers-sumo": "^0.7.5", + "lodash": "^4.17.21", + "npm": "^9.3.0", + "pbkdf2": "^3.1.2", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + }, + "peerDependencies": { + "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" + }, + "peerDependenciesMeta": { + "@dcspark/cardano-multiplatform-lib-asmjs": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-browser": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-nodejs": { + "optional": true + } + } + }, + "node_modules/@cardano-sdk/util": { + "version": "0.15.7", + "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.15.7.tgz", + "integrity": "sha512-L0f3gXFujRwSSpjzq2W/OwW23fg0gw5S+9R+91He3LgmyfjNygd939eFPCLhwOscsHcJ4AN27UJSYnx3JMKZ0w==", + "license": "Apache-2.0", + "dependencies": { + "bech32": "^2.0.0", + "lodash": "^4.17.21", + "serialize-error": "^8", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "type-fest": "^2.19.0" + }, + "engines": { + "node": ">=16.20.2" } }, "node_modules/@cardanosolutions/json-bigint": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@cardanosolutions/json-bigint/-/json-bigint-1.1.0.tgz", - "integrity": "sha512-Pdgz18cSwLKKgheOqW/dqbzNI+CliNT4AdaKaKY/P++J9qLxIB8MITCurlzbaFWV3W4nmK0CRQwI1yvuArmjFg==" + "integrity": "sha512-Pdgz18cSwLKKgheOqW/dqbzNI+CliNT4AdaKaKY/P++J9qLxIB8MITCurlzbaFWV3W4nmK0CRQwI1yvuArmjFg==", + "license": "MIT" }, "node_modules/@chainsafe/is-ip": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.1.0.tgz", - "integrity": "sha512-KIjt+6IfysQ4GCv66xihEitBjvhU/bixbbbFxdJ1sqCp4uJ0wuZiYBPhksZoy4lfaF0k9cwNzY5upEW/VWdw3w==" + "integrity": "sha512-KIjt+6IfysQ4GCv66xihEitBjvhU/bixbbbFxdJ1sqCp4uJ0wuZiYBPhksZoy4lfaF0k9cwNzY5upEW/VWdw3w==", + "license": "MIT" }, "node_modules/@chainsafe/netmask": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@chainsafe/netmask/-/netmask-2.0.0.tgz", "integrity": "sha512-I3Z+6SWUoaljh3TBzCnCxjlUyN8tA+NAk5L6m9IxvCf1BENQTePzPMis97CoN/iMW1St3WN+AWCCRp+TTBRiDg==", + "license": "MIT", "dependencies": { "@chainsafe/is-ip": "^2.0.1" } @@ -932,6 +1327,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-1.4.0.tgz", "integrity": "sha512-vZeOkKaAjyV4+RH3+rJZIfDFJAfr+7fyYr6sLDKbYX3uuTVszhFe9/YKf5DNqrDb5cKdKVlYkGn6DTDqMitAnA==", + "license": "Apache-2.0", "peerDependencies": { "@bufbuild/protobuf": "^1.4.2" } @@ -940,6 +1336,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@connectrpc/connect-node/-/connect-node-1.4.0.tgz", "integrity": "sha512-0ANnrr6SvsjevsWEgdzHy7BaHkluZyS6s4xNoVt7RBHFR5V/kT9lPokoIbYUOU9JHzdRgTaS3x5595mwUsu15g==", + "license": "Apache-2.0", "dependencies": { "undici": "^5.28.3" }, @@ -955,6 +1352,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-1.4.0.tgz", "integrity": "sha512-13aO4psFbbm7rdOFGV0De2Za64DY/acMspgloDlcOKzLPPs0yZkhp1OOzAQeiAIr7BM/VOHIA3p8mF0inxCYTA==", + "license": "Apache-2.0", "peerDependencies": { "@bufbuild/protobuf": "^1.4.2", "@connectrpc/connect": "1.4.0" @@ -964,6 +1362,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/@digitalbazaar/http-client/-/http-client-4.3.0.tgz", "integrity": "sha512-6lMpxpt9BOmqHKGs9Xm6DP4LlZTBFer/ZjHvP3FcW3IaUWYIWC7dw5RFZnvw4fP57kAVcm1dp3IF+Y50qhBvAw==", + "license": "BSD-3-Clause", "dependencies": { "ky": "^1.14.2", "undici": "^6.23.0" @@ -976,13 +1375,15 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -991,6 +1392,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/@dnsquery/dns-packet/-/dns-packet-6.1.1.tgz", "integrity": "sha512-WXTuFvL3G+74SchFAtz3FgIYVOe196ycvGsMgvSH/8Goptb1qpIQtIuM4SOK9G9lhMWYpHxnXyy544ZhluFOew==", + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.4", "utf8-codec": "^1.0.0" @@ -999,46 +1401,18 @@ "node": ">=6" } }, - "node_modules/@emnapi/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", - "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", - "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emurgo/cardano-message-signing-nodejs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emurgo/cardano-message-signing-nodejs/-/cardano-message-signing-nodejs-1.1.0.tgz", - "integrity": "sha512-PQRc8K8wZshEdmQenNUzVtiI8oJNF/1uAnBhidee5C4o1l2mDLOW+ur46HWHIFKQ6x8mSJTllcjMscHgzju0gQ==" + "integrity": "sha512-PQRc8K8wZshEdmQenNUzVtiI8oJNF/1uAnBhidee5C4o1l2mDLOW+ur46HWHIFKQ6x8mSJTllcjMscHgzju0gQ==", + "license": "MIT" }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -1057,17 +1431,19 @@ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/compat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.3.tgz", - "integrity": "sha512-SjIJhGigp8hmd1YGIBwh7Ovri7Kisl42GYFjrOyHhtfYGGoLW6teYi/5p8W50KSsawUPpuLOSmsq1bD0NGQLBw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.1.0.tgz", + "integrity": "sha512-LgaSCymEpw7tF53xvDw9SNsraPb1IBHxpdABIOM0hW8UAlP8znrjYtuxfR58FSJ3L9BhwD+FaPRFQpZq84Nh6g==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.1.1" + "@eslint/core": "^1.2.1" }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -1086,6 +1462,7 @@ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", @@ -1100,6 +1477,7 @@ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0" }, @@ -1112,6 +1490,7 @@ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -1120,10 +1499,11 @@ } }, "node_modules/@eslint/core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", - "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -1136,6 +1516,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", @@ -1159,6 +1540,7 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1171,6 +1553,7 @@ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1180,6 +1563,7 @@ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" @@ -1193,6 +1577,7 @@ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -1201,34 +1586,21 @@ } }, "node_modules/@fabianbormann/cardano-peer-connect": { - "version": "1.2.18", - "resolved": "https://registry.npmjs.org/@fabianbormann/cardano-peer-connect/-/cardano-peer-connect-1.2.18.tgz", - "integrity": "sha512-eyVVMlThkURTsHFJDww253Mk+IzCR2yRYaepyomyqu9HWu2/N8qqC98vNksAbAQ12AzQs7ElwwRgT9HggOuhcw==", + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@fabianbormann/cardano-peer-connect/-/cardano-peer-connect-1.2.19.tgz", + "integrity": "sha512-F+YtJIsvm47G8kl4iFXDXq97KbxMyXfZ7tcOeEEsHH/wA5byYtj88Q91KtShAHOpFu+k0BaQaUmUQbhWhPsCUA==", + "license": "Apache-2.0", "dependencies": { "@basementuniverse/marble-identicons": "^0.1.2", - "@fabianbormann/meerkat": "^1.0.17", + "peerjs": "^1.5.5", "qrcode-svg": "^1.1.0" } }, - "node_modules/@fabianbormann/meerkat": { - "version": "1.0.18", - "resolved": "https://registry.npmjs.org/@fabianbormann/meerkat/-/meerkat-1.0.18.tgz", - "integrity": "sha512-4QuyhlpouIJvcwqlItn91ugl8uC/L1muuN3XFLuO38qMrUucyV0+yykAp1RlzwOlO7YvDYZEaJ8kCa+/MU7UCg==", - "dependencies": { - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@rvagg/ripemd160": "^2.2.4", - "@webpod/ip": "^0.6.1", - "bs58": "^6.0.0", - "bs58check": "^4.0.0", - "tweetnacl": "^1.0.3", - "vm-browserify": "^1.1.2", - "webtorrent": "^2.8.4" - } - }, "node_modules/@floating-ui/core": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.11" } @@ -1237,6 +1609,7 @@ "version": "1.7.6", "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" @@ -1246,6 +1619,7 @@ "version": "2.1.8", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.7.6" }, @@ -1257,17 +1631,20 @@ "node_modules/@floating-ui/utils": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", - "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==" + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" }, "node_modules/@foxglove/crc": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@foxglove/crc/-/crc-0.0.3.tgz", - "integrity": "sha512-DjIZsnL3CyP/yQ/vUYA9cjrD0a/8YXejI5ZmsaOiT16cLfZcTwaCxIN01/ys4jsy+dZCQ/9DnWFn7AEFbiMDaA==" + "integrity": "sha512-DjIZsnL3CyP/yQ/vUYA9cjrD0a/8YXejI5ZmsaOiT16cLfZcTwaCxIN01/ys4jsy+dZCQ/9DnWFn7AEFbiMDaA==", + "license": "MIT" }, "node_modules/@grpc/grpc-js": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", - "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.4.tgz", + "integrity": "sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==", + "license": "Apache-2.0", "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" @@ -1277,13 +1654,14 @@ } }, "node_modules/@grpc/proto-loader": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", - "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.1.tgz", + "integrity": "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==", + "license": "Apache-2.0", "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", - "protobufjs": "^7.5.3", + "protobufjs": "^7.5.5", "yargs": "^17.7.2" }, "bin": { @@ -1297,6 +1675,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/bigint-utils/-/bigint-utils-1.0.0.tgz", "integrity": "sha512-OhZMHcdtH2hHKMlxWFHf71PmKHdoi9ARpjS9mUu0/cd8VWDDjT7VQoQwC5NN/68iyO4O5Dojrvrp9tjG5BDABA==", + "license": "Apache-2.0", "dependencies": { "@harmoniclabs/uint8array-utils": "^1.0.0" } @@ -1304,12 +1683,14 @@ "node_modules/@harmoniclabs/biguint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/biguint/-/biguint-1.0.0.tgz", - "integrity": "sha512-5DyCIBDL4W+7ffR1IJSbGrCG4xEYxAlFH5gCNF42qtyL5ltwZ92Ae1MyXpHM2TUPy7ocSTqlLUsOdy+SvqVVPw==" + "integrity": "sha512-5DyCIBDL4W+7ffR1IJSbGrCG4xEYxAlFH5gCNF42qtyL5ltwZ92Ae1MyXpHM2TUPy7ocSTqlLUsOdy+SvqVVPw==", + "license": "Apache-2.0" }, "node_modules/@harmoniclabs/bitstream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/bitstream/-/bitstream-1.0.0.tgz", "integrity": "sha512-Ed/I46IuCiytE5QiMmmUo9kPJcypM7OuUqoRaAXUALL5C6LKLpT6kYE1qeuhLkx2/WvkHT18jcOX6jhM/nmqoA==", + "license": "MIT", "dependencies": { "@harmoniclabs/uint8array-utils": "^1.0.0" } @@ -1318,6 +1699,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/bytestring/-/bytestring-1.0.0.tgz", "integrity": "sha512-d5m10O0okKc6QNX0pSRriFTkk/kNMnMBGbo5X3kEZwKaXTI4tDVoTZBL7bwbYHwOEdSxWJjVtlO9xtB7ZrYZNg==", + "license": "Apache-2.0", "dependencies": { "@harmoniclabs/uint8array-utils": "^1.0.0" } @@ -1326,6 +1708,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/cbor/-/cbor-1.6.0.tgz", "integrity": "sha512-KI25p8pHI1rmFZC9NYSxATwlCZ+KJdjydpptKebHcw03Iy7M+E8mF+hSnN5dTbS45xw5ZyKUgPLRgLo1sTuIoQ==", + "license": "Apache-2.0", "dependencies": { "@harmoniclabs/bytestring": "^1.0.0", "@harmoniclabs/obj-utils": "^1.0.0", @@ -1336,10 +1719,10 @@ } }, "node_modules/@harmoniclabs/crypto": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.3.0.tgz", - "integrity": "sha512-UvmGQOLFVFhRIDYLpcWbPQLXl9advCt0h02Z/BtBuXtHiy35WRxKQ3njcUKI0v6zGITuvqQhsf6VOPMeekLdeA==", - "peer": true, + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.2.5.tgz", + "integrity": "sha512-t2saWMFWBx8tOHotiYTTfQKhPGpWT4AMLXxq3u0apShVXNV0vgL0gEgSMudBjES/wrKByCqa2xmU70gadz26hA==", + "license": "MIT", "dependencies": { "@harmoniclabs/bitstream": "^1.0.0", "@harmoniclabs/uint8array-utils": "^1.0.3" @@ -1348,17 +1731,20 @@ "node_modules/@harmoniclabs/obj-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/obj-utils/-/obj-utils-1.0.0.tgz", - "integrity": "sha512-EO1bQBZAORrutcP+leP5YNDwNd/9TOE23VEvs3ktniXg6w0knUrLjUIl2Pkcbs/D1VQxqmsNpXho+vaMj00qxA==" + "integrity": "sha512-EO1bQBZAORrutcP+leP5YNDwNd/9TOE23VEvs3ktniXg6w0knUrLjUIl2Pkcbs/D1VQxqmsNpXho+vaMj00qxA==", + "license": "MIT" }, "node_modules/@harmoniclabs/pair": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@harmoniclabs/pair/-/pair-1.0.0.tgz", - "integrity": "sha512-D9OBowsUsy1LctHxWzd9AngTzoo5x3rBiJ0gu579t41Q23pb+VNx1euEfluUEiaYbgljcl1lb/4D1fFTZd1tRQ==" + "integrity": "sha512-D9OBowsUsy1LctHxWzd9AngTzoo5x3rBiJ0gu579t41Q23pb+VNx1euEfluUEiaYbgljcl1lb/4D1fFTZd1tRQ==", + "license": "MIT" }, "node_modules/@harmoniclabs/plutus-data": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@harmoniclabs/plutus-data/-/plutus-data-1.2.6.tgz", - "integrity": "sha512-rF046GZ07XDpjZBNybALKYSycjxCLzXKbhLylu9pRuZiii5fVXReEfgtLB29TsPBvGY6ZBeiyHgJnLgm+huZBw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@harmoniclabs/plutus-data/-/plutus-data-1.2.4.tgz", + "integrity": "sha512-cpr6AnJRultH6PJRDriewHEgNLQs2IGLampZrLjmK5shzTsHICD0yD0Zig9eKdcS7dmY6mlzvSpAJWPGeTxbCA==", + "license": "Apache-2.0", "dependencies": { "@harmoniclabs/biguint": "^1.0.0", "@harmoniclabs/crypto": "^0.2.4", @@ -1369,27 +1755,21 @@ "@harmoniclabs/cbor": "^1.3.0" } }, - "node_modules/@harmoniclabs/plutus-data/node_modules/@harmoniclabs/crypto": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.2.5.tgz", - "integrity": "sha512-t2saWMFWBx8tOHotiYTTfQKhPGpWT4AMLXxq3u0apShVXNV0vgL0gEgSMudBjES/wrKByCqa2xmU70gadz26hA==", - "dependencies": { - "@harmoniclabs/bitstream": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.3" - } - }, "node_modules/@harmoniclabs/uint8array-utils": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@harmoniclabs/uint8array-utils/-/uint8array-utils-1.0.4.tgz", - "integrity": "sha512-Z454prSbX4geXGHyjjcn9vm6u9NsD3VJykv8f8yE1VjIXSPitaLPEnm8u2+B+GMp1chYlLilOq+kW4OvJ6y28A==" + "integrity": "sha512-Z454prSbX4geXGHyjjcn9vm6u9NsD3VJykv8f8yE1VjIXSPitaLPEnm8u2+B+GMp1chYlLilOq+kW4OvJ6y28A==", + "license": "Apache-2.0" }, "node_modules/@harmoniclabs/uplc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@harmoniclabs/uplc/-/uplc-1.4.1.tgz", - "integrity": "sha512-sELKStjxPBPBxBMylU4oBSUe0/8eJe2HqRblNSwrMu8Fso4YpSPDqHZ33iDZ8QAadVUsT5r2EQKX0TLrj7qXvQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@harmoniclabs/uplc/-/uplc-1.2.4.tgz", + "integrity": "sha512-Px6utj94cO/hQd9NJgVQI8zycsbgh3rAzDeLdZ1m52bo++EuU1GL+arWX3JYso3/3uNrnUFuizjrAIISwQe3Fg==", + "license": "Apache-2.0", "dependencies": { "@harmoniclabs/bigint-utils": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.3" + "@harmoniclabs/bitstream": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/HarmonicLabs" @@ -1397,7 +1777,7 @@ "peerDependencies": { "@harmoniclabs/bytestring": "^1.0.0", "@harmoniclabs/cbor": "^1.3.0", - "@harmoniclabs/crypto": "^0.3.0-dev0", + "@harmoniclabs/crypto": "^0.2.4", "@harmoniclabs/pair": "^1.0.0", "@harmoniclabs/plutus-data": "^1.2.4" } @@ -1406,37 +1786,55 @@ "version": "3.10.0", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz", "integrity": "sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==", + "license": "MIT", "peerDependencies": { "react-hook-form": "^7.0.0" } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -1450,6 +1848,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -1462,6 +1861,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=18" @@ -1474,6 +1874,7 @@ "cpu": [ "arm64" ], + "license": "Apache-2.0", "optional": true, "os": [ "darwin" @@ -1488,27 +1889,6 @@ "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, "node_modules/@img/sharp-libvips-darwin-arm64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", @@ -1516,6 +1896,7 @@ "cpu": [ "arm64" ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "darwin" @@ -1524,680 +1905,328 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" } }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@istanbuljs/load-nyc-config/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, "funding": { - "url": "https://opencollective.com/libvips" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" + "node": ">=8" } }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" + "node": ">=8" } }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@jest/console": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.4.1.tgz", + "integrity": "sha512-v3bhyxUh9Hgmo5p6hAOXe14/R3ZxZDOsvHleh4B07z3m/x4/ngPUXEm9XwK4sF4u+f+P2ORb0Ge+MgpaqRMVDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", + "slash": "^3.0.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/@jest/core": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.4.2.tgz", + "integrity": "sha512-TZJA6cPJUFxoWhxaLo8t0VX/MZX2wPWr0uIDvLSHIvN4gu9h02vSzqI2kBADG1ExqQlC+cY09xKMSreivvrChQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.4.1", + "@jest/pattern": "30.4.0", + "@jest/reporters": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.4.1", + "jest-config": "30.4.2", + "jest-haste-map": "30.4.1", + "jest-message-util": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-resolve-dependencies": "30.4.2", + "jest-runner": "30.4.2", + "jest-runtime": "30.4.2", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", + "jest-watcher": "30.4.1", + "pretty-format": "30.4.1", + "slash": "^3.0.0" + }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://opencollective.com/libvips" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/@jest/diff-sequences": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", + "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "dev": true, + "license": "MIT", "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@jest/environment": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.4.1.tgz", + "integrity": "sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "jest-mock": "30.4.1" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@jest/expect": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.4.1.tgz", + "integrity": "sha512-ginrj6TMgh2GshLUGCjO94Ptx9HhdZA/I6A9iUfyeLKFtdAjnKzHDgzgP9HYQgbxM1lbXScQ2eUBz2lGeVDPWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "30.4.1", + "jest-snapshot": "30.4.1" }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@jest/expect-utils": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", + "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", - "cpu": [ - "wasm32" - ], - "optional": true, + "node_modules/@jest/fake-timers": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.4.1.tgz", + "integrity": "sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@emnapi/runtime": "^1.7.0" + "@jest/types": "30.4.1", + "@sinonjs/fake-timers": "^15.4.0", + "@types/node": "*", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-util": "30.4.1" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], + "node_modules/@jest/globals": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.4.1.tgz", + "integrity": "sha512-ZbuY4cmXC8DkxYjfvT2DbcHWL2T6vmsMhXCDcmTB2T0y0gaezBI77ufq5ZAIdcRkYZ7NEQEDg1xFeKbxUJ5v5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.1", + "@jest/expect": "30.4.1", + "@jest/types": "30.4.1", + "jest-mock": "30.4.1" + }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", + "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.4.0" }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@isaacs/cliui": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", - "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", - "engines": { - "node": ">=18" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.3.0.tgz", - "integrity": "sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==", - "dev": true, - "dependencies": { - "@jest/types": "30.3.0", - "@types/node": "*", - "chalk": "^4.1.2", - "jest-message-util": "30.3.0", - "jest-util": "30.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/core": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.3.0.tgz", - "integrity": "sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==", - "dev": true, - "dependencies": { - "@jest/console": "30.3.0", - "@jest/pattern": "30.0.1", - "@jest/reporters": "30.3.0", - "@jest/test-result": "30.3.0", - "@jest/transform": "30.3.0", - "@jest/types": "30.3.0", - "@types/node": "*", - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "exit-x": "^0.2.2", - "graceful-fs": "^4.2.11", - "jest-changed-files": "30.3.0", - "jest-config": "30.3.0", - "jest-haste-map": "30.3.0", - "jest-message-util": "30.3.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.3.0", - "jest-resolve-dependencies": "30.3.0", - "jest-runner": "30.3.0", - "jest-runtime": "30.3.0", - "jest-snapshot": "30.3.0", - "jest-util": "30.3.0", - "jest-validate": "30.3.0", - "jest-watcher": "30.3.0", - "pretty-format": "30.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/diff-sequences": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz", - "integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==", - "dev": true, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/environment": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.3.0.tgz", - "integrity": "sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "30.3.0", - "@jest/types": "30.3.0", - "@types/node": "*", - "jest-mock": "30.3.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.3.0.tgz", - "integrity": "sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==", - "dev": true, - "dependencies": { - "expect": "30.3.0", - "jest-snapshot": "30.3.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz", - "integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==", - "dev": true, - "dependencies": { - "@jest/get-type": "30.1.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.3.0.tgz", - "integrity": "sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==", - "dev": true, - "dependencies": { - "@jest/types": "30.3.0", - "@sinonjs/fake-timers": "^15.0.0", - "@types/node": "*", - "jest-message-util": "30.3.0", - "jest-mock": "30.3.0", - "jest-util": "30.3.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.3.0.tgz", - "integrity": "sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==", - "dev": true, - "dependencies": { - "@jest/environment": "30.3.0", - "@jest/expect": "30.3.0", - "@jest/types": "30.3.0", - "jest-mock": "30.3.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/pattern": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", - "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-regex-util": "30.0.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/reporters": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.3.0.tgz", - "integrity": "sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.4.1.tgz", + "integrity": "sha512-/SnkPCzEQpUaBH81kjdEdDdo2WZl5hxw+BmLDGWjRkm8o7XlhjwsU36cqwe5PGBE5WYpBvDzRSdXx9rbGuJtNA==", "dev": true, + "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.3.0", - "@jest/test-result": "30.3.0", - "@jest/transform": "30.3.0", - "@jest/types": "30.3.0", + "@jest/console": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "@jridgewell/trace-mapping": "^0.3.25", "@types/node": "*", "chalk": "^4.1.2", @@ -2210,9 +2239,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "30.3.0", - "jest-util": "30.3.0", - "jest-worker": "30.3.0", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", + "jest-worker": "30.4.1", "slash": "^3.0.0", "string-length": "^4.0.2", "v8-to-istanbul": "^9.0.1" @@ -2230,10 +2259,11 @@ } }, "node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", + "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.34.0" }, @@ -2242,12 +2272,13 @@ } }, "node_modules/@jest/snapshot-utils": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.3.0.tgz", - "integrity": "sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.4.1.tgz", + "integrity": "sha512-ObY4ljvQ95mt6iwKtVLetR/4yXiAgl3H4nJxhztr0MTjrN97TwDYrnCp/kF60Ec9HdhkWTHSu+Hg05aXfngpOA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "30.3.0", + "@jest/types": "30.4.1", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "natural-compare": "^1.4.0" @@ -2261,6 +2292,7 @@ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "callsites": "^3.1.0", @@ -2271,13 +2303,14 @@ } }, "node_modules/@jest/test-result": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.3.0.tgz", - "integrity": "sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.4.1.tgz", + "integrity": "sha512-/ZG7pgEiOmmWkN9TplKbOu4id2N5lh7FHwRwlkgBVAzGdRH+OkkQ8wX/kIxg4zmd3ZQvAL1RwL2yWsvNYYECTw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "30.3.0", - "@jest/types": "30.3.0", + "@jest/console": "30.4.1", + "@jest/types": "30.4.1", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" }, @@ -2286,14 +2319,15 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.3.0.tgz", - "integrity": "sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.4.1.tgz", + "integrity": "sha512-PeYE+4td5rKjoRPxztObrXU+H8hsjZfxKMXOcmrr34JerSyB/ROOxbbicz8B7A5j9R9VayDnVPvBmedqCsFCdw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/test-result": "30.3.0", + "@jest/test-result": "30.4.1", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.3.0", + "jest-haste-map": "30.4.1", "slash": "^3.0.0" }, "engines": { @@ -2301,22 +2335,23 @@ } }, "node_modules/@jest/transform": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.3.0.tgz", - "integrity": "sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.4.1.tgz", + "integrity": "sha512-Wz0LyktlTvRefoymh+n64hQ84KNXsRGcwdoZ8CSa0Ea+fgYcHZlnk+hDP7v2MS7il2bQ5uTEIxf4/NNfhMN4KQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/types": "30.3.0", + "@jest/types": "30.4.1", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.3.0", - "jest-regex-util": "30.0.1", - "jest-util": "30.3.0", + "jest-haste-map": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-util": "30.4.1", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" @@ -2326,13 +2361,14 @@ } }, "node_modules/@jest/types": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", - "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", + "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", + "@jest/pattern": "30.4.0", + "@jest/schemas": "30.4.1", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", @@ -2347,6 +2383,7 @@ "version": "0.0.11", "resolved": "https://registry.npmjs.org/@jinglescode/nostr-chat-plugin/-/nostr-chat-plugin-0.0.11.tgz", "integrity": "sha512-teAjUTPqbfI353M+Ip/QcT7LnA4VpUh4jHbbo0xryhajAXlNIYpUDs5bbTa0M4IroU/aMA65Ba8iaqhIta0D0g==", + "license": "Apache-2.0", "dependencies": { "nostr-tools": "^2.8.0" }, @@ -2358,6 +2395,7 @@ "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" @@ -2367,6 +2405,8 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -2376,6 +2416,7 @@ "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" } @@ -2383,12 +2424,14 @@ "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==" + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "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" @@ -2398,49 +2441,89 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/js-sdsl" } }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" - }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" }, "node_modules/@libp2p/interface": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-3.1.1.tgz", - "integrity": "sha512-pQuReZeZUSqk27UXwXXdAVlxrgs08GrcPsd92Qv27IFBPICG8da3FmHg1bclUpMW/6GE6o4qDCVqR4cBMRVKyA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-3.2.2.tgz", + "integrity": "sha512-IU78g6uF8Ls0//4v9VE1rL5Jvy+i6I8LI/DssojFICbaDJSkL59Sn5XRfHrY5OCxTnUnUxnWK7pHz/3+UZcRNQ==", + "license": "Apache-2.0 OR MIT", "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^13.0.1", "main-event": "^1.0.1", "multiformats": "^13.4.0", - "progress-events": "^1.0.1", + "progress-events": "^1.1.0", "uint8arraylist": "^2.4.8" } }, "node_modules/@libp2p/interface/node_modules/@multiformats/multiaddr": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-13.0.1.tgz", - "integrity": "sha512-XToN915cnfr6Lr9EdGWakGJbPT0ghpg/850HvdC+zFX8XvpLZElwa8synCiwa8TuvKNnny6m8j8NVBNCxhIO3g==", + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-13.0.3.tgz", + "integrity": "sha512-mEqqJ4r3a/uuFMTpRkU316wGNIDQNhuVWpm+ebKTQeYsfv9jXbPONWM6VVnj3KGUrwfsX7GZOyp4TFqEA2SPCw==", + "license": "Apache-2.0 OR MIT", "dependencies": { "@chainsafe/is-ip": "^2.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" + "multiformats": "^14.0.0", + "uint8-varint": "^3.0.0", + "uint8arrays": "^6.1.1" + } + }, + "node_modules/@libp2p/interface/node_modules/@multiformats/multiaddr/node_modules/multiformats": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-14.0.0.tgz", + "integrity": "sha512-iWK1RrAS58p2NDfeZFuSUSv3ZPewTIhsGbh/5NgeGGJwJmRljLxGtjRR3nkn+loG3zl+IrfR/W1590QnrSK+Gg==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/@libp2p/interface/node_modules/uint8-varint": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-3.0.0.tgz", + "integrity": "sha512-S4DdpXBaLwKcFo7f0bWzWfHjbZ/i3QhM842qn+ZvHjxqFCfUcEB9SQNcmI69S+zMlcmIcKxsk9Iyw77S2Kxv6Q==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8arraylist": "^3.0.1", + "uint8arrays": "^6.1.0" + } + }, + "node_modules/@libp2p/interface/node_modules/uint8-varint/node_modules/uint8arraylist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-3.0.2.tgz", + "integrity": "sha512-LDVoq9BQaGJzGDUovEnoX6rpKCvnY/Jbtws4ikwnBzjRbq5qBAFpBZevUEbSmMM87aO0Sp+wOZy2ZXf5yODmXQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8arrays": "^6.0.0" + } + }, + "node_modules/@libp2p/interface/node_modules/uint8arrays": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-6.1.1.tgz", + "integrity": "sha512-iz7JN0XCSZYA111lhFG2Ui9EhFvTNekqSRHw3lvMHq+dzwWy1OQftxFQREEh4rffU0oSoXdQHsk2TiHKVm4fsA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "multiformats": "^14.0.0" } }, + "node_modules/@libp2p/interface/node_modules/uint8arrays/node_modules/multiformats": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-14.0.0.tgz", + "integrity": "sha512-iWK1RrAS58p2NDfeZFuSUSv3ZPewTIhsGbh/5NgeGGJwJmRljLxGtjRR3nkn+loG3zl+IrfR/W1590QnrSK+Gg==", + "license": "Apache-2.0 OR MIT" + }, "node_modules/@lightsparkdev/core": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@lightsparkdev/core/-/core-1.5.1.tgz", - "integrity": "sha512-IHgxWxAfOvHh6sdv3YqW9xk16H/sfTfA0nLC6FfU8TWHWb7ZU3/UO6QjR0a5a2qR/Fv5ZlS6DSzM7ST7Qx6N4Q==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@lightsparkdev/core/-/core-1.5.2.tgz", + "integrity": "sha512-7EiV/Ld+IqAQJYvSLN2gS6E/UrcCCQ/H4voUz+nAPUDSk8U1P06afTKALh1FeizAXIzqxt1jFQWmQlXPSXmxIA==", + "license": "Apache-2.0", "dependencies": { "@noble/curves": "^1.9.7", "dayjs": "^1.11.7", @@ -2453,24 +2536,11 @@ "node": ">=18" } }, - "node_modules/@lightsparkdev/core/node_modules/@noble/curves": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", - "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@lightsparkdev/core/node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -2491,25 +2561,14 @@ "version": "0.10.17", "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", - "dev": true - }, - "node_modules/@meshsdk/bitcoin": { - "version": "1.9.0-beta.89", - "resolved": "https://registry.npmjs.org/@meshsdk/bitcoin/-/bitcoin-1.9.0-beta.89.tgz", - "integrity": "sha512-2ZREpEwqzMt63bRMi2vf+rbts+xzoWSMdSLhqA7XgGHkfZKr8eonaJW37NSsMFVtafwgR1UppIF7SuslrSlnww==", - "dependencies": { - "@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3", - "bip174": "^3.0.0", - "bip32": "^4.0.0", - "bip39": "^3.1.0", - "bitcoinjs-lib": "^6.1.7", - "ecpair": "^2.0.0" - } + "dev": true, + "license": "Apache-2.0" }, "node_modules/@meshsdk/common": { "version": "1.9.0-beta.102", "resolved": "https://registry.npmjs.org/@meshsdk/common/-/common-1.9.0-beta.102.tgz", "integrity": "sha512-21qkpcGEe3EYpsmCF8uRUj3vM31MeO1y9vWMllKOFPCOYcOIbTfP+EE/HUSbAi7TAFKNd075BqPVgnvb6LA+hA==", + "license": "Apache-2.0", "dependencies": { "bech32": "^2.0.0", "bip39": "3.1.0", @@ -2521,6 +2580,7 @@ "version": "1.9.0-beta.102", "resolved": "https://registry.npmjs.org/@meshsdk/core/-/core-1.9.0-beta.102.tgz", "integrity": "sha512-ZpF5ZnmLoNZ+/8jcgXH3AK3VPacah9Gf31GCJE4udS3Dz16Stbg9+fSIFWkgmZTu/U8cRbr6PcYtNE+mVvq1jg==", + "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "1.9.0-beta.102", "@meshsdk/core-cst": "1.9.0-beta.102", @@ -2533,6 +2593,7 @@ "version": "1.9.0-beta.102", "resolved": "https://registry.npmjs.org/@meshsdk/core-csl/-/core-csl-1.9.0-beta.102.tgz", "integrity": "sha512-ZPRisFi/if9sEKfcWYtiUSasXP1zS+Pxrnm1mOIJSgBHk6zqh+6Na6zUIx6RmPNck2xSSS2sd5tuNbr9z3/L8g==", + "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "1.9.0-beta.102", "@sidan-lab/whisky-js-browser": "^1.0.11", @@ -2547,6 +2608,7 @@ "version": "1.9.0-beta.102", "resolved": "https://registry.npmjs.org/@meshsdk/core-cst/-/core-cst-1.9.0-beta.102.tgz", "integrity": "sha512-PEIfq1c+Rls84giMpCyaGpnWRnjHEKrbDjCBOsL6meVXAARbX85zwSgpGryQL36dU/W6xkc7idNHcKyLW+HvLg==", + "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "0.46.12", "@cardano-sdk/crypto": "0.4.5", @@ -2566,87 +2628,17 @@ "scalus": "^0.14.2" } }, - "node_modules/@meshsdk/provider": { - "version": "1.9.0-beta.100", - "resolved": "https://registry.npmjs.org/@meshsdk/provider/-/provider-1.9.0-beta.100.tgz", - "integrity": "sha512-930tN8ZxK/pOXCSlvLxWIUbP5KyEO7EloacuPjSNnRP9rVJlt/AoiW30CSV8l9ZegA9VH30pev9Svv0Qj/kjRQ==", - "dependencies": { - "@meshsdk/common": "1.9.0-beta.100", - "@meshsdk/core-cst": "1.9.0-beta.100", - "@utxorpc/sdk": "^0.6.7", - "@utxorpc/spec": "^0.16.0", - "axios": "^1.7.2", - "cbor": "^10.0.9" - } - }, - "node_modules/@meshsdk/provider/node_modules/@meshsdk/common": { - "version": "1.9.0-beta.100", - "resolved": "https://registry.npmjs.org/@meshsdk/common/-/common-1.9.0-beta.100.tgz", - "integrity": "sha512-H3ktKR9eheRKZupg7DLdUr8A9dsefJbu7Wc+I1suwrv+oAZWiJ2wCuF3bX2QQo3LyWrSkVCE7WEiKFfQmukIww==", - "dependencies": { - "bech32": "^2.0.0", - "bip39": "3.1.0", - "blake2b": "^2.1.4", - "blakejs": "^1.2.1" - } - }, - "node_modules/@meshsdk/provider/node_modules/@meshsdk/core-cst": { - "version": "1.9.0-beta.100", - "resolved": "https://registry.npmjs.org/@meshsdk/core-cst/-/core-cst-1.9.0-beta.100.tgz", - "integrity": "sha512-gXC7c81puzv12C3xJ6vhH/KIEc/P6ScuXsgmLlqFMpDv0SuoMg+42HgdyWi0WrccVwi8cdepsn5YhtCaYVn0nw==", - "dependencies": { - "@cardano-sdk/core": "0.46.12", - "@cardano-sdk/crypto": "0.4.5", - "@cardano-sdk/input-selection": "0.14.28", - "@cardano-sdk/util": "0.17.1", - "@harmoniclabs/cbor": "1.6.0", - "@harmoniclabs/pair": "^1.0.0", - "@harmoniclabs/plutus-data": "1.2.6", - "@harmoniclabs/uplc": "1.4.1", - "@meshsdk/common": "1.9.0-beta.100", - "@types/base32-encoding": "^1.0.2", - "base32-encoding": "^1.0.0", - "bech32": "^2.0.0", - "blakejs": "^1.2.1", - "bn.js": "^5.2.0", - "hash.js": "^1.1.7", - "scalus": "^0.14.2" - } - }, - "node_modules/@meshsdk/react": { - "version": "1.9.0-beta-40", - "resolved": "https://registry.npmjs.org/@meshsdk/react/-/react-1.9.0-beta-40.tgz", - "integrity": "sha512-RsqI/dBpYDEg2uz3mYCuEgNJIAOm+1Bn/nJM+zlj66ujL349cLpmrTDF/ApGF9HHqjKF7NqesVimGqt6BNILQg==", - "dependencies": { - "@fabianbormann/cardano-peer-connect": "^1.2.18", - "@meshsdk/common": "1.9.0-beta-40", - "@meshsdk/transaction": "1.9.0-beta-40", - "@meshsdk/wallet": "1.9.0-beta-40", - "@meshsdk/web3-sdk": "0.0.26", - "@radix-ui/react-dialog": "^1.1.2", - "@radix-ui/react-dropdown-menu": "^2.1.2", - "@radix-ui/react-icons": "^1.3.2", - "@radix-ui/react-label": "^2.1.1", - "@radix-ui/react-tooltip": "^1.1.4", - "class-variance-authority": "^0.7.1", - "tailwind-merge": "^2.6.0", - "tailwindcss-animate": "^1.0.7" - }, - "peerDependencies": { - "react": ">=16.0.0 <20.0.0 || >=16.0.0-rc <20.0.0-rc || >=19.0.0-rc", - "react-dom": ">=16.0.0 <20.0.0 || >=16.0.0-rc <20.0.0-rc || >=19.0.0-rc" - } - }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/core": { - "version": "0.45.10", - "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.45.10.tgz", - "integrity": "sha512-PU/onQuPgsy0CtFKDlHcozGHMTHrigWztTmKq54tL0TdWRcClXbMh5Q63ALcP388ZouPC1nKomOAooVgyrrEfw==", + "node_modules/@meshsdk/core-cst/node_modules/@cardano-sdk/core": { + "version": "0.46.12", + "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.46.12.tgz", + "integrity": "sha512-yUA/xBUQMiMqIWiZPvIhM911pL3jNKg4PkZQ8qP9R7yU3NQ5x4RQkZ+zFDlVLxUt+gJiwIW2es0iPd8ObIKCxA==", + "license": "Apache-2.0", "dependencies": { "@biglup/is-cid": "^1.0.3", "@cardano-ogmios/client": "6.9.0", "@cardano-ogmios/schema": "6.9.0", - "@cardano-sdk/crypto": "~0.2.3", - "@cardano-sdk/util": "~0.16.0", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/util": "~0.17.1", "@foxglove/crc": "^0.0.3", "@scure/base": "^1.1.1", "fraction.js": "4.0.1", @@ -2668,34 +2660,18 @@ } } }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/core/node_modules/@cardano-sdk/util": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.16.0.tgz", - "integrity": "sha512-f0tfX8oiauqAFCyyc/o2Ouezyk83QD4zqLl4DUjZNyCtITL8gBHh25Bkw7RUCGEZ+hf6Qms1n0ui0j3wVY7zRg==", - "dependencies": { - "bech32": "^2.0.0", - "lodash": "^4.17.21", - "serialize-error": "^8", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "type-fest": "^2.19.0" - }, - "engines": { - "node": ">=16.20.2" - } - }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/crypto": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.2.3.tgz", - "integrity": "sha512-jTl8rbocV1XO5DBR6+lGY6Owc/bP+wBg5eO3PttTeKhx/J7o99pyuTa5H36a/XTJwqDwKIXV922QxZR+rfjVbA==", + "node_modules/@meshsdk/core-cst/node_modules/@cardano-sdk/crypto": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.4.5.tgz", + "integrity": "sha512-ymliqxdmen5dGVaiMVQ0VnhrwaYUjbPD3sHoMj8NI6MTuxrREp3pLJASREtWhwmv9k+QzDT6CoyuIXnlEQiWZQ==", + "license": "Apache-2.0", "dependencies": { - "@cardano-sdk/util": "~0.16.0", + "@cardano-sdk/util": "~0.17.1", "blake2b": "^2.1.4", "i": "^0.3.7", - "libsodium-wrappers-sumo": "^0.7.5", + "libsodium-wrappers-sumo": "0.7.10", "lodash": "^4.17.21", - "npm": "^9.3.0", - "pbkdf2": "^3.1.2", + "pbkdf2": "^3.1.3", "ts-custom-error": "^3.2.0", "ts-log": "^2.2.4" }, @@ -2719,30 +2695,15 @@ } } }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/crypto/node_modules/@cardano-sdk/util": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.16.0.tgz", - "integrity": "sha512-f0tfX8oiauqAFCyyc/o2Ouezyk83QD4zqLl4DUjZNyCtITL8gBHh25Bkw7RUCGEZ+hf6Qms1n0ui0j3wVY7zRg==", - "dependencies": { - "bech32": "^2.0.0", - "lodash": "^4.17.21", - "serialize-error": "^8", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "type-fest": "^2.19.0" - }, - "engines": { - "node": ">=16.20.2" - } - }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/input-selection": { - "version": "0.13.34", - "resolved": "https://registry.npmjs.org/@cardano-sdk/input-selection/-/input-selection-0.13.34.tgz", - "integrity": "sha512-/AidYTF9WesLoMc4PHoETxXgrfYEq8GECcikjvLwx1mygmKpok4Lp41Aio7sBasUCLvZ82/yTd3uXIAvec1aCA==", + "node_modules/@meshsdk/core-cst/node_modules/@cardano-sdk/input-selection": { + "version": "0.14.28", + "resolved": "https://registry.npmjs.org/@cardano-sdk/input-selection/-/input-selection-0.14.28.tgz", + "integrity": "sha512-pbysJUaIbbpesbv/f0XfFPKBb+bLjCmPcMfNJzpePSZBvr8bUcFpnfKtq28KthVdpe2mgL3k9ebTTcBSk7aERw==", + "license": "Apache-2.0", "dependencies": { - "@cardano-sdk/core": "~0.43.0", - "@cardano-sdk/key-management": "~0.25.1", - "@cardano-sdk/util": "~0.15.5", + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/key-management": "~0.29.12", + "@cardano-sdk/util": "~0.17.1", "bignumber.js": "^9.1.1", "lodash": "^4.17.21", "ts-custom-error": "^3.2.0" @@ -2751,105 +2712,127 @@ "node": ">=16.20.2" } }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/input-selection/node_modules/@cardano-sdk/core": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.43.0.tgz", - "integrity": "sha512-hPnZXjObJub0eXV2dDAG2/gEg/vw092RZ1VGMZfBSqavz18Tg/K6jGQ3cOpWZ9d+MqFzZTCB+s5ctdRkYt3idA==", + "node_modules/@meshsdk/core-cst/node_modules/@cardano-sdk/key-management": { + "version": "0.29.13", + "resolved": "https://registry.npmjs.org/@cardano-sdk/key-management/-/key-management-0.29.13.tgz", + "integrity": "sha512-yvdWrZcvrH9s5mBwnKpdT6xGF7vMZ9DSrrEENnhA9NG9jXDLpuYX/KI2TGczUdRPezBFm2y9kO7oHNf8GNYvAA==", + "license": "Apache-2.0", "dependencies": { - "@biglup/is-cid": "^1.0.3", - "@cardano-ogmios/client": "6.9.0", - "@cardano-ogmios/schema": "6.9.0", - "@cardano-sdk/crypto": "~0.1.32", - "@cardano-sdk/util": "~0.15.5", - "@foxglove/crc": "^0.0.3", - "@scure/base": "^1.1.1", - "fraction.js": "4.0.1", - "ip-address": "^9.0.5", + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/dapp-connector": "~0.13.26", + "@cardano-sdk/util": "~0.17.1", + "@emurgo/cardano-message-signing-nodejs": "^1.0.1", + "bip39": "^3.0.4", + "chacha": "^2.1.0", + "get-random-values": "^2.0.0", "lodash": "^4.17.21", + "pbkdf2": "^3.1.3", + "rxjs": "^7.4.0", "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "web-encoding": "^1.1.5" + "ts-log": "^2.2.4" }, "engines": { "node": ">=16.20.2" - }, - "peerDependencies": { - "rxjs": "^7.4.0" - }, - "peerDependenciesMeta": { - "rxjs": { - "optional": true - } } }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/input-selection/node_modules/@cardano-sdk/crypto": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.1.32.tgz", - "integrity": "sha512-RCKFvkzD32QpKQ0jULADVRNmfBNkCwiZl2nlFbkZ3aCrfIex+6/2CizoagJ161fA7lL5/HGuzWfjOg3GX2ax6w==", + "node_modules/@meshsdk/core-cst/node_modules/@cardano-sdk/util": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.17.1.tgz", + "integrity": "sha512-TCYe+wRguW1WgRlbWqhGPhcSBkzVzdIcCVgDDN7wiQk2dew0EWVqjsKeqDZdfwzy/s2kr/ZOgXIGywBn/Bzu/Q==", + "license": "Apache-2.0", "dependencies": { - "@cardano-sdk/util": "~0.15.5", - "blake2b": "^2.1.4", - "i": "^0.3.7", - "libsodium-wrappers-sumo": "^0.7.5", + "bech32": "^2.0.0", "lodash": "^4.17.21", - "npm": "^9.3.0", - "pbkdf2": "^3.1.2", + "serialize-error": "^8", "ts-custom-error": "^3.2.0", "ts-log": "^2.2.4" }, "engines": { "node": ">=16.20.2" - }, - "peerDependencies": { - "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", - "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", - "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" - }, - "peerDependenciesMeta": { - "@dcspark/cardano-multiplatform-lib-asmjs": { - "optional": true - }, - "@dcspark/cardano-multiplatform-lib-browser": { - "optional": true - }, - "@dcspark/cardano-multiplatform-lib-nodejs": { - "optional": true - } } }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/key-management": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@cardano-sdk/key-management/-/key-management-0.25.1.tgz", - "integrity": "sha512-D99XTIplI2aQnCZtVUKZdmH9wZJQC2WuZL6hTqGZHHFBAeju2zBzGWT21LlcPRlT0/2DP2/OdfIHoHCr2ORp4g==", + "node_modules/@meshsdk/core-cst/node_modules/@harmoniclabs/crypto": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.3.0.tgz", + "integrity": "sha512-UvmGQOLFVFhRIDYLpcWbPQLXl9advCt0h02Z/BtBuXtHiy35WRxKQ3njcUKI0v6zGITuvqQhsf6VOPMeekLdeA==", + "license": "MIT", + "peer": true, "dependencies": { - "@cardano-sdk/core": "~0.43.0", - "@cardano-sdk/crypto": "~0.1.32", - "@cardano-sdk/dapp-connector": "~0.13.1", - "@cardano-sdk/util": "~0.15.5", - "@emurgo/cardano-message-signing-nodejs": "^1.0.1", - "bip39": "^3.0.4", - "chacha": "^2.1.0", - "get-random-values": "^2.0.0", - "lodash": "^4.17.21", - "pbkdf2": "^3.1.2", - "rxjs": "^7.4.0", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4" + "@harmoniclabs/bitstream": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" + } + }, + "node_modules/@meshsdk/core-cst/node_modules/@harmoniclabs/plutus-data": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@harmoniclabs/plutus-data/-/plutus-data-1.2.6.tgz", + "integrity": "sha512-rF046GZ07XDpjZBNybALKYSycjxCLzXKbhLylu9pRuZiii5fVXReEfgtLB29TsPBvGY6ZBeiyHgJnLgm+huZBw==", + "license": "Apache-2.0", + "dependencies": { + "@harmoniclabs/biguint": "^1.0.0", + "@harmoniclabs/crypto": "^0.2.4", + "@harmoniclabs/uint8array-utils": "^1.0.0" }, - "engines": { - "node": ">=16.20.2" + "peerDependencies": { + "@harmoniclabs/bytestring": "^1.0.0", + "@harmoniclabs/cbor": "^1.3.0" } }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/key-management/node_modules/@cardano-sdk/core": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.43.0.tgz", - "integrity": "sha512-hPnZXjObJub0eXV2dDAG2/gEg/vw092RZ1VGMZfBSqavz18Tg/K6jGQ3cOpWZ9d+MqFzZTCB+s5ctdRkYt3idA==", + "node_modules/@meshsdk/core-cst/node_modules/@harmoniclabs/plutus-data/node_modules/@harmoniclabs/crypto": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.2.5.tgz", + "integrity": "sha512-t2saWMFWBx8tOHotiYTTfQKhPGpWT4AMLXxq3u0apShVXNV0vgL0gEgSMudBjES/wrKByCqa2xmU70gadz26hA==", + "license": "MIT", + "dependencies": { + "@harmoniclabs/bitstream": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" + } + }, + "node_modules/@meshsdk/core-cst/node_modules/@harmoniclabs/uplc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@harmoniclabs/uplc/-/uplc-1.4.1.tgz", + "integrity": "sha512-sELKStjxPBPBxBMylU4oBSUe0/8eJe2HqRblNSwrMu8Fso4YpSPDqHZ33iDZ8QAadVUsT5r2EQKX0TLrj7qXvQ==", + "license": "Apache-2.0", + "dependencies": { + "@harmoniclabs/bigint-utils": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/HarmonicLabs" + }, + "peerDependencies": { + "@harmoniclabs/bytestring": "^1.0.0", + "@harmoniclabs/cbor": "^1.3.0", + "@harmoniclabs/crypto": "^0.3.0-dev0", + "@harmoniclabs/pair": "^1.0.0", + "@harmoniclabs/plutus-data": "^1.2.4" + } + }, + "node_modules/@meshsdk/provider": { + "version": "1.9.0-beta.100", + "resolved": "https://registry.npmjs.org/@meshsdk/provider/-/provider-1.9.0-beta.100.tgz", + "integrity": "sha512-930tN8ZxK/pOXCSlvLxWIUbP5KyEO7EloacuPjSNnRP9rVJlt/AoiW30CSV8l9ZegA9VH30pev9Svv0Qj/kjRQ==", + "license": "Apache-2.0", + "dependencies": { + "@meshsdk/common": "1.9.0-beta.100", + "@meshsdk/core-cst": "1.9.0-beta.100", + "@utxorpc/sdk": "^0.6.7", + "@utxorpc/spec": "^0.16.0", + "axios": "^1.7.2", + "cbor": "^10.0.9" + } + }, + "node_modules/@meshsdk/provider/node_modules/@cardano-sdk/core": { + "version": "0.46.12", + "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.46.12.tgz", + "integrity": "sha512-yUA/xBUQMiMqIWiZPvIhM911pL3jNKg4PkZQ8qP9R7yU3NQ5x4RQkZ+zFDlVLxUt+gJiwIW2es0iPd8ObIKCxA==", + "license": "Apache-2.0", "dependencies": { "@biglup/is-cid": "^1.0.3", "@cardano-ogmios/client": "6.9.0", "@cardano-ogmios/schema": "6.9.0", - "@cardano-sdk/crypto": "~0.1.32", - "@cardano-sdk/util": "~0.15.5", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/util": "~0.17.1", "@foxglove/crc": "^0.0.3", "@scure/base": "^1.1.1", "fraction.js": "4.0.1", @@ -2871,18 +2854,18 @@ } } }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/key-management/node_modules/@cardano-sdk/crypto": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.1.32.tgz", - "integrity": "sha512-RCKFvkzD32QpKQ0jULADVRNmfBNkCwiZl2nlFbkZ3aCrfIex+6/2CizoagJ161fA7lL5/HGuzWfjOg3GX2ax6w==", + "node_modules/@meshsdk/provider/node_modules/@cardano-sdk/crypto": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.4.5.tgz", + "integrity": "sha512-ymliqxdmen5dGVaiMVQ0VnhrwaYUjbPD3sHoMj8NI6MTuxrREp3pLJASREtWhwmv9k+QzDT6CoyuIXnlEQiWZQ==", + "license": "Apache-2.0", "dependencies": { - "@cardano-sdk/util": "~0.15.5", + "@cardano-sdk/util": "~0.17.1", "blake2b": "^2.1.4", "i": "^0.3.7", - "libsodium-wrappers-sumo": "^0.7.5", + "libsodium-wrappers-sumo": "0.7.10", "lodash": "^4.17.21", - "npm": "^9.3.0", - "pbkdf2": "^3.1.2", + "pbkdf2": "^3.1.3", "ts-custom-error": "^3.2.0", "ts-log": "^2.2.4" }, @@ -2906,49 +2889,68 @@ } } }, - "node_modules/@meshsdk/react/node_modules/@cardano-sdk/util": { - "version": "0.15.7", - "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.15.7.tgz", - "integrity": "sha512-L0f3gXFujRwSSpjzq2W/OwW23fg0gw5S+9R+91He3LgmyfjNygd939eFPCLhwOscsHcJ4AN27UJSYnx3JMKZ0w==", + "node_modules/@meshsdk/provider/node_modules/@cardano-sdk/input-selection": { + "version": "0.14.28", + "resolved": "https://registry.npmjs.org/@cardano-sdk/input-selection/-/input-selection-0.14.28.tgz", + "integrity": "sha512-pbysJUaIbbpesbv/f0XfFPKBb+bLjCmPcMfNJzpePSZBvr8bUcFpnfKtq28KthVdpe2mgL3k9ebTTcBSk7aERw==", + "license": "Apache-2.0", "dependencies": { - "bech32": "^2.0.0", + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/key-management": "~0.29.12", + "@cardano-sdk/util": "~0.17.1", + "bignumber.js": "^9.1.1", "lodash": "^4.17.21", - "serialize-error": "^8", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "type-fest": "^2.19.0" + "ts-custom-error": "^3.2.0" }, "engines": { "node": ">=16.20.2" } }, - "node_modules/@meshsdk/react/node_modules/@harmoniclabs/cbor": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@harmoniclabs/cbor/-/cbor-1.3.0.tgz", - "integrity": "sha512-gzRqqcJL8sulc2/6iqRXZdWUCEeK3A+jwJ88sbVNzgk4IeMFQLSFg4Ck8ZBETu/W/q1zdknjNfJYyH1OxVriQA==", - "deprecated": "update to 1.6.0", + "node_modules/@meshsdk/provider/node_modules/@cardano-sdk/key-management": { + "version": "0.29.13", + "resolved": "https://registry.npmjs.org/@cardano-sdk/key-management/-/key-management-0.29.13.tgz", + "integrity": "sha512-yvdWrZcvrH9s5mBwnKpdT6xGF7vMZ9DSrrEENnhA9NG9jXDLpuYX/KI2TGczUdRPezBFm2y9kO7oHNf8GNYvAA==", + "license": "Apache-2.0", "dependencies": { - "@harmoniclabs/bytestring": "^1.0.0", - "@harmoniclabs/obj-utils": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.0" + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/dapp-connector": "~0.13.26", + "@cardano-sdk/util": "~0.17.1", + "@emurgo/cardano-message-signing-nodejs": "^1.0.1", + "bip39": "^3.0.4", + "chacha": "^2.1.0", + "get-random-values": "^2.0.0", + "lodash": "^4.17.21", + "pbkdf2": "^3.1.3", + "rxjs": "^7.4.0", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" }, - "funding": { - "url": "https://github.com/sponsors/HarmonicLabs" + "engines": { + "node": ">=16.20.2" } }, - "node_modules/@meshsdk/react/node_modules/@harmoniclabs/crypto": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.2.5.tgz", - "integrity": "sha512-t2saWMFWBx8tOHotiYTTfQKhPGpWT4AMLXxq3u0apShVXNV0vgL0gEgSMudBjES/wrKByCqa2xmU70gadz26hA==", + "node_modules/@meshsdk/provider/node_modules/@cardano-sdk/util": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.17.1.tgz", + "integrity": "sha512-TCYe+wRguW1WgRlbWqhGPhcSBkzVzdIcCVgDDN7wiQk2dew0EWVqjsKeqDZdfwzy/s2kr/ZOgXIGywBn/Bzu/Q==", + "license": "Apache-2.0", "dependencies": { - "@harmoniclabs/bitstream": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.3" + "bech32": "^2.0.0", + "lodash": "^4.17.21", + "serialize-error": "^8", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" } }, - "node_modules/@meshsdk/react/node_modules/@harmoniclabs/plutus-data": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@harmoniclabs/plutus-data/-/plutus-data-1.2.4.tgz", - "integrity": "sha512-cpr6AnJRultH6PJRDriewHEgNLQs2IGLampZrLjmK5shzTsHICD0yD0Zig9eKdcS7dmY6mlzvSpAJWPGeTxbCA==", + "node_modules/@meshsdk/provider/node_modules/@harmoniclabs/plutus-data": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@harmoniclabs/plutus-data/-/plutus-data-1.2.6.tgz", + "integrity": "sha512-rF046GZ07XDpjZBNybALKYSycjxCLzXKbhLylu9pRuZiii5fVXReEfgtLB29TsPBvGY6ZBeiyHgJnLgm+huZBw==", + "license": "Apache-2.0", "dependencies": { "@harmoniclabs/biguint": "^1.0.0", "@harmoniclabs/crypto": "^0.2.4", @@ -2959,30 +2961,11 @@ "@harmoniclabs/cbor": "^1.3.0" } }, - "node_modules/@meshsdk/react/node_modules/@harmoniclabs/uplc": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@harmoniclabs/uplc/-/uplc-1.2.4.tgz", - "integrity": "sha512-Px6utj94cO/hQd9NJgVQI8zycsbgh3rAzDeLdZ1m52bo++EuU1GL+arWX3JYso3/3uNrnUFuizjrAIISwQe3Fg==", - "dependencies": { - "@harmoniclabs/bigint-utils": "^1.0.0", - "@harmoniclabs/bitstream": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/HarmonicLabs" - }, - "peerDependencies": { - "@harmoniclabs/bytestring": "^1.0.0", - "@harmoniclabs/cbor": "^1.3.0", - "@harmoniclabs/crypto": "^0.2.4", - "@harmoniclabs/pair": "^1.0.0", - "@harmoniclabs/plutus-data": "^1.2.4" - } - }, - "node_modules/@meshsdk/react/node_modules/@meshsdk/common": { - "version": "1.9.0-beta-40", - "resolved": "https://registry.npmjs.org/@meshsdk/common/-/common-1.9.0-beta-40.tgz", - "integrity": "sha512-owMpLDCJAIY5SFcvrh5uIBd7EPKl7vfxLuPFv9ZA/QcbT7YvbzBD/f6H+2ZgCHnNkuHFqoqBPoC+DQEzjeyagQ==", + "node_modules/@meshsdk/provider/node_modules/@meshsdk/common": { + "version": "1.9.0-beta.100", + "resolved": "https://registry.npmjs.org/@meshsdk/common/-/common-1.9.0-beta.100.tgz", + "integrity": "sha512-H3ktKR9eheRKZupg7DLdUr8A9dsefJbu7Wc+I1suwrv+oAZWiJ2wCuF3bX2QQo3LyWrSkVCE7WEiKFfQmukIww==", + "license": "Apache-2.0", "dependencies": { "bech32": "^2.0.0", "bip39": "3.1.0", @@ -2990,71 +2973,166 @@ "blakejs": "^1.2.1" } }, - "node_modules/@meshsdk/react/node_modules/@meshsdk/core-cst": { - "version": "1.9.0-beta-40", - "resolved": "https://registry.npmjs.org/@meshsdk/core-cst/-/core-cst-1.9.0-beta-40.tgz", - "integrity": "sha512-fP71MGGZ3u99nCYn1+cil7oMhYGTPYN6jbwmuJXTyxrSJe7xA6jBb13WBl4VRm+wII/ME9topxx9BirhQO6bGA==", + "node_modules/@meshsdk/provider/node_modules/@meshsdk/core-cst": { + "version": "1.9.0-beta.100", + "resolved": "https://registry.npmjs.org/@meshsdk/core-cst/-/core-cst-1.9.0-beta.100.tgz", + "integrity": "sha512-gXC7c81puzv12C3xJ6vhH/KIEc/P6ScuXsgmLlqFMpDv0SuoMg+42HgdyWi0WrccVwi8cdepsn5YhtCaYVn0nw==", + "license": "Apache-2.0", "dependencies": { - "@cardano-sdk/core": "^0.45.5", - "@cardano-sdk/crypto": "^0.2.2", - "@cardano-sdk/input-selection": "^0.13.33", - "@cardano-sdk/util": "^0.15.5", - "@harmoniclabs/cbor": "1.3.0", + "@cardano-sdk/core": "0.46.12", + "@cardano-sdk/crypto": "0.4.5", + "@cardano-sdk/input-selection": "0.14.28", + "@cardano-sdk/util": "0.17.1", + "@harmoniclabs/cbor": "1.6.0", "@harmoniclabs/pair": "^1.0.0", - "@harmoniclabs/plutus-data": "1.2.4", - "@harmoniclabs/uplc": "1.2.4", - "@meshsdk/common": "1.9.0-beta-40", + "@harmoniclabs/plutus-data": "1.2.6", + "@harmoniclabs/uplc": "1.4.1", + "@meshsdk/common": "1.9.0-beta.100", "@types/base32-encoding": "^1.0.2", "base32-encoding": "^1.0.0", "bech32": "^2.0.0", "blakejs": "^1.2.1", - "bn.js": "^5.2.0" + "bn.js": "^5.2.0", + "hash.js": "^1.1.7", + "scalus": "^0.14.2" } }, - "node_modules/@meshsdk/react/node_modules/@meshsdk/transaction": { - "version": "1.9.0-beta-40", - "resolved": "https://registry.npmjs.org/@meshsdk/transaction/-/transaction-1.9.0-beta-40.tgz", - "integrity": "sha512-AP68D1op0MTnuagh7Ti6eqizLuN6m2FVGWuLRdZcdWRwGfWnIxctKENgPkd7QcTgtTfsHrce80GsIw6wy+KHPQ==", + "node_modules/@meshsdk/provider/node_modules/@meshsdk/core-cst/node_modules/@harmoniclabs/crypto": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.3.0.tgz", + "integrity": "sha512-UvmGQOLFVFhRIDYLpcWbPQLXl9advCt0h02Z/BtBuXtHiy35WRxKQ3njcUKI0v6zGITuvqQhsf6VOPMeekLdeA==", + "license": "MIT", + "peer": true, "dependencies": { - "@cardano-sdk/core": "^0.45.5", - "@cardano-sdk/input-selection": "^0.13.33", - "@cardano-sdk/util": "^0.15.5", - "@meshsdk/common": "1.9.0-beta-40", - "@meshsdk/core-cst": "1.9.0-beta-40", - "json-bigint": "^1.0.0" + "@harmoniclabs/bitstream": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" } }, - "node_modules/@meshsdk/react/node_modules/@meshsdk/wallet": { - "version": "1.9.0-beta-40", - "resolved": "https://registry.npmjs.org/@meshsdk/wallet/-/wallet-1.9.0-beta-40.tgz", - "integrity": "sha512-MEMQEbbC5Ej++VrLt1Gf3nzmtnRieI6NJ/EgoWEmBvMlgj6g5OdDF3DkWJDOSAx38OJCnKnZQ/DN7W3zDmmaGA==", + "node_modules/@meshsdk/provider/node_modules/@meshsdk/core-cst/node_modules/@harmoniclabs/uplc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@harmoniclabs/uplc/-/uplc-1.4.1.tgz", + "integrity": "sha512-sELKStjxPBPBxBMylU4oBSUe0/8eJe2HqRblNSwrMu8Fso4YpSPDqHZ33iDZ8QAadVUsT5r2EQKX0TLrj7qXvQ==", + "license": "Apache-2.0", + "dependencies": { + "@harmoniclabs/bigint-utils": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/HarmonicLabs" + }, + "peerDependencies": { + "@harmoniclabs/bytestring": "^1.0.0", + "@harmoniclabs/cbor": "^1.3.0", + "@harmoniclabs/crypto": "^0.3.0-dev0", + "@harmoniclabs/pair": "^1.0.0", + "@harmoniclabs/plutus-data": "^1.2.4" + } + }, + "node_modules/@meshsdk/react": { + "version": "1.9.0-beta-40", + "resolved": "https://registry.npmjs.org/@meshsdk/react/-/react-1.9.0-beta-40.tgz", + "integrity": "sha512-RsqI/dBpYDEg2uz3mYCuEgNJIAOm+1Bn/nJM+zlj66ujL349cLpmrTDF/ApGF9HHqjKF7NqesVimGqt6BNILQg==", + "license": "Apache-2.0", "dependencies": { + "@fabianbormann/cardano-peer-connect": "^1.2.18", "@meshsdk/common": "1.9.0-beta-40", - "@meshsdk/core-cst": "1.9.0-beta-40", "@meshsdk/transaction": "1.9.0-beta-40", - "@simplewebauthn/browser": "^13.0.0" + "@meshsdk/wallet": "1.9.0-beta-40", + "@meshsdk/web3-sdk": "0.0.26", + "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-dropdown-menu": "^2.1.2", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/react-label": "^2.1.1", + "@radix-ui/react-tooltip": "^1.1.4", + "class-variance-authority": "^0.7.1", + "tailwind-merge": "^2.6.0", + "tailwindcss-animate": "^1.0.7" + }, + "peerDependencies": { + "react": ">=16.0.0 <20.0.0 || >=16.0.0-rc <20.0.0-rc || >=19.0.0-rc", + "react-dom": ">=16.0.0 <20.0.0 || >=16.0.0-rc <20.0.0-rc || >=19.0.0-rc" } }, - "node_modules/@meshsdk/react/node_modules/@simplewebauthn/browser": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.3.0.tgz", - "integrity": "sha512-BE/UWv6FOToAdVk0EokzkqQQDOWtNydYlY6+OrmiZ5SCNmb41VehttboTetUM3T/fr6EAFYVXjz4My2wg230rQ==" - }, - "node_modules/@meshsdk/react/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "engines": { - "node": ">=12.20" + "node_modules/@meshsdk/react/node_modules/@harmoniclabs/cbor": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/cbor/-/cbor-1.3.0.tgz", + "integrity": "sha512-gzRqqcJL8sulc2/6iqRXZdWUCEeK3A+jwJ88sbVNzgk4IeMFQLSFg4Ck8ZBETu/W/q1zdknjNfJYyH1OxVriQA==", + "deprecated": "update to 1.6.0", + "license": "Apache-2.0", + "dependencies": { + "@harmoniclabs/bytestring": "^1.0.0", + "@harmoniclabs/obj-utils": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/HarmonicLabs" + } + }, + "node_modules/@meshsdk/react/node_modules/@meshsdk/common": { + "version": "1.9.0-beta-40", + "resolved": "https://registry.npmjs.org/@meshsdk/common/-/common-1.9.0-beta-40.tgz", + "integrity": "sha512-owMpLDCJAIY5SFcvrh5uIBd7EPKl7vfxLuPFv9ZA/QcbT7YvbzBD/f6H+2ZgCHnNkuHFqoqBPoC+DQEzjeyagQ==", + "license": "Apache-2.0", + "dependencies": { + "bech32": "^2.0.0", + "bip39": "3.1.0", + "blake2b": "^2.1.4", + "blakejs": "^1.2.1" + } + }, + "node_modules/@meshsdk/react/node_modules/@meshsdk/core-cst": { + "version": "1.9.0-beta-40", + "resolved": "https://registry.npmjs.org/@meshsdk/core-cst/-/core-cst-1.9.0-beta-40.tgz", + "integrity": "sha512-fP71MGGZ3u99nCYn1+cil7oMhYGTPYN6jbwmuJXTyxrSJe7xA6jBb13WBl4VRm+wII/ME9topxx9BirhQO6bGA==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/core": "^0.45.5", + "@cardano-sdk/crypto": "^0.2.2", + "@cardano-sdk/input-selection": "^0.13.33", + "@cardano-sdk/util": "^0.15.5", + "@harmoniclabs/cbor": "1.3.0", + "@harmoniclabs/pair": "^1.0.0", + "@harmoniclabs/plutus-data": "1.2.4", + "@harmoniclabs/uplc": "1.2.4", + "@meshsdk/common": "1.9.0-beta-40", + "@types/base32-encoding": "^1.0.2", + "base32-encoding": "^1.0.0", + "bech32": "^2.0.0", + "blakejs": "^1.2.1", + "bn.js": "^5.2.0" + } + }, + "node_modules/@meshsdk/react/node_modules/@meshsdk/transaction": { + "version": "1.9.0-beta-40", + "resolved": "https://registry.npmjs.org/@meshsdk/transaction/-/transaction-1.9.0-beta-40.tgz", + "integrity": "sha512-AP68D1op0MTnuagh7Ti6eqizLuN6m2FVGWuLRdZcdWRwGfWnIxctKENgPkd7QcTgtTfsHrce80GsIw6wy+KHPQ==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/core": "^0.45.5", + "@cardano-sdk/input-selection": "^0.13.33", + "@cardano-sdk/util": "^0.15.5", + "@meshsdk/common": "1.9.0-beta-40", + "@meshsdk/core-cst": "1.9.0-beta-40", + "json-bigint": "^1.0.0" + } + }, + "node_modules/@meshsdk/react/node_modules/@meshsdk/wallet": { + "version": "1.9.0-beta-40", + "resolved": "https://registry.npmjs.org/@meshsdk/wallet/-/wallet-1.9.0-beta-40.tgz", + "integrity": "sha512-MEMQEbbC5Ej++VrLt1Gf3nzmtnRieI6NJ/EgoWEmBvMlgj6g5OdDF3DkWJDOSAx38OJCnKnZQ/DN7W3zDmmaGA==", + "license": "Apache-2.0", + "dependencies": { + "@meshsdk/common": "1.9.0-beta-40", + "@meshsdk/core-cst": "1.9.0-beta-40", + "@meshsdk/transaction": "1.9.0-beta-40", + "@simplewebauthn/browser": "^13.0.0" } }, "node_modules/@meshsdk/transaction": { "version": "1.9.0-beta.102", "resolved": "https://registry.npmjs.org/@meshsdk/transaction/-/transaction-1.9.0-beta.102.tgz", "integrity": "sha512-YW2LF/mzrs/hWw7+F4psfmSELQL37TgYDG+3y8krg+mUClDntYYVftpEDFAuX+YLjxDiGA2bqcAQaW/l28A+aw==", + "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "0.46.12", "@cardano-sdk/input-selection": "0.14.28", @@ -3064,10 +3142,135 @@ "json-bigint": "^1.0.0" } }, + "node_modules/@meshsdk/transaction/node_modules/@cardano-sdk/core": { + "version": "0.46.12", + "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.46.12.tgz", + "integrity": "sha512-yUA/xBUQMiMqIWiZPvIhM911pL3jNKg4PkZQ8qP9R7yU3NQ5x4RQkZ+zFDlVLxUt+gJiwIW2es0iPd8ObIKCxA==", + "license": "Apache-2.0", + "dependencies": { + "@biglup/is-cid": "^1.0.3", + "@cardano-ogmios/client": "6.9.0", + "@cardano-ogmios/schema": "6.9.0", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/util": "~0.17.1", + "@foxglove/crc": "^0.0.3", + "@scure/base": "^1.1.1", + "fraction.js": "4.0.1", + "ip-address": "^9.0.5", + "lodash": "^4.17.21", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "web-encoding": "^1.1.5" + }, + "engines": { + "node": ">=16.20.2" + }, + "peerDependencies": { + "rxjs": "^7.4.0" + }, + "peerDependenciesMeta": { + "rxjs": { + "optional": true + } + } + }, + "node_modules/@meshsdk/transaction/node_modules/@cardano-sdk/crypto": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.4.5.tgz", + "integrity": "sha512-ymliqxdmen5dGVaiMVQ0VnhrwaYUjbPD3sHoMj8NI6MTuxrREp3pLJASREtWhwmv9k+QzDT6CoyuIXnlEQiWZQ==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/util": "~0.17.1", + "blake2b": "^2.1.4", + "i": "^0.3.7", + "libsodium-wrappers-sumo": "0.7.10", + "lodash": "^4.17.21", + "pbkdf2": "^3.1.3", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + }, + "peerDependencies": { + "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" + }, + "peerDependenciesMeta": { + "@dcspark/cardano-multiplatform-lib-asmjs": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-browser": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-nodejs": { + "optional": true + } + } + }, + "node_modules/@meshsdk/transaction/node_modules/@cardano-sdk/input-selection": { + "version": "0.14.28", + "resolved": "https://registry.npmjs.org/@cardano-sdk/input-selection/-/input-selection-0.14.28.tgz", + "integrity": "sha512-pbysJUaIbbpesbv/f0XfFPKBb+bLjCmPcMfNJzpePSZBvr8bUcFpnfKtq28KthVdpe2mgL3k9ebTTcBSk7aERw==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/key-management": "~0.29.12", + "@cardano-sdk/util": "~0.17.1", + "bignumber.js": "^9.1.1", + "lodash": "^4.17.21", + "ts-custom-error": "^3.2.0" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@meshsdk/transaction/node_modules/@cardano-sdk/key-management": { + "version": "0.29.13", + "resolved": "https://registry.npmjs.org/@cardano-sdk/key-management/-/key-management-0.29.13.tgz", + "integrity": "sha512-yvdWrZcvrH9s5mBwnKpdT6xGF7vMZ9DSrrEENnhA9NG9jXDLpuYX/KI2TGczUdRPezBFm2y9kO7oHNf8GNYvAA==", + "license": "Apache-2.0", + "dependencies": { + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/dapp-connector": "~0.13.26", + "@cardano-sdk/util": "~0.17.1", + "@emurgo/cardano-message-signing-nodejs": "^1.0.1", + "bip39": "^3.0.4", + "chacha": "^2.1.0", + "get-random-values": "^2.0.0", + "lodash": "^4.17.21", + "pbkdf2": "^3.1.3", + "rxjs": "^7.4.0", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@meshsdk/transaction/node_modules/@cardano-sdk/util": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.17.1.tgz", + "integrity": "sha512-TCYe+wRguW1WgRlbWqhGPhcSBkzVzdIcCVgDDN7wiQk2dew0EWVqjsKeqDZdfwzy/s2kr/ZOgXIGywBn/Bzu/Q==", + "license": "Apache-2.0", + "dependencies": { + "bech32": "^2.0.0", + "lodash": "^4.17.21", + "serialize-error": "^8", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + } + }, "node_modules/@meshsdk/wallet": { "version": "1.9.0-beta.102", "resolved": "https://registry.npmjs.org/@meshsdk/wallet/-/wallet-1.9.0-beta.102.tgz", "integrity": "sha512-e0Ba4XZ+XQcxQqA211BryIPZ4xkefhlRoAJKp37ZcuTfmiK1IyrDkaBGA3yuEgi1GnUPhNiCrY4aEBfdRrY1YQ==", + "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "1.9.0-beta.102", "@meshsdk/core-cst": "1.9.0-beta.102", @@ -3075,16 +3278,12 @@ "@simplewebauthn/browser": "^13.0.0" } }, - "node_modules/@meshsdk/wallet/node_modules/@simplewebauthn/browser": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.3.0.tgz", - "integrity": "sha512-BE/UWv6FOToAdVk0EokzkqQQDOWtNydYlY6+OrmiZ5SCNmb41VehttboTetUM3T/fr6EAFYVXjz4My2wg230rQ==" - }, "node_modules/@meshsdk/web3-sdk": { "version": "0.0.26", "resolved": "https://registry.npmjs.org/@meshsdk/web3-sdk/-/web3-sdk-0.0.26.tgz", "integrity": "sha512-HCEOXYeeE569S1T4nILhu9E00an8ya+jtrn5t85NIWYwNxmMhoqjSrxfx5tfEXSN1g2SukuDqViAUZPLuwQjHg==", "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "^1.9.0-beta.35", "@meshsdk/core-cst": "^1.9.0-beta.35", @@ -3095,22 +3294,49 @@ "uuid": "^11.1.0" } }, - "node_modules/@monogrid/gainmap-js": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", - "integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==", - "dev": true, + "node_modules/@meshsdk/web3-sdk/node_modules/@peculiar/webcrypto": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", + "license": "MIT", "dependencies": { - "promise-worker-transferable": "^1.0.4" - }, - "peerDependencies": { - "three": ">= 0.159.0" + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.8.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@monogrid/gainmap-js": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", + "integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "promise-worker-transferable": "^1.0.4" + }, + "peerDependencies": { + "three": ">= 0.159.0" + } + }, + "node_modules/@msgpack/msgpack": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz", + "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==", + "license": "ISC", + "engines": { + "node": ">= 10" } }, "node_modules/@multiformats/dns": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/@multiformats/dns/-/dns-1.0.13.tgz", "integrity": "sha512-yr4bxtA3MbvJ+2461kYIYMsiiZj/FIqKI64hE4SdvWJUdWF9EtZLar38juf20Sf5tguXKFUruluswAO6JsjS2w==", + "license": "Apache-2.0 OR MIT", "dependencies": { "@dnsquery/dns-packet": "^6.1.1", "@libp2p/interface": "^3.1.0", @@ -3124,6 +3350,7 @@ "version": "12.1.6", "resolved": "https://registry.npmjs.org/@multiformats/mafmt/-/mafmt-12.1.6.tgz", "integrity": "sha512-tlJRfL21X+AKn9b5i5VnaTD6bNttpSpcqwKVmDmSHLwxoz97fAHaepqFOk/l1fIu94nImIXneNbhsJx/RQNIww==", + "license": "Apache-2.0 OR MIT", "dependencies": { "@multiformats/multiaddr": "^12.0.0" } @@ -3132,6 +3359,7 @@ "version": "12.5.1", "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", + "license": "Apache-2.0 OR MIT", "dependencies": { "@chainsafe/is-ip": "^2.0.1", "@chainsafe/netmask": "^2.0.0", @@ -3142,23 +3370,12 @@ "uint8arrays": "^5.0.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" - } - }, "node_modules/@next/bundle-analyzer": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-16.2.1.tgz", - "integrity": "sha512-fbj2WE6dnCyG8CvQnrBfpHyxdOIyZ4aEHJY0bSqAmamRiIXDqunFQPDvuSOPo24mJE9zQHw7TY6d+sGrXO98TQ==", + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-16.2.6.tgz", + "integrity": "sha512-amPkVtHCTJAdBwyhhl5+qztHk24O4JlASgrWqh15AmnYi74apfZR46NGC0u4pM6BMAU1mYld4WdzD3cRBP3dOA==", "dev": true, + "license": "MIT", "dependencies": { "webpack-bundle-analyzer": "4.10.1" } @@ -3166,13 +3383,15 @@ "node_modules/@next/env": { "version": "16.1.6", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", - "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==" + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.1.tgz", - "integrity": "sha512-r0epZGo24eT4g08jJlg2OEryBphXqO8aL18oajoTKLzHJ6jVr6P6FI58DLMug04MwD3j8Fj0YK0slyzneKVyzA==", + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.6.tgz", + "integrity": "sha512-Z8l6o4JWKUl755x4R+wogD86KPeU+Ckw4K+SYG4kHeOJtRenDeK+OSbGcqZpDtbwn9DsJVdir2UxmwXuinUbUw==", "dev": true, + "license": "MIT", "dependencies": { "fast-glob": "3.3.1" } @@ -3184,6 +3403,7 @@ "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3192,115 +3412,11 @@ "node": ">= 10" } }, - "node_modules/@next/swc-darwin-x64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", - "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", - "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", - "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", - "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", - "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", - "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", - "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@noble/ciphers": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.1.1.tgz", "integrity": "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw==", + "license": "MIT", "engines": { "node": ">= 20.19.0" }, @@ -3309,25 +3425,15 @@ } }, "node_modules/@noble/curves": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", - "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", "dependencies": { - "@noble/hashes": "2.0.1" - }, - "engines": { - "node": ">= 20.19.0" + "@noble/hashes": "1.8.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", - "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", "engines": { - "node": ">= 20.19.0" + "node": "^14.21.3 || >=16" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -3337,6 +3443,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", "engines": { "node": "^14.21.3 || >=16" }, @@ -3348,6 +3455,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -3360,6 +3468,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", "engines": { "node": ">= 8" } @@ -3368,6 +3477,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -3381,6 +3491,7 @@ "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.4.0" } @@ -3389,6 +3500,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz", "integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==", + "license": "MIT", "engines": { "node": ">= 18" } @@ -3397,6 +3509,7 @@ "version": "6.1.6", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.6.tgz", "integrity": "sha512-kIU8SLQkYWGp3pVKiYzA5OSaNF5EE03P/R8zEmmrG6XwOg5oBjXyQVVIauQ0dgau4zYhpZEhJrvIYt6oM+zZZA==", + "license": "MIT", "dependencies": { "@octokit/auth-token": "^5.0.0", "@octokit/graphql": "^8.2.2", @@ -3414,6 +3527,7 @@ "version": "10.1.4", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.4.tgz", "integrity": "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==", + "license": "MIT", "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" @@ -3426,6 +3540,7 @@ "version": "8.2.2", "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.2.tgz", "integrity": "sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA==", + "license": "MIT", "dependencies": { "@octokit/request": "^9.2.3", "@octokit/types": "^14.0.0", @@ -3438,12 +3553,14 @@ "node_modules/@octokit/openapi-types": { "version": "25.1.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", - "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", + "license": "MIT" }, "node_modules/@octokit/request": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.4.tgz", "integrity": "sha512-q8ybdytBmxa6KogWlNa818r0k1wlqzNC+yNkcQDECHvQo8Vmstrg18JwqJHdJdUiHD2sjlwBgSm9kHkOKe2iyA==", + "license": "MIT", "dependencies": { "@octokit/endpoint": "^10.1.4", "@octokit/request-error": "^6.1.8", @@ -3459,6 +3576,7 @@ "version": "6.1.8", "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.8.tgz", "integrity": "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ==", + "license": "MIT", "dependencies": { "@octokit/types": "^14.0.0" }, @@ -3470,6 +3588,7 @@ "version": "14.1.0", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", + "license": "MIT", "dependencies": { "@octokit/openapi-types": "^25.1.0" } @@ -3478,6 +3597,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", "engines": { "node": ">=8.0.0" } @@ -3486,6 +3606,7 @@ "version": "0.203.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.203.0.tgz", "integrity": "sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ==", + "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.3.0" }, @@ -3494,9 +3615,10 @@ } }, "node_modules/@opentelemetry/context-async-hooks": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.6.1.tgz", - "integrity": "sha512-XHzhwRNkBpeP8Fs/qjGrAf9r9PRv67wkJQ/7ZPaBQQ68DYlTBBx5MF9LvPx7mhuXcDessKK2b+DcxqwpgkcivQ==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.1.tgz", + "integrity": "sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ==", + "license": "Apache-2.0", "engines": { "node": "^18.19.0 || >=20.6.0" }, @@ -3505,9 +3627,10 @@ } }, "node_modules/@opentelemetry/core": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.1.tgz", - "integrity": "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz", + "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", + "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -3522,6 +3645,7 @@ "version": "0.203.0", "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.203.0.tgz", "integrity": "sha512-ke1qyM+3AK2zPuBPb6Hk/GCsc5ewbLvPNkEuELx/JmANeEp6ZjnZ+wypPAJSucTw0wvCGrUaibDSdcrGFoWxKQ==", + "license": "Apache-2.0", "dependencies": { "@opentelemetry/api-logs": "0.203.0", "import-in-the-middle": "^1.8.1", @@ -3538,6 +3662,7 @@ "version": "0.14.0", "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.14.0.tgz", "integrity": "sha512-2HN+7ztxAReXuxzrtA3WboAKlfP5OsPA57KQn2AdYZbJ3zeRPcLXyW4uO/jpLE6PLm0QRtmeGCmfYpqRlwgSwg==", + "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", "@opentelemetry/instrumentation": "^0.203.0" @@ -3550,11 +3675,12 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.1.tgz", - "integrity": "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.1.tgz", + "integrity": "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==", + "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.6.1", + "@opentelemetry/core": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -3565,12 +3691,13 @@ } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.6.1.tgz", - "integrity": "sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.1.tgz", + "integrity": "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==", + "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/resources": "2.6.1", + "@opentelemetry/core": "2.7.1", + "@opentelemetry/resources": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -3581,13 +3708,14 @@ } }, "node_modules/@opentelemetry/sdk-trace-node": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.6.1.tgz", - "integrity": "sha512-Hh2i4FwHWRFhnO2Q/p6svMxy8MPsNCG0uuzUY3glqm0rwM0nQvbTO1dXSp9OqQoTKXcQzaz9q1f65fsurmOhNw==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.7.1.tgz", + "integrity": "sha512-pCpQxU68lV+I9s9svqMyVu5iHdDDUnqUpSxqwyCU8A9ejEsSnMPCbearwsUO4yk08ZJzAIUCFuReMdVQvHrdvg==", + "license": "Apache-2.0", "dependencies": { - "@opentelemetry/context-async-hooks": "2.6.1", - "@opentelemetry/core": "2.6.1", - "@opentelemetry/sdk-trace-base": "2.6.1" + "@opentelemetry/context-async-hooks": "2.7.1", + "@opentelemetry/core": "2.7.1", + "@opentelemetry/sdk-trace-base": "2.7.1" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -3597,12 +3725,13 @@ } }, "node_modules/@opentelemetry/sdk-trace-web": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-2.6.1.tgz", - "integrity": "sha512-JQevIjBlWGcKBfuwe7tdxGR/75RERsf1OOIvUzPKq86J8qhzkyjnLTTuPNPLRQF1xxEe65W5aI1Uwl6yWUGPQQ==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-2.7.1.tgz", + "integrity": "sha512-K806OouCSOjMd8Nr7+ZCq3QT22tdAzzS/7h8vprfiKjkgFQ99/dvwU8d12WJANA6D5Qtme65hyBAqAu9CkQuxQ==", + "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/sdk-trace-base": "2.6.1" + "@opentelemetry/core": "2.7.1", + "@opentelemetry/sdk-trace-base": "2.7.1" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -3612,9 +3741,10 @@ } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", - "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", + "license": "Apache-2.0", "engines": { "node": ">=14" } @@ -3623,6 +3753,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } @@ -3631,17 +3762,19 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "license": "MIT", "dependencies": { "@noble/hashes": "^1.1.5" } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", - "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.7.0.tgz", + "integrity": "sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==", + "license": "MIT", "dependencies": { + "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, @@ -3649,6 +3782,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -3656,19 +3790,13 @@ "node": ">=8.0.0" } }, - "node_modules/@peculiar/webcrypto": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", - "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2", - "webcrypto-core": "^1.8.0" - }, - "engines": { - "node": ">=10.12.0" + "tslib": "^2.8.1" } }, "node_modules/@pkgr/core": { @@ -3676,6 +3804,7 @@ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -3687,13 +3816,15 @@ "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@prisma/client": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.2.tgz", - "integrity": "sha512-gR2EMvfK/aTxsuooaDA32D8v+us/8AAet+C3J1cc04SW35FPdZYgLF+iN4NDLUgAaUGTKdAB0CYenu1TAgGdMg==", + "version": "6.19.3", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.3.tgz", + "integrity": "sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==", "hasInstallScript": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -3711,130 +3842,148 @@ } }, "node_modules/@prisma/config": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.2.tgz", - "integrity": "sha512-kadBGDl+aUswv/zZMk9Mx0C8UZs1kjao8H9/JpI4Wh4SHZaM7zkTwiKn/iFLfRg+XtOAo/Z/c6pAYhijKl0nzQ==", + "version": "6.19.3", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.3.tgz", + "integrity": "sha512-CBPT44BjlQxEt8kiMEauji2WHTDoVBOKl7UlewXmUgBPnr/oPRZC3psci5chJnYmH0ivEIog2OU9PGWoki3DLQ==", "devOptional": true, + "license": "Apache-2.0", "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", - "effect": "3.18.4", + "effect": "3.21.0", "empathic": "2.0.0" } }, "node_modules/@prisma/debug": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.2.tgz", - "integrity": "sha512-lFnEZsLdFLmEVCVNdskLDCL8Uup41GDfU0LUfquw+ercJC8ODTuL0WNKgOKmYxCJVvFwf0OuZBzW99DuWmoH2A==", - "devOptional": true + "version": "6.19.3", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.3.tgz", + "integrity": "sha512-ljkJ+SgpXNktLG0Q/n4JGYCkKf0f8oYLyjImS2I8e2q2WCfdRRtWER062ZV/ixaNP2M2VKlWXVJiGzZaUgbKZw==", + "devOptional": true, + "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.2.tgz", - "integrity": "sha512-TTkJ8r+uk/uqczX40wb+ODG0E0icVsMgwCTyTHXehaEfb0uo80M9g1aW1tEJrxmFHeOZFXdI2sTA1j1AgcHi4A==", + "version": "6.19.3", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.3.tgz", + "integrity": "sha512-RSYxtlYFl5pJ8ZePgMv0lZ9IzVCOdTPOegrs2qcbAEFrBI1G33h6wyC9kjQvo0DnYEhEVY0X4LsuFHXLKQk88g==", "devOptional": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.19.2", + "@prisma/debug": "6.19.3", "@prisma/engines-version": "7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7", - "@prisma/fetch-engine": "6.19.2", - "@prisma/get-platform": "6.19.2" + "@prisma/fetch-engine": "6.19.3", + "@prisma/get-platform": "6.19.3" } }, "node_modules/@prisma/engines-version": { "version": "7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7.tgz", "integrity": "sha512-03bgb1VD5gvuumNf+7fVGBzfpJPjmqV423l/WxsWk2cNQ42JD0/SsFBPhN6z8iAvdHs07/7ei77SKu7aZfq8bA==", - "devOptional": true + "devOptional": true, + "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.2.tgz", - "integrity": "sha512-h4Ff4Pho+SR1S8XerMCC12X//oY2bG3Iug/fUnudfcXEUnIeRiBdXHFdGlGOgQ3HqKgosTEhkZMvGM9tWtYC+Q==", + "version": "6.19.3", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.3.tgz", + "integrity": "sha512-tKtl/qco9Nt7LU5iKhpultD8O4vMCZcU2CHjNTnRrL1QvSUr5W/GcyFPjNL87GtRrwBc7ubXXD9xy4EvLvt8JA==", "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.19.2", + "@prisma/debug": "6.19.3", "@prisma/engines-version": "7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7", - "@prisma/get-platform": "6.19.2" + "@prisma/get-platform": "6.19.3" } }, "node_modules/@prisma/get-platform": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.2.tgz", - "integrity": "sha512-PGLr06JUSTqIvztJtAzIxOwtWKtJm5WwOG6xpsgD37Rc84FpfUBGLKz65YpJBGtkRQGXTYEFie7pYALocC3MtA==", + "version": "6.19.3", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.3.tgz", + "integrity": "sha512-xFj1VcJ1N3MKooOQAGO0W5tsd0W2QzIvW7DD7c/8H14Zmp4jseeWAITm+w2LLoLrlhoHdPPh0NMZ8mfL6puoHA==", "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.19.2" + "@prisma/debug": "6.19.3" } }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "@protobufjs/aspromise": "^1.1.1" } }, "node_modules/@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", + "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "license": "BSD-3-Clause" }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==" + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==" + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" }, "node_modules/@radix-ui/react-accordion": { "version": "1.2.12", "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", @@ -3865,6 +4014,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, @@ -3887,6 +4037,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -3916,6 +4067,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -3945,6 +4097,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", @@ -3970,6 +4123,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -3987,6 +4141,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -4001,6 +4156,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -4015,6 +4171,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -4050,6 +4207,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -4067,6 +4225,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -4081,6 +4240,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -4107,6 +4267,7 @@ "version": "2.1.16", "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -4135,6 +4296,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -4149,6 +4311,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", @@ -4173,6 +4336,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -4203,6 +4367,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", + "license": "MIT", "peerDependencies": { "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" } @@ -4211,6 +4376,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -4228,6 +4394,7 @@ "version": "2.1.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, @@ -4250,6 +4417,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.4" }, @@ -4272,6 +4440,7 @@ "version": "2.1.16", "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", @@ -4311,6 +4480,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -4328,6 +4498,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", @@ -4359,6 +4530,7 @@ "version": "1.1.9", "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -4382,6 +4554,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -4405,6 +4578,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" }, @@ -4427,6 +4601,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -4444,6 +4619,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", @@ -4474,6 +4650,7 @@ "version": "2.2.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", @@ -4516,6 +4693,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -4533,6 +4711,7 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, @@ -4555,6 +4734,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.4" }, @@ -4577,6 +4757,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -4594,6 +4775,7 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", @@ -4623,6 +4805,7 @@ "version": "1.2.15", "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", @@ -4656,6 +4839,7 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", @@ -4680,6 +4864,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", @@ -4708,6 +4893,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -4741,6 +4927,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -4758,6 +4945,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -4772,6 +4960,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -4790,6 +4979,7 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -4807,6 +4997,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, @@ -4824,6 +5015,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -4838,6 +5030,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -4852,6 +5045,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", "dependencies": { "@radix-ui/rect": "1.1.1" }, @@ -4869,6 +5063,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -4886,6 +5081,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, @@ -4907,13 +5103,15 @@ "node_modules/@radix-ui/rect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==" + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" }, "node_modules/@react-spring/animated": { "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", "dev": true, + "license": "MIT", "dependencies": { "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" @@ -4927,6 +5125,7 @@ "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", "dev": true, + "license": "MIT", "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/shared": "~9.7.5", @@ -4944,13 +5143,15 @@ "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@react-spring/shared": { "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", "dev": true, + "license": "MIT", "dependencies": { "@react-spring/rafz": "~9.7.5", "@react-spring/types": "~9.7.5" @@ -4964,6 +5165,7 @@ "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.7.5.tgz", "integrity": "sha512-RxIsCoQfUqOS3POmhVHa1wdWS0wyHAUway73uRLp3GAL5U2iYVNdnzQsep6M2NZ994BlW8TcKuMtQHUqOsy6WA==", "dev": true, + "license": "MIT", "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/core": "~9.7.5", @@ -4980,13 +5182,15 @@ "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@react-three/drei": { "version": "9.122.0", "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.122.0.tgz", "integrity": "sha512-SEO/F/rBCTjlLez7WAlpys+iGe9hty4rNgjZvgkQeXFSiwqD4Hbk/wNHMAbdd8vprO2Aj81mihv4dF5bC7D0CA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", "@mediapipe/tasks-vision": "0.10.17", @@ -5024,10 +5228,11 @@ } }, "node_modules/@react-three/drei/node_modules/zustand": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.12.tgz", - "integrity": "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==", + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.13.tgz", + "integrity": "sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.20.0" }, @@ -5057,6 +5262,7 @@ "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.18.0.tgz", "integrity": "sha512-FYZZqD0UUHUswKz3LQl2Z7H24AhD14XGTsIRw3SJaXUxyfVMi+1yiZGmqTcPt/CkPpdU7rrxqcyQ1zJE5DjvIQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.17.8", "@types/react-reconciler": "^0.26.7", @@ -5106,6 +5312,7 @@ "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.7.0" }, @@ -5122,94 +5329,57 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true - }, - "node_modules/@rvagg/ripemd160": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rvagg/ripemd160/-/ripemd160-2.2.4.tgz", - "integrity": "sha512-ejuJhx9Q+hfOy/4w86E+obE4OAzTVcDh6QNc0v/0IG9hHvegqzwLeltNJSarzkXvIIZfgh63a/EZhpA25VoJLg==" + "dev": true, + "license": "MIT" }, "node_modules/@scarf/scarf": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", - "hasInstallScript": true + "hasInstallScript": true, + "license": "Apache-2.0" }, "node_modules/@scure/base": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@scure/bip32": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-2.0.1.tgz", - "integrity": "sha512-4Md1NI5BzoVP+bhyJaY3K6yMesEFzNS1sE/cP+9nuvE7p/b0kx9XbpDHHFl8dHtufcbdHRUUQdRqLIPHN/s7yA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", "dependencies": { - "@noble/curves": "2.0.1", - "@noble/hashes": "2.0.1", - "@scure/base": "2.0.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", - "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", - "engines": { - "node": ">= 20.19.0" + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" }, "funding": { "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/bip32/node_modules/@scure/base": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.0.0.tgz", - "integrity": "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@scure/bip39": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-2.0.1.tgz", - "integrity": "sha512-PsxdFj/d2AcJcZDX1FXN3dDgitDDTmwf78rKZq1a6c1P1Nan1X/Sxc7667zU3U+AN60g7SxxP0YCVw2H/hBycg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", "dependencies": { - "@noble/hashes": "2.0.1", - "@scure/base": "2.0.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", - "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", - "engines": { - "node": ">= 20.19.0" + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" }, "funding": { "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/bip39/node_modules/@scure/base": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.0.0.tgz", - "integrity": "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@scure/btc-signer": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@scure/btc-signer/-/btc-signer-1.8.1.tgz", "integrity": "sha512-8nX9T++dFyKpvqksNHfSi9CgRsGnHAQtCdIQ1y1GmbCGLpV97v4MUyemUUT6uDumKL3oo3m4niyY6A32nmdLuQ==", + "license": "MIT", "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", @@ -5220,66 +5390,56 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/btc-signer/node_modules/@noble/curves": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", - "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@sidan-lab/whisky-js-browser": { "version": "1.0.25", "resolved": "https://registry.npmjs.org/@sidan-lab/whisky-js-browser/-/whisky-js-browser-1.0.25.tgz", - "integrity": "sha512-Y2aShJwtyUB9j2L9NqGD+Qtxtke/Hnku2wsMT0eFavp7Ppwllro5WzWb20/q1gUs6vRAlVQzA9EChvUH+HsAJg==" + "integrity": "sha512-Y2aShJwtyUB9j2L9NqGD+Qtxtke/Hnku2wsMT0eFavp7Ppwllro5WzWb20/q1gUs6vRAlVQzA9EChvUH+HsAJg==", + "license": "Apache-2.0" }, "node_modules/@sidan-lab/whisky-js-nodejs": { "version": "1.0.25", "resolved": "https://registry.npmjs.org/@sidan-lab/whisky-js-nodejs/-/whisky-js-nodejs-1.0.25.tgz", - "integrity": "sha512-GKbyatMr/AKA/ax6urd7X+zlgKDEpjL/4Vq18re52mQGfbJzLkPJ0etOy3wZMywd9Cxwxaf6nnPIyqj7JlGsTg==" + "integrity": "sha512-GKbyatMr/AKA/ax6urd7X+zlgKDEpjL/4Vq18re52mQGfbJzLkPJ0etOy3wZMywd9Cxwxaf6nnPIyqj7JlGsTg==", + "license": "Apache-2.0" }, - "node_modules/@silentbot1/nat-api": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/@silentbot1/nat-api/-/nat-api-0.4.9.tgz", - "integrity": "sha512-Bm2Fr0sJyGr4B/XgKjQxjGe7Rzs/OlK91OIHsghObxhP3Y4j2y8o7Xjlledu/pxzFEIWaTbZIBSl8ABqoP/WhQ==", - "dependencies": { - "chrome-dgram": "^3.0.6", - "cross-fetch-ponyfill": "^1.0.3", - "debug": "^4.4.0", - "default-gateway": "^7.2.2", - "unordered-array-remove": "^1.0.2", - "xml2js": "^0.6.2" - }, - "engines": { - "node": ">=10.0.0" - } + "node_modules/@simplewebauthn/browser": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.3.0.tgz", + "integrity": "sha512-BE/UWv6FOToAdVk0EokzkqQQDOWtNydYlY6+OrmiZ5SCNmb41VehttboTetUM3T/fr6EAFYVXjz4My2wg230rQ==", + "license": "MIT" + }, + "node_modules/@simplewebauthn/types": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@simplewebauthn/types/-/types-9.0.1.tgz", + "integrity": "sha512-tGSRP1QvsAvsJmnOlRQyw/mvK9gnPtjEc5fg2+m8n+QUa+D7rvrKkOYyfpy42GTs90X3RDOnqJgfHt+qO67/+w==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@sinclair/typebox": { "version": "0.34.49", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz", - "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" } @@ -5288,15 +5448,17 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/@swagger-api/apidom-ast": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ast/-/apidom-ast-1.9.0.tgz", - "integrity": "sha512-K5bnDnR5ugoSyqPjRdxnXt2zMlVE/UTFQGwy6Slln2mb6PdQv+z0nIeybgb+pk0z/DfBGmc2LFHZSRXFUq7g0A==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ast/-/apidom-ast-1.11.1.tgz", + "integrity": "sha512-5vcFzXltmIpCsjQouVKzjj7pPPUxYmwIARHuenim96GDnmqqVTtAoBXpIX++cD5RcJA72EBEqepQ+VSAA12RPA==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-error": "^1.9.0", + "@swagger-api/apidom-error": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5304,13 +5466,14 @@ } }, "node_modules/@swagger-api/apidom-core": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-core/-/apidom-core-1.9.0.tgz", - "integrity": "sha512-CFrb0h6B4iz4G1c6/vjm63u5RaXYUTt4uejp1BBMiLHgE/nucomC8HOdtNI+X+5nOsXRXYu1pX97QDp/9C1rWQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-core/-/apidom-core-1.11.1.tgz", + "integrity": "sha512-KsN0dZBsutUGWtbsqBMvQ+3pJUjq/wRRABCNIG2Ys/1Ctq8FaQaA0MoICPuYgDZCUNsZuJYbw6Swm6e0GaHWtA==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-ast": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", + "@swagger-api/apidom-ast": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", "@types/ramda": "~0.30.0", "minim": "~0.23.8", "ramda": "~0.30.0", @@ -5320,34 +5483,37 @@ } }, "node_modules/@swagger-api/apidom-error": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-error/-/apidom-error-1.9.0.tgz", - "integrity": "sha512-cqwUoqocRT406tx0wMwxbDUbqZKj0wnMdW9s/i30bhw3tyct7CLuj7RHeCePycsH2wnyGBGYLcwHeoE+e050FA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-error/-/apidom-error-1.11.1.tgz", + "integrity": "sha512-7KV2Ac4BOcrv4yJz7T5DbZiTdqbnVUT+g68Hjhabl5zhD28mfEEn9V8Zq2D6rtjlCYkqWAMFb8Y6Y+9ssH5wgA==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7" } }, "node_modules/@swagger-api/apidom-json-pointer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-1.9.0.tgz", - "integrity": "sha512-y38Z0gaFkyHgdzxZ56WPnZavzfeg5x18C/Ju1N3ElB0GWxppSWwx3SfKp3klvqwwYrsZAsMZcrO0ZU67yIEj2g==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-1.11.1.tgz", + "integrity": "sha512-c8QSUgQxDolTO+rP2bvX4CrZOrnTMTAMh0xGq8LaYvzVzs0bQT7ZApsbcA/4bzWlwcg6wy2Uuw+qMadl1FNR3w==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", "@swaggerexpert/json-pointer": "^2.10.1" } }, "node_modules/@swagger-api/apidom-ns-api-design-systems": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-api-design-systems/-/apidom-ns-api-design-systems-1.9.0.tgz", - "integrity": "sha512-ePYELhZOF+tGMMoi7fTuFdioQ5j4wcKGqSFTu09mq6wRJLfx/XjlXfCnH2mMvRaNEx6VC1Z6dPCEt2YBpz0WIA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-api-design-systems/-/apidom-ns-api-design-systems-1.11.1.tgz", + "integrity": "sha512-2K3Ix+nRHDkuixkZ4FAMWY5MAJHipzpFvZrRtneZ7hsx7nObw9HYEXZw/yXuYrvnhC8jsE4z91Gwuvvz7ZjfPw==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-1": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-1": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5355,14 +5521,15 @@ } }, "node_modules/@swagger-api/apidom-ns-arazzo-1": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-arazzo-1/-/apidom-ns-arazzo-1-1.9.0.tgz", - "integrity": "sha512-LDOevWmtIcC4ulEYvjodiFu0DMXK8okKJLoEMV6CPwM6vbuBrvp1YfCUtyhsfm6mH/CdAfhEuatYldYmHY/frQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-arazzo-1/-/apidom-ns-arazzo-1-1.11.1.tgz", + "integrity": "sha512-rnICw0uXnKeNHUaS+Ip7lxtVXqH1iA3zFlX446e4XAamJd6yU28sujIsGiZ71qPQ217teidkfK7Bx7MktHdiEw==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-2020-12": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-2020-12": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5370,14 +5537,15 @@ } }, "node_modules/@swagger-api/apidom-ns-asyncapi-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-2/-/apidom-ns-asyncapi-2-1.9.0.tgz", - "integrity": "sha512-Pugxu7Oibjh7Ba54Z6HRJU+G7zysr1MZUDJ740KJ6TY37S/vN3h3QylWhAcPZ2gbmCEfDmU2LLznWmQhjO505g==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-2/-/apidom-ns-asyncapi-2-1.11.1.tgz", + "integrity": "sha512-syABiWLeWRfKoonUhPriPVwDDeEOlN5RD20Dj/MS9DT5r1BJUrAB1BfRRRHsVhzaXVdUcKKH99iC9C842J9kvA==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-draft-7": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-draft-7": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5385,14 +5553,15 @@ } }, "node_modules/@swagger-api/apidom-ns-asyncapi-3": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-3/-/apidom-ns-asyncapi-3-1.9.0.tgz", - "integrity": "sha512-w7jrzKKvy4CeDC3jMrjn4EpsD3PIM+oY+QGYmCZB8QfQT8j9DwEcThFXwibTjP8bk2SspKNgxjOUHwahHRCEsA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-3/-/apidom-ns-asyncapi-3-1.11.1.tgz", + "integrity": "sha512-y4syE8jOEGuSirc3YaeI0dh3rEvHfc/pERQOTj3KofS2IABpBXTmtg+oDfG2zte1/Cyc/eJ6qecVAns5mhBpow==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-asyncapi-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-asyncapi-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5400,14 +5569,15 @@ } }, "node_modules/@swagger-api/apidom-ns-json-schema-2019-09": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-2019-09/-/apidom-ns-json-schema-2019-09-1.9.0.tgz", - "integrity": "sha512-WoA4C4fhZag+zqhpcH9r5rqjReMQhpCoWM916iPwFzMdvxG1hXjRdxKyb/qjLdx8CWqTOk399fnbdQmUuiejDg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-2019-09/-/apidom-ns-json-schema-2019-09-1.11.1.tgz", + "integrity": "sha512-1SNXikZN2uQ1YZ3A4dzWBoMN6wTkba1qZdy/NOkweFtoLuBb63KKN/gD1e6chQV8+ikqGn8TTUZnYvX6SVBZ6g==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-draft-7": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-draft-7": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5415,14 +5585,15 @@ } }, "node_modules/@swagger-api/apidom-ns-json-schema-2020-12": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-2020-12/-/apidom-ns-json-schema-2020-12-1.9.0.tgz", - "integrity": "sha512-Cj2E1/f1NNDDPUWxeDQqtCRDPz2UNWLfUJvW1vrgS7gw/nC9Dn969xXXG88KNEjt4qL5I9au1lD6NVd6KU71tA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-2020-12/-/apidom-ns-json-schema-2020-12-1.11.1.tgz", + "integrity": "sha512-oyvTkjDXI9k3G8oVHOvpL/t1MfZmx8d7rgeNqsm6j/vK6WlOXIOHdN9LTYRo8YdACaWq/JV5B30grkio/HRMKQ==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-2019-09": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-2019-09": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5430,13 +5601,14 @@ } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-1.9.0.tgz", - "integrity": "sha512-gib7byiNlU3Wrz1STSEr/9m/kj1Da7mDdUuEIh4qGOMuGORXJ/ed+9WP45Ho1Wkz87j8FrnyiJ1s5Q87/woWug==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-1.11.1.tgz", + "integrity": "sha512-Ha23zkVSItmFZbAoSKMI7hwYJT7yTMWO+EcNzDBEClsqRrkcCtvF2YsiQZcyUt5SrEwV8rW0TWE0CVG+WEs2zg==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-ast": "^1.9.0", - "@swagger-api/apidom-core": "^1.9.0", + "@swagger-api/apidom-ast": "^1.11.1", + "@swagger-api/apidom-core": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5444,14 +5616,15 @@ } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-6": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-1.9.0.tgz", - "integrity": "sha512-Dzwi5/El/r9TKnI/xkWTwrPhHZ6rAcuOwmTEUfAmz/UttJnoIUF2BisPTKcVY2sUmpPtSTPYzDC/U0tRf9EiWQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-1.11.1.tgz", + "integrity": "sha512-Gm4ULCg4yulfjZiMIbH1XiiKHI/BqK0zc1GexViiLShXS35/2dc27GmpI0YgV7S+DqvivNrwAkqojeN7ho9/NA==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-draft-4": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-draft-4": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5459,14 +5632,15 @@ } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-7": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-1.9.0.tgz", - "integrity": "sha512-Gutve6BB94a0JNaRYwwKcsCyxhWe0hMf6Up/zmslonegP11O4O3Dp2u446cDUfucyKBFsxjAwhIRBgXeuFYsZQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-1.11.1.tgz", + "integrity": "sha512-OHW4Qb0BqbHJ3QoQcGREE5bobMeBkZzSQe/0RFGayhI1HJZqrmwtot2nLAuie9sQJoj/xeUprOsA/he06NVFEw==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-draft-6": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-draft-6": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5474,15 +5648,16 @@ } }, "node_modules/@swagger-api/apidom-ns-openapi-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-2/-/apidom-ns-openapi-2-1.9.0.tgz", - "integrity": "sha512-UtWDuTVV5g59eLWUoms4IUFWrP1jtiwUDbkqxnVWNcHOXwd+wsgrvxSUL3mIYgxQTK3jKxCSPyycreo2BlKK1w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-2/-/apidom-ns-openapi-2-1.11.1.tgz", + "integrity": "sha512-yXHJmyN+NyF2xBD6KlFmGuMrf1hKqK9pm/FwStepIUqvn6bfTGgEdUi5BivQuErRrN6NtQczFF21Jlu6jjg86Q==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-draft-4": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-draft-4": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5490,14 +5665,15 @@ } }, "node_modules/@swagger-api/apidom-ns-openapi-3-0": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-0/-/apidom-ns-openapi-3-0-1.9.0.tgz", - "integrity": "sha512-BXUpIOlo76kkMLghmDNLEIynzy2WiRoPW/wu8WqYm1bX3L1Dd1vspPNnPgyS0SnRawvLCDVmWF6LJiwcXz46Yw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-0/-/apidom-ns-openapi-3-0-1.11.1.tgz", + "integrity": "sha512-R2zHd33OiVT5eTlYKS1FyVDP0G76ymdP2EIrBPbM1FDKam1kRIRdgZA2StCd9PY4oNp/LqQKMnfe9wdLWZS3AA==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-draft-4": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-draft-4": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5505,16 +5681,17 @@ } }, "node_modules/@swagger-api/apidom-ns-openapi-3-1": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-1.9.0.tgz", - "integrity": "sha512-LKF78h8kVmM8T9vUcD338VTG4FdWgMWokDy/vftQtckUL7Br98leVl4CSz+Vb1jAxle3wXsE40xxkek6UwKg5Q==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-1.11.1.tgz", + "integrity": "sha512-FtoW4wkFO1VSHu6G+wUZ71hQhIOuastJPyWEePbfySE4Uiz+01t/X/ODnl2OHRGVUYFoJa7kJi5/xqcsprdxtA==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-ast": "^1.9.0", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-json-pointer": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-2020-12": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-0": "^1.9.0", + "@swagger-api/apidom-ast": "^1.11.1", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-json-pointer": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-2020-12": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-0": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5522,17 +5699,18 @@ } }, "node_modules/@swagger-api/apidom-ns-openapi-3-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-2/-/apidom-ns-openapi-3-2-1.9.0.tgz", - "integrity": "sha512-Netfb7NPArDft5vFKdl48KLiSIA3cN4PiG27xhjt0oRgvYEaryALHyei9xv04Mlm+u8KTy8MmcWueUOq9SP1wg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-2/-/apidom-ns-openapi-3-2-1.11.1.tgz", + "integrity": "sha512-ILJAgp6mHwoV8rRuKYD3QuvPdcRcmK9YmAfrsjgC7fJM7irqzC+nBOKhrWVpTAee7r3b+B3HpV5MG8aKGd9qNQ==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-ast": "^1.9.0", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-json-pointer": "^1.9.0", - "@swagger-api/apidom-ns-json-schema-2020-12": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-0": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-1": "^1.9.0", + "@swagger-api/apidom-ast": "^1.11.1", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-json-pointer": "^1.11.1", + "@swagger-api/apidom-ns-json-schema-2020-12": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-0": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-1": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5540,135 +5718,144 @@ } }, "node_modules/@swagger-api/apidom-parser-adapter-api-design-systems-json": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-json/-/apidom-parser-adapter-api-design-systems-json-1.9.0.tgz", - "integrity": "sha512-lWRPlyotW+djH6oEX7b2iYWAhj/+KaFJsOEooGGLCETvyCQsCdSfIT1y5EEIQHWNPmw/z4UlIGczyUBT+Lu9KA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-json/-/apidom-parser-adapter-api-design-systems-json-1.11.1.tgz", + "integrity": "sha512-bCt1/7NPfCznhq2D3Y1UcZowdxMtr6wGCISMSPf3ziaCcOQhy7sG/nWEzS/rwcKCVNefVft833Ab3jaCWGivJw==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-api-design-systems": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-api-design-systems": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-api-design-systems-yaml": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-yaml/-/apidom-parser-adapter-api-design-systems-yaml-1.9.0.tgz", - "integrity": "sha512-x6TWhxwi824tv9biRNZOlHew1x5rKLvKISBrDx3Nr7oo/G688hWTNkDMmLpHIxIhLV1hAmqOIr8C+gc3dPqS+A==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-yaml/-/apidom-parser-adapter-api-design-systems-yaml-1.11.1.tgz", + "integrity": "sha512-hUcshr5ydn/L4VsgP5nyrFDp4QqIADrx5nQnFddw/OWCNi1Al19ccPxuBh1Qlf421AAmk1oUiybeGyduvRsVPQ==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-api-design-systems": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-api-design-systems": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-arazzo-json-1": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-arazzo-json-1/-/apidom-parser-adapter-arazzo-json-1-1.9.0.tgz", - "integrity": "sha512-uKowJL9zhy4l7Fi+JlcPlErHa8Tt0IpVFmGPfINY1yJumUrIwPNa+hsjXqVwy3O/YVjjSYleDqqAyG8afyxs2w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-arazzo-json-1/-/apidom-parser-adapter-arazzo-json-1-1.11.1.tgz", + "integrity": "sha512-8ydiEnlSJ7DPhFqg9Z11u4Vda16yaOuIGLablI0mOnYoAMTlqnteGk5CDPlVb970VBTYvsNlgW+164XfHAU/6w==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-arazzo-1": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-arazzo-1": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-arazzo-yaml-1": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-arazzo-yaml-1/-/apidom-parser-adapter-arazzo-yaml-1-1.9.0.tgz", - "integrity": "sha512-FtwXvAkeOKuQopzmn2U+e+tm7cA3i8KEjyMXGIuE6ElutpHfZoFm+gXnFY0bEqKXlYtXhl87MpXQIrN8XMcuVg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-arazzo-yaml-1/-/apidom-parser-adapter-arazzo-yaml-1-1.11.1.tgz", + "integrity": "sha512-G4++rZDMKokEfq78EJ2aE7pgd1Xo70XIn1/ikSiT5awfuhPJzNcV99ZdzQI2xVVU/pbKIL2Vc/b5SP1IRlfCwA==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-arazzo-1": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-arazzo-1": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-asyncapi-json-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-2/-/apidom-parser-adapter-asyncapi-json-2-1.9.0.tgz", - "integrity": "sha512-kjuiAW8cwl5hjR/0yITm6kZRmv9PgeAqwANzrtqgAzNA9e19oBmQvTEW8rPPRgqFccglm1Oq1VyqTirJiD8XLw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-2/-/apidom-parser-adapter-asyncapi-json-2-1.11.1.tgz", + "integrity": "sha512-7Npn4LkG4q95b2VimG3SV0lqgG3xPeF5Srq+sVbG7iFd4yDubvEVy5zzqx5QH4tOtATdarhv6glA9j3hTfWBdQ==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-asyncapi-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-asyncapi-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-asyncapi-json-3": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-3/-/apidom-parser-adapter-asyncapi-json-3-1.9.0.tgz", - "integrity": "sha512-doM/IJXaVwrqT2mAiXpaLqG7TnPGBvrl0dmRxUHh/JHIzdEUfkgC6L4lf89BWSemC72J2uThFoA9PqF6z+IRUg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-3/-/apidom-parser-adapter-asyncapi-json-3-1.11.1.tgz", + "integrity": "sha512-/C1CzsnUW2ZMBg4kWYrhrfqmyjb4aGo9+YaySQwdArLfM8l2HCOQqDEteGIivedVEsmTpVdhC60gdb6N2VzSaQ==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-asyncapi-3": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-asyncapi-3": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2/-/apidom-parser-adapter-asyncapi-yaml-2-1.9.0.tgz", - "integrity": "sha512-lqWuxkWwFK5dct+8NRh1N2w8dm/61oOq4hHSe9+PsINPwv3gEdU6G3dz/WOrD4hWBwzssB37uNl/UxbGbkmkGA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2/-/apidom-parser-adapter-asyncapi-yaml-2-1.11.1.tgz", + "integrity": "sha512-0Xfu8PLM787el0R7lwjFfQYe0Bpv3Jz0YlkEiQqAVvftVb0oNi8tg9FhDTR8ju/N94gpNXIfaH/5Ahgz5G+NKg==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-asyncapi-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-asyncapi-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-asyncapi-yaml-3": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-yaml-3/-/apidom-parser-adapter-asyncapi-yaml-3-1.9.0.tgz", - "integrity": "sha512-giy3nafwV7yVLuYQAztTTTg3N1Nw+EXFfQ7PdgLXKlAJUIrNJN2Aypfvvl1eirLNTyvaVDtO5saDUPNiO7S+zQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-yaml-3/-/apidom-parser-adapter-asyncapi-yaml-3-1.11.1.tgz", + "integrity": "sha512-DqoR43NsFBmiJW1h2Xg3n2V6NQx+95qJ3ziA9rIbKJHGCidHtjNJgi4I7sWGnaIApIHijYY2bW22MKXaT0a0cQ==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-asyncapi-3": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-asyncapi-3": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-json": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-json/-/apidom-parser-adapter-json-1.9.0.tgz", - "integrity": "sha512-h/UkZiFXK69rYJgNtbVQ+LltVagZndtcVyjc20guF/HT7eWjwpmd3Kt2cOk0QkhmoHjDZfNYsBw1yGjfcHNhvQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-json/-/apidom-parser-adapter-json-1.11.1.tgz", + "integrity": "sha512-L8XFzTbEknHDhD40M/pSoDlimjlYaXXWZS4AmyD3i+XRfiDWWVhEWHPE9OTNk6UL8R6DOBm3RSDxAd5xpLoPjg==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-ast": "^1.9.0", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", + "@swagger-api/apidom-ast": "^1.11.1", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -5678,135 +5865,144 @@ } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-2/-/apidom-parser-adapter-openapi-json-2-1.9.0.tgz", - "integrity": "sha512-aFyY950Np4Y69nsxtho8TdShIE6T9iGmbFWyo/RTxcE39ST97W5xOBrF0s7IX5o1MsuYTNJYOcrSRiwIcn8MxQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-2/-/apidom-parser-adapter-openapi-json-2-1.11.1.tgz", + "integrity": "sha512-s9xZa/h4Yiz+Qc304s+9JSTPFsToYtSWQCeyA9jkHOWy/Oq8ZjD9wg34IjENS3yBqM1YLz6Dk+PX06DcyAOnnw==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-openapi-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-openapi-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-3-0": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-0/-/apidom-parser-adapter-openapi-json-3-0-1.9.0.tgz", - "integrity": "sha512-7f7IvOh+BEd73K92jXVIPECGgGReLf/x6WP81osB7npc0MIosMRvkT031LuGB7OVUj7UlBeq9kWqF2h1YGt71w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-0/-/apidom-parser-adapter-openapi-json-3-0-1.11.1.tgz", + "integrity": "sha512-dLGaVn24N+YZRB0vzQMC4R+aiSNfD81Xcp5TwdEbE+jOeOnoOe5NqzqCWjaDpSMChDsK/NdaSDjQj4uiYfWpug==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-0": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-0": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-3-1": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-1/-/apidom-parser-adapter-openapi-json-3-1-1.9.0.tgz", - "integrity": "sha512-hHOKnNOf81cAqzra+PBS/t5lRMhpSAoMavjqDdpmH5ad06nbDEyr7RcQmQl+WM9lsfeU0fbYteMhvSo2neuIWg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-1/-/apidom-parser-adapter-openapi-json-3-1-1.11.1.tgz", + "integrity": "sha512-EnYF3rzPZoiCYDnp4ChB6K15RUV4rE6QfEh7fTEwIlkWMUKv4oVwZd8aqz2i9laRZiBH6S2uUoED8YNtCNbeIg==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-1": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-1": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-3-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-2/-/apidom-parser-adapter-openapi-json-3-2-1.9.0.tgz", - "integrity": "sha512-ajuSbYNMqrcb3ZBkOEESp/D9ima4+mRowBsYRhCF6bg0rKC+Qd2UmdQ6rh/mwgt7h9Jad64FflfmaIt9IRGNYQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-2/-/apidom-parser-adapter-openapi-json-3-2-1.11.1.tgz", + "integrity": "sha512-digw37g+k/rg87HHMUHuSZVWH1Kh8OjC8SmQflIh1Oot9fGhmnZWddsws+sKWSVy6/HveuZPykL8bxtSV3Nc/A==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-2/-/apidom-parser-adapter-openapi-yaml-2-1.9.0.tgz", - "integrity": "sha512-1HIUcxF/prJWmACmkHrreX4aapHzexs+LrdJeTGo7Q5fXs2seZxF+CRynldigi7MXjuoQ0o+Ww0xTXAov7nqNg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-2/-/apidom-parser-adapter-openapi-yaml-2-1.11.1.tgz", + "integrity": "sha512-b38GFur/NjjLFBCVR/wo7DRF6EW5h8B5jBe7C17EVaJvg9eRzknnr9/KMnxYeTtjQVO8W/JeY7LlLad1/j0pcA==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-openapi-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-openapi-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0/-/apidom-parser-adapter-openapi-yaml-3-0-1.9.0.tgz", - "integrity": "sha512-Ukzv15L3DX3K2xVZqCJerg3gU/qi+xVx6VpmjhGuibq03pGKuI6dM++HlczW3Vm7Xo5RwTuF2CFUJJie8QDLHw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0/-/apidom-parser-adapter-openapi-yaml-3-0-1.11.1.tgz", + "integrity": "sha512-dza6Bwe5kLL+4jANuaScxvYh3o7RxESp6Riz6M09cXRysyRrHFQ7UYuUhxepSD4jSiSxJQS8nu0i547i6Z7W7Q==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-0": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-0": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1/-/apidom-parser-adapter-openapi-yaml-3-1-1.9.0.tgz", - "integrity": "sha512-XbVtS1LR8BdSI4iK9x6riA+BYLQkyCuKt3uWrlBUWgojiqm2FZC1s9Q3a5UVnbs77OrKQyFkNkiWhcX8ct7VVA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1/-/apidom-parser-adapter-openapi-yaml-3-1-1.11.1.tgz", + "integrity": "sha512-PgmolQN1PYdROSo/cHNyXINVD+aLmW6VqfwT7potNo08c4aWj+QQ/a0Az+mldfJ+G98WjNRvEKr8dhEw8zfqmw==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-1": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-1": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-3-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-2/-/apidom-parser-adapter-openapi-yaml-3-2-1.9.0.tgz", - "integrity": "sha512-A82nil8pszk6oIo23pAyXQuYtp5Rdrp0rDLS17jSg4ziC/i0biwlh2Hi+Sfrcy96jaCA2HIghOiVFSrSBwJPkQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-2/-/apidom-parser-adapter-openapi-yaml-3-2-1.11.1.tgz", + "integrity": "sha512-+nmtJ3/wPLBBN6d8xI8rD0mOz80V4iSRe6rYYOQ/skel673N1SY4B58Ufnc7KnMNV4cOce/a52ASQ1Qd1csLvQ==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-yaml-1-2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-1.9.0.tgz", - "integrity": "sha512-UvF2oyT3fBTyDXKvBMa96ODUD+qjWeVZwydZmGLZpa7Fo0gsc2cDByzmnLm8O9+DUZEpJgz7It5irL7FlR9Xvg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-1.11.1.tgz", + "integrity": "sha512-KEgk5PoSmmLC7ZvH0+RF4FPyWAj0NyrPFbTr04DmNPznfr2qpGqvt3ZBmAJm82jrWoI1dc8EH1ugT1YX69N8ww==", + "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-ast": "^1.9.0", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", + "@swagger-api/apidom-ast": "^1.11.1", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", "@tree-sitter-grammars/tree-sitter-yaml": "=0.7.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", @@ -5820,6 +6016,7 @@ "resolved": "https://registry.npmjs.org/@tree-sitter-grammars/tree-sitter-yaml/-/tree-sitter-yaml-0.7.1.tgz", "integrity": "sha512-AynBwkIoQCTgjDR33bDUp9Mqq+YTco0is3n5hRApMqG9of/6A4eQsfC1/uSEeHSUyMQSYawcAWamsexnVpIP4Q==", "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "node-addon-api": "^8.3.1", @@ -5839,6 +6036,7 @@ "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.22.4.tgz", "integrity": "sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg==", "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "node-addon-api": "^8.3.0", @@ -5846,59 +6044,62 @@ } }, "node_modules/@swagger-api/apidom-reference": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-1.9.0.tgz", - "integrity": "sha512-dlJPZSg6G8TvmL7sFi5nJOTITJAZRZpWcVozvJCjwak5lkB+i95fPiH7O59fWYfg5U4fUUiAwG4+mVwSjBWpNA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-1.11.1.tgz", + "integrity": "sha512-wxsRo12YVc2Q4o81K9EGzX5oM1htNDkeCIRkLyg1wPvzFQUH4khd6aOWYaX/0V0L+7yqwwmeW/t80xV8qLEGAQ==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.26.10", - "@swagger-api/apidom-core": "^1.9.0", - "@swagger-api/apidom-error": "^1.9.0", + "@swagger-api/apidom-core": "^1.11.1", + "@swagger-api/apidom-error": "^1.11.1", "@types/ramda": "~0.30.0", - "axios": "^1.12.2", + "axios": "^1.16.0", "minimatch": "^10.2.1", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" }, "optionalDependencies": { - "@swagger-api/apidom-json-pointer": "^1.9.0", - "@swagger-api/apidom-ns-arazzo-1": "^1.9.0", - "@swagger-api/apidom-ns-asyncapi-2": "^1.9.0", - "@swagger-api/apidom-ns-openapi-2": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-0": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-1": "^1.9.0", - "@swagger-api/apidom-ns-openapi-3-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-api-design-systems-json": "^1.9.0", - "@swagger-api/apidom-parser-adapter-api-design-systems-yaml": "^1.9.0", - "@swagger-api/apidom-parser-adapter-arazzo-json-1": "^1.9.0", - "@swagger-api/apidom-parser-adapter-arazzo-yaml-1": "^1.9.0", - "@swagger-api/apidom-parser-adapter-asyncapi-json-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-asyncapi-json-3": "^1.9.0", - "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-asyncapi-yaml-3": "^1.9.0", - "@swagger-api/apidom-parser-adapter-json": "^1.9.0", - "@swagger-api/apidom-parser-adapter-openapi-json-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-openapi-json-3-0": "^1.9.0", - "@swagger-api/apidom-parser-adapter-openapi-json-3-1": "^1.9.0", - "@swagger-api/apidom-parser-adapter-openapi-json-3-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-openapi-yaml-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": "^1.9.0", - "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": "^1.9.0", - "@swagger-api/apidom-parser-adapter-openapi-yaml-3-2": "^1.9.0", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.9.0" + "@swagger-api/apidom-json-pointer": "^1.11.1", + "@swagger-api/apidom-ns-arazzo-1": "^1.11.1", + "@swagger-api/apidom-ns-asyncapi-2": "^1.11.1", + "@swagger-api/apidom-ns-openapi-2": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-0": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-1": "^1.11.1", + "@swagger-api/apidom-ns-openapi-3-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-api-design-systems-json": "^1.11.1", + "@swagger-api/apidom-parser-adapter-api-design-systems-yaml": "^1.11.1", + "@swagger-api/apidom-parser-adapter-arazzo-json-1": "^1.11.1", + "@swagger-api/apidom-parser-adapter-arazzo-yaml-1": "^1.11.1", + "@swagger-api/apidom-parser-adapter-asyncapi-json-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-asyncapi-json-3": "^1.11.1", + "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-asyncapi-yaml-3": "^1.11.1", + "@swagger-api/apidom-parser-adapter-json": "^1.11.1", + "@swagger-api/apidom-parser-adapter-openapi-json-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-openapi-json-3-0": "^1.11.1", + "@swagger-api/apidom-parser-adapter-openapi-json-3-1": "^1.11.1", + "@swagger-api/apidom-parser-adapter-openapi-json-3-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-openapi-yaml-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": "^1.11.1", + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": "^1.11.1", + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-2": "^1.11.1", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.11.1" } }, "node_modules/@swagger-api/apidom-reference/node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", "engines": { "node": "18 || 20 || >=22" } }, "node_modules/@swagger-api/apidom-reference/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, @@ -5907,11 +6108,12 @@ } }, "node_modules/@swagger-api/apidom-reference/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -5924,6 +6126,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/@swaggerexpert/cookie/-/cookie-2.0.2.tgz", "integrity": "sha512-DPI8YJ0Vznk4CT+ekn3rcFNq1uQwvUHZhH6WvTSPD0YKBIlMS9ur2RYKghXuxxOiqOam/i4lHJH4xTIiTgs3Mg==", + "license": "Apache-2.0", "dependencies": { "apg-lite": "^1.0.3" }, @@ -5935,6 +6138,7 @@ "version": "2.10.2", "resolved": "https://registry.npmjs.org/@swaggerexpert/json-pointer/-/json-pointer-2.10.2.tgz", "integrity": "sha512-qMx1nOrzoB+PF+pzb26Q4Tc2sOlrx9Ba2UBNX9hB31Omrq+QoZ2Gly0KLrQWw4Of1AQ4J9lnD+XOdwOdcdXqqw==", + "license": "Apache-2.0", "dependencies": { "apg-lite": "^1.0.4" }, @@ -5946,6 +6150,7 @@ "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.0" } @@ -5954,6 +6159,7 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/@t3-oss/env-core/-/env-core-0.10.1.tgz", "integrity": "sha512-GcKZiCfWks5CTxhezn9k5zWX3sMDIYf6Kaxy2Gx9YEQftFcz8hDRN56hcbylyAO3t4jQnQ5ifLawINsNgCDpOg==", + "license": "MIT", "peerDependencies": { "typescript": ">=5.0.0", "zod": "^3.0.0" @@ -5968,6 +6174,7 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/@t3-oss/env-nextjs/-/env-nextjs-0.10.1.tgz", "integrity": "sha512-iy2qqJLnFh1RjEWno2ZeyTu0ufomkXruUsOZludzDIroUabVvHsrSjtkHqwHp1/pgPUzN3yBRHMILW162X7x2Q==", + "license": "MIT", "dependencies": { "@t3-oss/env-core": "0.10.1" }, @@ -5982,20 +6189,22 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.95.2", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.95.2.tgz", - "integrity": "sha512-o4T8vZHZET4Bib3jZ/tCW9/7080urD4c+0/AUaYVpIqOsr7y0reBc1oX3ttNaSW5mYyvZHctiQ/UOP2PfdmFEQ==", + "version": "5.100.14", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.14.tgz", + "integrity": "sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/react-query": { - "version": "5.95.2", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.95.2.tgz", - "integrity": "sha512-/wGkvLj/st5Ud1Q76KF1uFxScV7WeqN1slQx5280ycwAyYkIPGaRZAEgHxe3bjirSd5Zpwkj6zNcR4cqYni/ZA==", + "version": "5.100.14", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.14.tgz", + "integrity": "sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==", + "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.95.2" + "@tanstack/query-core": "5.100.14" }, "funding": { "type": "github", @@ -6005,101 +6214,38 @@ "react": "^18 || ^19" } }, - "node_modules/@thaunknown/simple-peer": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@thaunknown/simple-peer/-/simple-peer-10.1.0.tgz", - "integrity": "sha512-xNM49v0rBbjIKrS9XNwXW3FFuGvsPGadFRWbBdLAY87pEJeo7V0dxyX6GBHP8UVlefffRedCLsjYXb6i8W9Ofg==", - "dependencies": { - "debug": "^4.4.3", - "err-code": "^3.0.1", - "streamx": "^2.23.0", - "uint8-util": "^2.2.6", - "webrtc-polyfill": "^1.2.0" - } - }, - "node_modules/@thaunknown/simple-peer/node_modules/streamx": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", - "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", - "dependencies": { - "events-universal": "^1.0.0", - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - } - }, - "node_modules/@thaunknown/simple-websocket": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/@thaunknown/simple-websocket/-/simple-websocket-9.1.3.tgz", - "integrity": "sha512-pf/FCJsgWtLJiJmIpiSI7acOZVq3bIQCpnNo222UFc8Ph1lOUOTpe6LoYhhiOSKB9GUaWJEVUtZ+sK1/aBgU5Q==", - "dependencies": { - "debug": "^4.3.5", - "queue-microtask": "^1.2.3", - "streamx": "^2.17.0", - "uint8-util": "^2.2.5", - "ws": "^8.17.1" - } - }, - "node_modules/@thaunknown/simple-websocket/node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@thaunknown/thirty-two": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@thaunknown/thirty-two/-/thirty-two-1.0.5.tgz", - "integrity": "sha512-Q53KyCXweV1CS62EfqtPDqfpksn5keQ59PGqzzkK+g8Vif1jB4inoBCcs/BUSdsqddhE3G+2Fn+4RX3S6RqT0A==", - "dependencies": { - "uint8-util": "^2.2.5" - }, - "engines": { - "node": ">=0.2.6" - } - }, "node_modules/@trpc/client": { - "version": "11.16.0", - "resolved": "https://registry.npmjs.org/@trpc/client/-/client-11.16.0.tgz", - "integrity": "sha512-TxIzm7OoK3baKZ0XCbuMUbI3GhgjcbKHIc4nWVKaRpCRnbSh0T31BT6fTPYwtnA/Nur8pBCGqC2B4J5hEPiPFQ==", + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/@trpc/client/-/client-11.17.0.tgz", + "integrity": "sha512-KpJBFrbKTDeVCFv/3ckL1XBBH5Yssn8hethI/rUy7GIpTj+VzjtPjykDqJpzobuVOz+d26cXCSu1t4I6MYI5Zg==", "funding": [ "https://trpc.io/sponsor" ], + "license": "MIT", "bin": { "intent": "bin/intent.js" }, "peerDependencies": { - "@trpc/server": "11.16.0", + "@trpc/server": "11.17.0", "typescript": ">=5.7.2" } }, "node_modules/@trpc/next": { - "version": "11.16.0", - "resolved": "https://registry.npmjs.org/@trpc/next/-/next-11.16.0.tgz", - "integrity": "sha512-6KyedRnGd7wZ44crr7oZ/fHxVDPkyItvg2PS6kfhM5Y6yLlBcEsMOhqxqKQNQZHBjAtnQzZjPuCslP05gZ6BSA==", + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/@trpc/next/-/next-11.17.0.tgz", + "integrity": "sha512-EjwMkyamGjf5aslgfYB70hMKs4cgmsjSJbMinmuXktkGvbmdW54VbV04Sk4o4QTY5b//Rns9dz+ku8DN6lVhvw==", "funding": [ "https://trpc.io/sponsor" ], + "license": "MIT", "bin": { "intent": "bin/intent.js" }, "peerDependencies": { "@tanstack/react-query": "^5.59.15", - "@trpc/client": "11.16.0", - "@trpc/react-query": "11.16.0", - "@trpc/server": "11.16.0", + "@trpc/client": "11.17.0", + "@trpc/react-query": "11.17.0", + "@trpc/server": "11.17.0", "next": "*", "react": ">=16.8.0", "react-dom": ">=16.8.0", @@ -6115,27 +6261,29 @@ } }, "node_modules/@trpc/react-query": { - "version": "11.16.0", - "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-11.16.0.tgz", - "integrity": "sha512-ah6ULOu4k7lCEFAEoEgqg14YPVu1lnCVVYcz8TP7avPPKwtcB0CbFKYve3ElRP+V5DoBT75Q+G66bRdR+rQ5fg==", + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-11.17.0.tgz", + "integrity": "sha512-AGcl5YAF8NnhBmyJ6PqJqKb1M5VTGSoNRNqJ3orct4o4epdcg0GWhW+qT9q6gPzs/2ImIwYCdfFpgNGdZ9yLHA==", "funding": [ "https://trpc.io/sponsor" ], + "license": "MIT", "peerDependencies": { "@tanstack/react-query": "^5.80.3", - "@trpc/client": "11.16.0", - "@trpc/server": "11.16.0", + "@trpc/client": "11.17.0", + "@trpc/server": "11.17.0", "react": ">=18.2.0", "typescript": ">=5.7.2" } }, "node_modules/@trpc/server": { - "version": "11.16.0", - "resolved": "https://registry.npmjs.org/@trpc/server/-/server-11.16.0.tgz", - "integrity": "sha512-XgGuUMddrUTd04+za/WE5GFuZ1/YU9XQG0t3VL5WOIu2JspkOlq6k4RYEiqS6HSJt+S0RXaPdIoE2anIP/BBRQ==", + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/@trpc/server/-/server-11.17.0.tgz", + "integrity": "sha512-jbAOUe0PpUTCYqziyu+8vYXZdDXPudZgnEhWCQ2NjKnVEjfE93RqHTt1oycZJv/HNf51YlRXfEEwSIAbb161rw==", "funding": [ "https://trpc.io/sponsor" ], + "license": "MIT", "bin": { "intent": "bin/intent.js" }, @@ -6144,12 +6292,13 @@ } }, "node_modules/@turf/boolean-point-in-polygon": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.3.4.tgz", - "integrity": "sha512-v/4hfyY90Vz9cDgs2GwjQf+Lft8o7mNCLJOTz/iv8SHAIgMMX0czEoIaNVOJr7tBqPqwin1CGwsncrkf5C9n8Q==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.3.5.tgz", + "integrity": "sha512-ba7+B0wzaS9GtERZOoXUZ6oW8IcIJHNQZf3c+tiD9ESjcsPO1Q/4qIJGTKl92nBLhhracHJxMWBM/U6hAVkaRg==", + "license": "MIT", "dependencies": { - "@turf/helpers": "7.3.4", - "@turf/invariant": "7.3.4", + "@turf/helpers": "7.3.5", + "@turf/invariant": "7.3.5", "@types/geojson": "^7946.0.10", "point-in-polygon-hao": "^1.1.0", "tslib": "^2.8.1" @@ -6159,9 +6308,10 @@ } }, "node_modules/@turf/helpers": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", - "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.5.tgz", + "integrity": "sha512-E/NMGV5MwbjjP7AJXBtsanC3yY8N2MQ87IGdIgkB2ji5AtBpwnH4L3gEqpYN4RlCJJWbLbzO91BbKv2waUd0eg==", + "license": "MIT", "dependencies": { "@types/geojson": "^7946.0.10", "tslib": "^2.8.1" @@ -6171,11 +6321,12 @@ } }, "node_modules/@turf/invariant": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", - "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.5.tgz", + "integrity": "sha512-ZVIvsBvjr8lO7WxC5zYNjRsjSDvyGvWkJMjuWaJjTU8x+1tmfNnw3gDX/TI2Sit83gcRYLYkNo23lB/udqx/Hg==", + "license": "MIT", "dependencies": { - "@turf/helpers": "7.3.4", + "@turf/helpers": "7.3.5", "@types/geojson": "^7946.0.10", "tslib": "^2.8.1" }, @@ -6186,23 +6337,15 @@ "node_modules/@tweenjs/tween.js": { "version": "23.1.3", "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", - "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==" - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -6216,6 +6359,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } @@ -6225,6 +6369,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -6235,6 +6380,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" } @@ -6243,6 +6389,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/base32-encoding/-/base32-encoding-1.0.2.tgz", "integrity": "sha512-6kXiZ8gETqBU/B9ddcw15nwacX4iX9mLZTU0kghWK5u+OdjfJg6vxHh/vXoURWTyLSzs2jKgcq1lS3S/Tvl4mw==", + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6252,6 +6399,7 @@ "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.4.tgz", "integrity": "sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6261,6 +6409,7 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6268,22 +6417,26 @@ "node_modules/@types/d3-array": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==" + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" }, "node_modules/@types/d3-ease": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", "dependencies": { "@types/d3-color": "*" } @@ -6291,12 +6444,14 @@ "node_modules/@types/d3-path": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==" + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" }, "node_modules/@types/d3-scale": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", "dependencies": { "@types/d3-time": "*" } @@ -6305,6 +6460,7 @@ "version": "3.1.8", "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", "dependencies": { "@types/d3-path": "*" } @@ -6312,17 +6468,20 @@ "node_modules/@types/d3-time": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==" + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" }, "node_modules/@types/d3-timer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" }, "node_modules/@types/debug": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", "dependencies": { "@types/ms": "*" } @@ -6331,36 +6490,41 @@ "version": "1.4.10", "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/eslint": { "version": "8.56.12", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" }, "node_modules/@types/estree-jsx": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/formidable": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.5.0.tgz", - "integrity": "sha512-fHChKoKkxUy/n7uCHHWTMQ8yA7/raxz1+K2B7edHTIQhwBHX9TfRnCX0ohmuR77ezEFgMapUuSksk0MA7nQCrA==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.5.1.tgz", + "integrity": "sha512-aFQijSGbD8JCeEST2LEbwR7faHynbt43lojLIcTM/QhB2U06h41ZVRFVEql+Z1xdL+aKGIzm69V/P/uSW9N6XA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6368,12 +6532,14 @@ "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==" + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -6382,13 +6548,15 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -6398,6 +6566,7 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } @@ -6407,6 +6576,7 @@ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^30.0.0", "pretty-format": "^30.0.0" @@ -6415,30 +6585,35 @@ "node_modules/@types/json-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@types/json-bigint/-/json-bigint-1.0.4.tgz", - "integrity": "sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag==" + "integrity": "sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag==", + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/jsonld": { "version": "1.5.15", "resolved": "https://registry.npmjs.org/@types/jsonld/-/jsonld-1.5.15.tgz", "integrity": "sha512-PlAFPZjL+AuGYmwlqwKEL0IMP8M8RexH0NIPGfCVWSQ041H2rR/8OlyZSD7KsCVoN8vCfWdtWDBxX8yBVP+xow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/jsonwebtoken": { "version": "9.0.10", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", "dev": true, + "license": "MIT", "dependencies": { "@types/ms": "*", "@types/node": "*" @@ -6448,6 +6623,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -6455,12 +6631,14 @@ "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", - "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", + "version": "20.19.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", + "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", + "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } @@ -6469,13 +6647,15 @@ "version": "2019.7.3", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/papaparse": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.5.2.tgz", "integrity": "sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6483,20 +6663,23 @@ "node_modules/@types/prismjs": { "version": "1.26.6", "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", - "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==" + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "license": "MIT" }, "node_modules/@types/ramda": { "version": "0.30.2", "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.30.2.tgz", "integrity": "sha512-PyzHvjCalm2BRYjAU6nIB3TprYwMNOUY/7P/N8bSzp9W/yM2YrtGtAnnVtaCNSeOZ8DzKyFDvaqQs7LnWwwmBA==", + "license": "MIT", "dependencies": { "types-ramda": "^0.30.1" } }, "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", + "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", + "license": "MIT", "dependencies": { "csstype": "^3.2.2" } @@ -6506,6 +6689,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, + "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" } @@ -6515,6 +6699,7 @@ "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } @@ -6523,71 +6708,80 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/stats.js": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/swagger-jsdoc": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz", "integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/swagger-ui-react": { "version": "5.18.0", "resolved": "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-5.18.0.tgz", "integrity": "sha512-c2M9adVG7t28t1pq19K9Jt20VLQf0P/fwJwnfcmsVVsdkwCWhRmbKDu+tIs0/NGwJ/7GY8lBx+iKZxuDI5gDbw==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } }, "node_modules/@types/three": { - "version": "0.183.1", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.183.1.tgz", - "integrity": "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==", + "version": "0.184.1", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.184.1.tgz", + "integrity": "sha512-6q4VdiqVsrTRqmk62/BnlcAvIrnDM0zf2ZDVKI5kZiniWrSaOHaQzmbp+BNzoggc/8tgW412pL//wZIxu2PPTA==", "dev": true, + "license": "MIT", "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": ">=0.5.17", - "@webgpu/types": "*", "fflate": "~0.8.2", - "meshoptimizer": "~1.0.1" + "meshoptimizer": "~1.1.1" } }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", "optional": true }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" }, "node_modules/@types/use-sync-external-store": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", - "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==" + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" }, "node_modules/@types/webxr": { "version": "0.5.24", "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/yargs": { "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -6596,27 +6790,30 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/zen-observable": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", - "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" + "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==", + "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz", - "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.4.tgz", + "integrity": "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/type-utils": "8.57.2", - "@typescript-eslint/utils": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/type-utils": "8.59.4", + "@typescript-eslint/utils": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6626,9 +6823,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.57.2", + "@typescript-eslint/parser": "^8.59.4", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { @@ -6636,20 +6833,22 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz", - "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.4.tgz", + "integrity": "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", "debug": "^4.4.3" }, "engines": { @@ -6661,17 +6860,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", - "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.4.tgz", + "integrity": "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.2", - "@typescript-eslint/types": "^8.57.2", + "@typescript-eslint/tsconfig-utils": "^8.59.4", + "@typescript-eslint/types": "^8.59.4", "debug": "^4.4.3" }, "engines": { @@ -6682,17 +6882,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", - "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.4.tgz", + "integrity": "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2" + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6703,10 +6904,11 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", - "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.4.tgz", + "integrity": "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -6715,20 +6917,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz", - "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.4.tgz", + "integrity": "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4", + "@typescript-eslint/utils": "8.59.4", "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6739,14 +6942,15 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", - "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.4.tgz", + "integrity": "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -6756,20 +6960,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", - "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.4.tgz", + "integrity": "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.57.2", - "@typescript-eslint/tsconfig-utils": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/project-service": "8.59.4", + "@typescript-eslint/tsconfig-utils": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6779,7 +6984,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { @@ -6787,15 +6992,17 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, + "license": "MIT", "engines": { "node": "18 || 20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, @@ -6804,12 +7011,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -6818,28 +7026,17 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", - "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.4.tgz", + "integrity": "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2" + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6850,16 +7047,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", - "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.4.tgz", + "integrity": "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/types": "8.59.4", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -6875,6 +7073,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" }, @@ -6883,294 +7082,63 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==" - }, - "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", - "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", - "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "license": "ISC" }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, - "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", - "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", - "cpu": [ - "x64" - ], + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", "dev": true, - "optional": true, - "os": [ - "darwin" - ] + "license": "MIT" }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", - "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", - "cpu": [ - "x64" - ], + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", "dev": true, - "optional": true, - "os": [ - "freebsd" - ] + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", - "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", - "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", - "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", - "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", - "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", - "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", - "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", - "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", - "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", - "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", - "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", - "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@use-gesture/core": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", - "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", - "dev": true - }, - "node_modules/@use-gesture/react": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", - "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", - "dev": true, - "dependencies": { - "@use-gesture/core": "10.3.1" - }, - "peerDependencies": { - "react": ">= 16.8.0" - } - }, - "node_modules/@utxorpc/sdk": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@utxorpc/sdk/-/sdk-0.6.8.tgz", - "integrity": "sha512-Mff6q2o7R2aam85KmjtAZDKPhJesMmnGFbk2M54lPO0FwrrWRfUf6DYezqWfYcjXgKQSHDuklAcdtF0weEENRA==", - "dependencies": { - "@connectrpc/connect": "1.4", - "@connectrpc/connect-node": "1.4", - "@connectrpc/connect-web": "1.4", - "@utxorpc/spec": "0.16.0", - "buffer": "^6.0.3" - } + "node_modules/@utxorpc/sdk": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@utxorpc/sdk/-/sdk-0.6.8.tgz", + "integrity": "sha512-Mff6q2o7R2aam85KmjtAZDKPhJesMmnGFbk2M54lPO0FwrrWRfUf6DYezqWfYcjXgKQSHDuklAcdtF0weEENRA==", + "license": "MIT", + "dependencies": { + "@connectrpc/connect": "1.4", + "@connectrpc/connect-node": "1.4", + "@connectrpc/connect-web": "1.4", + "@utxorpc/spec": "0.16.0", + "buffer": "^6.0.3" + } }, "node_modules/@utxorpc/spec": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/@utxorpc/spec/-/spec-0.16.0.tgz", "integrity": "sha512-EK2M0TBp14MrRCYDuFeJ+bAS39RxxLLh+CD08h/YvAgxSv/4ZOBCf1/sxHAGCBGGndB4heZYFeuQ+i1i8vP5lw==", + "license": "MIT", "dependencies": { "@bufbuild/protobuf": "^1.10.0" }, @@ -7182,6 +7150,7 @@ "version": "0.0.78", "resolved": "https://registry.npmjs.org/@utxos/sdk/-/sdk-0.0.78.tgz", "integrity": "sha512-K90Ks1Bhd+41eV/B/VGWH2w8Ohr7aVJQs74v1btO7WG43rTQ+ay5uxZshefRNQCf2yTN00on8phUq7BKgamANQ==", + "license": "Apache-2.0", "dependencies": { "@buildonspark/spark-sdk": "0.5.0", "@meshsdk/bitcoin": "1.9.0-beta.89", @@ -7196,14 +7165,16 @@ } }, "node_modules/@utxos/sdk/node_modules/@bufbuild/protobuf": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", - "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==" + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.0.tgz", + "integrity": "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==", + "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/@utxos/sdk/node_modules/@buildonspark/spark-sdk": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@buildonspark/spark-sdk/-/spark-sdk-0.5.0.tgz", "integrity": "sha512-+u39p8Hb9t0VzWPsPvnt5r8P799R/wTyLfycu9PvZdsTQbxOPbSV+vYhMWLxqQdEtT/DeC+zVgt2skda+lG4Gg==", + "license": "Apache-2.0", "dependencies": { "@bufbuild/protobuf": "^2.2.5", "@lightsparkdev/core": "^1.4.4", @@ -7233,364 +7204,50 @@ "nice-grpc": "^2.1.10", "nice-grpc-client-middleware-retry": "^3.1.10", "nice-grpc-common": "^2.0.2", - "nice-grpc-opentelemetry": "^0.1.18", - "nice-grpc-web": "^3.3.7", - "ts-proto": "^2.6.1", - "ua-parser-js": "^2.0.6", - "uuidv7": "^1.0.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": ">=18.2.0", - "react-native": ">=0.71.0", - "react-native-get-random-values": ">=1.11.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-native": { - "optional": true - }, - "react-native-get-random-values": { - "optional": true - } - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/core": { - "version": "0.45.10", - "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.45.10.tgz", - "integrity": "sha512-PU/onQuPgsy0CtFKDlHcozGHMTHrigWztTmKq54tL0TdWRcClXbMh5Q63ALcP388ZouPC1nKomOAooVgyrrEfw==", - "dependencies": { - "@biglup/is-cid": "^1.0.3", - "@cardano-ogmios/client": "6.9.0", - "@cardano-ogmios/schema": "6.9.0", - "@cardano-sdk/crypto": "~0.2.3", - "@cardano-sdk/util": "~0.16.0", - "@foxglove/crc": "^0.0.3", - "@scure/base": "^1.1.1", - "fraction.js": "4.0.1", - "ip-address": "^9.0.5", - "lodash": "^4.17.21", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "web-encoding": "^1.1.5" - }, - "engines": { - "node": ">=16.20.2" - }, - "peerDependencies": { - "rxjs": "^7.4.0" - }, - "peerDependenciesMeta": { - "rxjs": { - "optional": true - } - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/core/node_modules/@cardano-sdk/util": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.16.0.tgz", - "integrity": "sha512-f0tfX8oiauqAFCyyc/o2Ouezyk83QD4zqLl4DUjZNyCtITL8gBHh25Bkw7RUCGEZ+hf6Qms1n0ui0j3wVY7zRg==", - "dependencies": { - "bech32": "^2.0.0", - "lodash": "^4.17.21", - "serialize-error": "^8", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "type-fest": "^2.19.0" - }, - "engines": { - "node": ">=16.20.2" - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/crypto": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.2.3.tgz", - "integrity": "sha512-jTl8rbocV1XO5DBR6+lGY6Owc/bP+wBg5eO3PttTeKhx/J7o99pyuTa5H36a/XTJwqDwKIXV922QxZR+rfjVbA==", - "dependencies": { - "@cardano-sdk/util": "~0.16.0", - "blake2b": "^2.1.4", - "i": "^0.3.7", - "libsodium-wrappers-sumo": "^0.7.5", - "lodash": "^4.17.21", - "npm": "^9.3.0", - "pbkdf2": "^3.1.2", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4" - }, - "engines": { - "node": ">=16.20.2" - }, - "peerDependencies": { - "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", - "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", - "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" - }, - "peerDependenciesMeta": { - "@dcspark/cardano-multiplatform-lib-asmjs": { - "optional": true - }, - "@dcspark/cardano-multiplatform-lib-browser": { - "optional": true - }, - "@dcspark/cardano-multiplatform-lib-nodejs": { - "optional": true - } - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/crypto/node_modules/@cardano-sdk/util": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.16.0.tgz", - "integrity": "sha512-f0tfX8oiauqAFCyyc/o2Ouezyk83QD4zqLl4DUjZNyCtITL8gBHh25Bkw7RUCGEZ+hf6Qms1n0ui0j3wVY7zRg==", - "dependencies": { - "bech32": "^2.0.0", - "lodash": "^4.17.21", - "serialize-error": "^8", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "type-fest": "^2.19.0" - }, - "engines": { - "node": ">=16.20.2" - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/input-selection": { - "version": "0.13.34", - "resolved": "https://registry.npmjs.org/@cardano-sdk/input-selection/-/input-selection-0.13.34.tgz", - "integrity": "sha512-/AidYTF9WesLoMc4PHoETxXgrfYEq8GECcikjvLwx1mygmKpok4Lp41Aio7sBasUCLvZ82/yTd3uXIAvec1aCA==", - "dependencies": { - "@cardano-sdk/core": "~0.43.0", - "@cardano-sdk/key-management": "~0.25.1", - "@cardano-sdk/util": "~0.15.5", - "bignumber.js": "^9.1.1", - "lodash": "^4.17.21", - "ts-custom-error": "^3.2.0" - }, - "engines": { - "node": ">=16.20.2" - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/input-selection/node_modules/@cardano-sdk/core": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.43.0.tgz", - "integrity": "sha512-hPnZXjObJub0eXV2dDAG2/gEg/vw092RZ1VGMZfBSqavz18Tg/K6jGQ3cOpWZ9d+MqFzZTCB+s5ctdRkYt3idA==", - "dependencies": { - "@biglup/is-cid": "^1.0.3", - "@cardano-ogmios/client": "6.9.0", - "@cardano-ogmios/schema": "6.9.0", - "@cardano-sdk/crypto": "~0.1.32", - "@cardano-sdk/util": "~0.15.5", - "@foxglove/crc": "^0.0.3", - "@scure/base": "^1.1.1", - "fraction.js": "4.0.1", - "ip-address": "^9.0.5", - "lodash": "^4.17.21", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "web-encoding": "^1.1.5" - }, - "engines": { - "node": ">=16.20.2" - }, - "peerDependencies": { - "rxjs": "^7.4.0" - }, - "peerDependenciesMeta": { - "rxjs": { - "optional": true - } - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/input-selection/node_modules/@cardano-sdk/crypto": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.1.32.tgz", - "integrity": "sha512-RCKFvkzD32QpKQ0jULADVRNmfBNkCwiZl2nlFbkZ3aCrfIex+6/2CizoagJ161fA7lL5/HGuzWfjOg3GX2ax6w==", - "dependencies": { - "@cardano-sdk/util": "~0.15.5", - "blake2b": "^2.1.4", - "i": "^0.3.7", - "libsodium-wrappers-sumo": "^0.7.5", - "lodash": "^4.17.21", - "npm": "^9.3.0", - "pbkdf2": "^3.1.2", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4" - }, - "engines": { - "node": ">=16.20.2" - }, - "peerDependencies": { - "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", - "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", - "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" - }, - "peerDependenciesMeta": { - "@dcspark/cardano-multiplatform-lib-asmjs": { - "optional": true - }, - "@dcspark/cardano-multiplatform-lib-browser": { - "optional": true - }, - "@dcspark/cardano-multiplatform-lib-nodejs": { - "optional": true - } - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/key-management": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@cardano-sdk/key-management/-/key-management-0.25.1.tgz", - "integrity": "sha512-D99XTIplI2aQnCZtVUKZdmH9wZJQC2WuZL6hTqGZHHFBAeju2zBzGWT21LlcPRlT0/2DP2/OdfIHoHCr2ORp4g==", - "dependencies": { - "@cardano-sdk/core": "~0.43.0", - "@cardano-sdk/crypto": "~0.1.32", - "@cardano-sdk/dapp-connector": "~0.13.1", - "@cardano-sdk/util": "~0.15.5", - "@emurgo/cardano-message-signing-nodejs": "^1.0.1", - "bip39": "^3.0.4", - "chacha": "^2.1.0", - "get-random-values": "^2.0.0", - "lodash": "^4.17.21", - "pbkdf2": "^3.1.2", - "rxjs": "^7.4.0", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4" - }, - "engines": { - "node": ">=16.20.2" - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/key-management/node_modules/@cardano-sdk/core": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.43.0.tgz", - "integrity": "sha512-hPnZXjObJub0eXV2dDAG2/gEg/vw092RZ1VGMZfBSqavz18Tg/K6jGQ3cOpWZ9d+MqFzZTCB+s5ctdRkYt3idA==", - "dependencies": { - "@biglup/is-cid": "^1.0.3", - "@cardano-ogmios/client": "6.9.0", - "@cardano-ogmios/schema": "6.9.0", - "@cardano-sdk/crypto": "~0.1.32", - "@cardano-sdk/util": "~0.15.5", - "@foxglove/crc": "^0.0.3", - "@scure/base": "^1.1.1", - "fraction.js": "4.0.1", - "ip-address": "^9.0.5", - "lodash": "^4.17.21", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "web-encoding": "^1.1.5" - }, - "engines": { - "node": ">=16.20.2" - }, - "peerDependencies": { - "rxjs": "^7.4.0" - }, - "peerDependenciesMeta": { - "rxjs": { - "optional": true - } - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/key-management/node_modules/@cardano-sdk/crypto": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.1.32.tgz", - "integrity": "sha512-RCKFvkzD32QpKQ0jULADVRNmfBNkCwiZl2nlFbkZ3aCrfIex+6/2CizoagJ161fA7lL5/HGuzWfjOg3GX2ax6w==", - "dependencies": { - "@cardano-sdk/util": "~0.15.5", - "blake2b": "^2.1.4", - "i": "^0.3.7", - "libsodium-wrappers-sumo": "^0.7.5", - "lodash": "^4.17.21", - "npm": "^9.3.0", - "pbkdf2": "^3.1.2", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4" - }, - "engines": { - "node": ">=16.20.2" - }, - "peerDependencies": { - "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", - "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", - "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" - }, - "peerDependenciesMeta": { - "@dcspark/cardano-multiplatform-lib-asmjs": { - "optional": true - }, - "@dcspark/cardano-multiplatform-lib-browser": { - "optional": true - }, - "@dcspark/cardano-multiplatform-lib-nodejs": { - "optional": true - } - } - }, - "node_modules/@utxos/sdk/node_modules/@cardano-sdk/util": { - "version": "0.15.7", - "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.15.7.tgz", - "integrity": "sha512-L0f3gXFujRwSSpjzq2W/OwW23fg0gw5S+9R+91He3LgmyfjNygd939eFPCLhwOscsHcJ4AN27UJSYnx3JMKZ0w==", - "dependencies": { - "bech32": "^2.0.0", - "lodash": "^4.17.21", - "serialize-error": "^8", - "ts-custom-error": "^3.2.0", - "ts-log": "^2.2.4", - "type-fest": "^2.19.0" - }, - "engines": { - "node": ">=16.20.2" - } - }, - "node_modules/@utxos/sdk/node_modules/@harmoniclabs/crypto": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.2.5.tgz", - "integrity": "sha512-t2saWMFWBx8tOHotiYTTfQKhPGpWT4AMLXxq3u0apShVXNV0vgL0gEgSMudBjES/wrKByCqa2xmU70gadz26hA==", - "dependencies": { - "@harmoniclabs/bitstream": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.3" - } - }, - "node_modules/@utxos/sdk/node_modules/@harmoniclabs/plutus-data": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@harmoniclabs/plutus-data/-/plutus-data-1.2.4.tgz", - "integrity": "sha512-cpr6AnJRultH6PJRDriewHEgNLQs2IGLampZrLjmK5shzTsHICD0yD0Zig9eKdcS7dmY6mlzvSpAJWPGeTxbCA==", - "dependencies": { - "@harmoniclabs/biguint": "^1.0.0", - "@harmoniclabs/crypto": "^0.2.4", - "@harmoniclabs/uint8array-utils": "^1.0.0" + "nice-grpc-opentelemetry": "^0.1.18", + "nice-grpc-web": "^3.3.7", + "ts-proto": "^2.6.1", + "ua-parser-js": "^2.0.6", + "uuidv7": "^1.0.2" + }, + "engines": { + "node": ">=18.0.0" }, "peerDependencies": { - "@harmoniclabs/bytestring": "^1.0.0", - "@harmoniclabs/cbor": "^1.3.0" + "react": ">=18.2.0", + "react-native": ">=0.71.0", + "react-native-get-random-values": ">=1.11.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-native": { + "optional": true + }, + "react-native-get-random-values": { + "optional": true + } } }, - "node_modules/@utxos/sdk/node_modules/@harmoniclabs/uplc": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@harmoniclabs/uplc/-/uplc-1.2.4.tgz", - "integrity": "sha512-Px6utj94cO/hQd9NJgVQI8zycsbgh3rAzDeLdZ1m52bo++EuU1GL+arWX3JYso3/3uNrnUFuizjrAIISwQe3Fg==", + "node_modules/@utxos/sdk/node_modules/@meshsdk/bitcoin": { + "version": "1.9.0-beta.89", + "resolved": "https://registry.npmjs.org/@meshsdk/bitcoin/-/bitcoin-1.9.0-beta.89.tgz", + "integrity": "sha512-2ZREpEwqzMt63bRMi2vf+rbts+xzoWSMdSLhqA7XgGHkfZKr8eonaJW37NSsMFVtafwgR1UppIF7SuslrSlnww==", "dependencies": { - "@harmoniclabs/bigint-utils": "^1.0.0", - "@harmoniclabs/bitstream": "^1.0.0", - "@harmoniclabs/uint8array-utils": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/HarmonicLabs" - }, - "peerDependencies": { - "@harmoniclabs/bytestring": "^1.0.0", - "@harmoniclabs/cbor": "^1.3.0", - "@harmoniclabs/crypto": "^0.2.4", - "@harmoniclabs/pair": "^1.0.0", - "@harmoniclabs/plutus-data": "^1.2.4" + "@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3", + "bip174": "^3.0.0", + "bip32": "^4.0.0", + "bip39": "^3.1.0", + "bitcoinjs-lib": "^6.1.7", + "ecpair": "^2.0.0" } }, "node_modules/@utxos/sdk/node_modules/@meshsdk/common": { "version": "1.9.0-beta.89", "resolved": "https://registry.npmjs.org/@meshsdk/common/-/common-1.9.0-beta.89.tgz", "integrity": "sha512-K78TSif28c+gcXuk9yeqN0VCI4LNoZm6z+oPI+bQWQz865aSsCBVMuE3AN1plZtLCn6fhhWW5O72HLRQzX+Bkg==", + "license": "Apache-2.0", "dependencies": { "bech32": "^2.0.0", "bip39": "3.1.0", @@ -7602,6 +7259,7 @@ "version": "1.9.0-beta.89", "resolved": "https://registry.npmjs.org/@meshsdk/core-cst/-/core-cst-1.9.0-beta.89.tgz", "integrity": "sha512-DSnAKOlCD+LncUNnxNYMTvOx4Zf7NlV3koa781idA1jCJneW17VSgE7VmrLdg2gO68t7xkF5931xSZUDzUwbIg==", + "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "^0.45.5", "@cardano-sdk/crypto": "^0.2.2", @@ -7623,6 +7281,7 @@ "version": "1.9.0-beta.89", "resolved": "https://registry.npmjs.org/@meshsdk/transaction/-/transaction-1.9.0-beta.89.tgz", "integrity": "sha512-p3ePCJWcLosswb4F5OiCHYszTci6EG5UR7JnONTJmjkE83blg92iNSkWYQbHclXXM5Ldf/CuHL9BDhPQcIfErw==", + "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "^0.45.5", "@cardano-sdk/input-selection": "^0.13.33", @@ -7636,6 +7295,7 @@ "version": "1.9.0-beta.89", "resolved": "https://registry.npmjs.org/@meshsdk/wallet/-/wallet-1.9.0-beta.89.tgz", "integrity": "sha512-HcirkitcpSflgCjZdKu2hKy6ico36L54cgI+mJXIqhYk8evAZiUyw8bLhfqQhjjTCKCTfmGDtu+xuBs8eYmVWw==", + "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "1.9.0-beta.89", "@meshsdk/core-cst": "1.9.0-beta.89", @@ -7643,120 +7303,52 @@ "@simplewebauthn/browser": "^13.0.0" } }, - "node_modules/@utxos/sdk/node_modules/@noble/curves": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", - "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@utxos/sdk/node_modules/@scure/bip32": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", - "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", - "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@utxos/sdk/node_modules/@scure/bip39": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", - "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "node_modules/@utxos/sdk/node_modules/@peculiar/webcrypto": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", + "license": "MIT", "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@utxos/sdk/node_modules/@simplewebauthn/browser": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.3.0.tgz", - "integrity": "sha512-BE/UWv6FOToAdVk0EokzkqQQDOWtNydYlY6+OrmiZ5SCNmb41VehttboTetUM3T/fr6EAFYVXjz4My2wg230rQ==" - }, - "node_modules/@utxos/sdk/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "engines": { - "node": ">=12.20" + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.8.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@webgpu/types": { - "version": "0.1.69", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz", - "integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==", - "dev": true - }, - "node_modules/@webpod/ip": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@webpod/ip/-/ip-0.6.1.tgz", - "integrity": "sha512-0oPIqLPfoIPzstsbmWUFlLx9I8KiisiC9/+YQPaotVU67DnTV+vx/zXXnkMgZTKu9rHWznmUQX3jgvfqr1t4+g==", "engines": { - "node": ">=10" - } - }, - "node_modules/@webtorrent/http-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@webtorrent/http-node/-/http-node-1.3.0.tgz", - "integrity": "sha512-GWZQKroPES4z91Ijx6zsOsb7+USOxjy66s8AoTWg0HiBBdfnbtf9aeh3Uav0MgYn4BL8Q7tVSUpd0gGpngKGEQ==", - "dependencies": { - "freelist": "^1.0.3", - "http-parser-js": "^0.4.3" + "node": ">=10.12.0" } }, "node_modules/@zxing/text-encoding": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "license": "(Unlicense OR Apache-2.0)", "optional": true }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/abort-controller-x": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.4.3.tgz", - "integrity": "sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==" + "integrity": "sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==", + "license": "MIT" }, "node_modules/abort-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/abort-error/-/abort-error-1.0.1.tgz", - "integrity": "sha512-fxqCblJiIPdSXIUrxI0PL+eJG49QdP9SQ70qtB65MVAoMr2rASlOyAbJFOylfB467F/f+5BCLJJq58RYi7mGfg==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/abort-error/-/abort-error-1.0.2.tgz", + "integrity": "sha512-lVgvB2NyPLqbXXhVmXcYFTC1x5K7CiVdPgdY7LGgFQWC8506oN01sPN3i9cl9ynuwF4iJ0TS9exnR7cZ9FuX4w==", + "license": "Apache-2.0 OR MIT" }, "node_modules/abortcontroller-polyfill": { "version": "1.7.8", "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.8.tgz", - "integrity": "sha512-9f1iZ2uWh92VcrU9Y8x+LdM4DLj75VE0MJB8zuF1iUnroEptStw+DQ8EQPMUdfe5k+PkB1uUfDQfWbhstH8LrQ==" + "integrity": "sha512-9f1iZ2uWh92VcrU9Y8x+LdM4DLj75VE0MJB8zuF1iUnroEptStw+DQ8EQPMUdfe5k+PkB1uUfDQfWbhstH8LrQ==", + "license": "MIT" }, "node_modules/accessor-fn": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/accessor-fn/-/accessor-fn-1.5.3.tgz", "integrity": "sha512-rkAofCwe/FvYFUlMB0v0gWmhqtfAtV1IUkdPbfhTUyYniu5LrC0A0UJkTH0Jv3S8SvwkmfuAlY+mQIJATdocMA==", + "license": "MIT", "engines": { "node": ">=12" } @@ -7765,6 +7357,7 @@ "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -7776,6 +7369,7 @@ "version": "1.9.5", "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", "peerDependencies": { "acorn": "^8" } @@ -7785,6 +7379,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -7794,6 +7389,7 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", "dev": true, + "license": "MIT", "dependencies": { "acorn": "^8.11.0" }, @@ -7801,19 +7397,24 @@ "node": ">=0.4.0" } }, - "node_modules/addr-to-ip-port": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/addr-to-ip-port/-/addr-to-ip-port-2.0.0.tgz", - "integrity": "sha512-9bYbtjamtdLHZSqVIUXhilOryNPiL+x+Q5J/Unpg4VY3ZIkK3fT52UoErj1NdUeVm3J1t2iBEAur4Ywbl/bahw==", + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, "engines": { - "node": ">=12.20.0" + "node": ">= 6.0.0" } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -7830,6 +7431,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -7840,10 +7442,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -7852,6 +7468,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7865,12 +7482,14 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" }, "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" @@ -7883,6 +7502,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7893,22 +7513,26 @@ "node_modules/apg-lite": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/apg-lite/-/apg-lite-1.0.5.tgz", - "integrity": "sha512-SlI+nLMQDzCZfS39ihzjGp3JNBQfJXyMi6cg9tkLOCPVErgFsUIAEdO9IezR7kbP5Xd0ozcPNQBkf9TO5cHgWw==" + "integrity": "sha512-SlI+nLMQDzCZfS39ihzjGp3JNBQfJXyMi6cg9tkLOCPVErgFsUIAEdO9IezR7kbP5Xd0ozcPNQBkf9TO5cHgWw==", + "license": "BSD-2-Clause" }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" }, "node_modules/aria-hidden": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -7921,6 +7545,7 @@ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">= 0.4" } @@ -7930,6 +7555,7 @@ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" @@ -7946,6 +7572,7 @@ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -7968,6 +7595,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -7988,6 +7616,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -8009,6 +7638,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -8027,6 +7657,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -8045,6 +7676,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -8061,6 +7693,7 @@ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", @@ -8080,15 +7713,17 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" }, "node_modules/asn1js": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", - "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", + "license": "BSD-3-Clause", "dependencies": { "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", + "pvutils": "^1.1.5", "tslib": "^2.8.1" }, "engines": { @@ -8099,13 +7734,15 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -8114,6 +7751,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "license": "MIT", "dependencies": { "tslib": "^2.4.0" } @@ -8121,12 +7759,14 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/attr-accept": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==", + "license": "MIT", "engines": { "node": ">=4" } @@ -8135,6 +7775,7 @@ "version": "3.16.2", "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.16.2.tgz", "integrity": "sha512-JiYl7j2Z19F9NdTmirENSUUIIL/9MytEWtmzhfmsKPCp9E+G35Y0UNCMoM9tFigxT59qSc8Ml2dlZXOCVTYwuA==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" } @@ -8143,6 +7784,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -8154,21 +7796,24 @@ } }, "node_modules/axe-core": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", - "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.4.tgz", + "integrity": "sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==", "dev": true, + "license": "MPL-2.0", "engines": { "node": ">=4" } }, "node_modules/axios": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", - "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, @@ -8177,20 +7822,22 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">= 0.4" } }, "node_modules/babel-jest": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.3.0.tgz", - "integrity": "sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.4.1.tgz", + "integrity": "sha512-fATAbM8piYxkiXQp3RBXmZHxZVNJZAVXXfyeyCN2Tida3+qJ8ea9UxhiJ2y4fLO90ZImKt6k9FlcH2+rLkJGhw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/transform": "30.3.0", + "@jest/transform": "30.4.1", "@types/babel__core": "^7.20.5", "babel-plugin-istanbul": "^7.0.1", - "babel-preset-jest": "30.3.0", + "babel-preset-jest": "30.4.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" @@ -8207,6 +7854,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", "dev": true, + "license": "BSD-3-Clause", "workspaces": [ "test/babel-8" ], @@ -8222,10 +7870,11 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.3.0.tgz", - "integrity": "sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.4.0.tgz", + "integrity": "sha512-9EdtWM/sSfXLOGLwSn+GS6pIXyBnL07/8gyJlwFXjWy4DxMOyItqyUT29d4lQiS380EZwYlX7/At4PgBS+m2aA==", "dev": true, + "license": "MIT", "dependencies": { "@types/babel__core": "^7.20.5" }, @@ -8238,6 +7887,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -8260,12 +7910,13 @@ } }, "node_modules/babel-preset-jest": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.3.0.tgz", - "integrity": "sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.4.0.tgz", + "integrity": "sha512-lBY4jxsNmCnSiu7kquw8ZC9F4+XLMOKypT3RnNHPvU2Kpd4W0xaPuLr5ZkRyOsvLYAY4yaW1ZwTW4xB7NIiZzg==", "dev": true, + "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "30.3.0", + "babel-plugin-jest-hoist": "30.4.0", "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { @@ -8279,6 +7930,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -8288,30 +7940,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/bare-addon-resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz", - "integrity": "sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA==", - "optional": true, - "dependencies": { - "bare-module-resolve": "^1.10.0", - "bare-semver": "^1.0.0" - }, - "peerDependencies": { - "bare-url": "*" - }, - "peerDependenciesMeta": { - "bare-url": { - "optional": true - } - } + "dev": true, + "license": "MIT" }, "node_modules/bare-ansi-escapes": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/bare-ansi-escapes/-/bare-ansi-escapes-2.2.3.tgz", "integrity": "sha512-02ES4/E2RbrtZSnHJ9LntBhYkLA6lPpSEeP8iqS3MccBIVhVBlEmruF1I7HZqx5Q8aiTeYfQVeqmrU9YO2yYoQ==", + "license": "Apache-2.0", "dependencies": { "bare-stream": "^2.6.5" }, @@ -8328,6 +7964,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/bare-assert/-/bare-assert-1.2.0.tgz", "integrity": "sha512-c6uvgvTJBspTDxtVnPgrBKmLgcpW3Fp72NVKDLg6oT4QjQbhGtvrkHMhGYMK1sh4vjBHOBmuUalyt9hSzV37fQ==", + "license": "Apache-2.0", "dependencies": { "bare-inspect": "^3.1.2" } @@ -8336,14 +7973,16 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/bare-buffer/-/bare-buffer-3.6.0.tgz", "integrity": "sha512-/maRWEQ2eBkVNMbNFVsq1pHXJYVj4Y3AixwruB24eKZDs5Gtu0fixzvjYmBIuTsBMtVH5Yb27pQO9BhFa+IlIQ==", + "license": "Apache-2.0", "engines": { "bare": ">=1.20.0" } }, "node_modules/bare-crypto": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/bare-crypto/-/bare-crypto-1.13.4.tgz", - "integrity": "sha512-JiCZ5l2YOG1y8J7yy1BCAKTCZrPnHLb7pDRIdurBTOn5oIwBQDIv8iH5Pl2V85vzjl1NZXRfNY4HZLsE942jJA==", + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/bare-crypto/-/bare-crypto-1.13.7.tgz", + "integrity": "sha512-gvYgECS1X1wDXFuipwgrN1kwOovMP+BNpaSnRcKRZeT0wYrZIDf9H48BpdWd0t81nmCWtfbpKZhWBziUwLY05Q==", + "license": "Apache-2.0", "dependencies": { "bare-assert": "^1.2.0", "bare-stream": "^2.6.3" @@ -8361,14 +8000,16 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/bare-dns/-/bare-dns-2.1.4.tgz", "integrity": "sha512-abwjHmpWqSRNB7V5615QxPH92L71AVzFm/kKTs8VYiNTAi2xVdonpv0BjJ0hwXLwomoW+xsSOPjW6PZPO14asg==", + "license": "Apache-2.0", "engines": { "bare": ">=1.7.0" } }, "node_modules/bare-events": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", - "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz", + "integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==", + "license": "Apache-2.0", "peerDependencies": { "bare-abort-controller": "*" }, @@ -8379,13 +8020,15 @@ } }, "node_modules/bare-fetch": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/bare-fetch/-/bare-fetch-2.8.0.tgz", - "integrity": "sha512-xCBF6oKwzZmq+M6FGcAHv8Fn3XEXHeauLr6dfmr5IG07PFhabg1+r9eeVaIybPAqx8syF9M9+4r23QuDvh3Uvg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/bare-fetch/-/bare-fetch-2.9.1.tgz", + "integrity": "sha512-OqyubfnEXu9BqIVXg+LcdsutZk+amvPey2N+FeG7zeIk+0qarDreAMtixcRGvpR95rM1SNJedHRpBv3BNjja5g==", + "license": "Apache-2.0", "dependencies": { "bare-form-data": "^1.2.0", "bare-http1": "^4.5.2", - "bare-https": "^2.0.0", + "bare-https": "^3.0.0", + "bare-mime": "^1.0.0", "bare-stream": "^2.9.1", "bare-url": "^2.4.0", "bare-zlib": "^1.3.0" @@ -8404,46 +8047,26 @@ } }, "node_modules/bare-form-data": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bare-form-data/-/bare-form-data-1.2.1.tgz", - "integrity": "sha512-DFZhp5Tn0S7TjII/xhgLl2BNU6f7l5QbIW/YH7TjzQVnxLa8SaMSbl77jpy0ZR1oUnAo0a7NHJ9QAOU6PPr0Jg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bare-form-data/-/bare-form-data-1.2.2.tgz", + "integrity": "sha512-DQyAkCf5mgKT07orewuvaJfoalw7RBSHia4wgkrG7+seI6aHLB+r6gMRdCGrlO+BmCqMwgTeHAHxDU2NrOjQnQ==", + "license": "Apache-2.0", "dependencies": { "bare-buffer": "^3.6.0", "bare-stream": "^2.6.5" } }, - "node_modules/bare-fs": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.6.tgz", - "integrity": "sha512-1QovqDrR80Pmt5HPAsMsXTCFcDYr+NSUKW6nd6WO5v0JBmnItc/irNRzm2KOQ5oZ69P37y+AMujNyNtG+1Rggw==", - "dependencies": { - "bare-events": "^2.5.4", - "bare-path": "^3.0.0", - "bare-stream": "^2.6.4", - "bare-url": "^2.2.2", - "fast-fifo": "^1.3.2" - }, - "engines": { - "bare": ">=1.16.0" - }, - "peerDependencies": { - "bare-buffer": "*" - }, - "peerDependenciesMeta": { - "bare-buffer": { - "optional": true - } - } - }, "node_modules/bare-http-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/bare-http-parser/-/bare-http-parser-1.1.3.tgz", - "integrity": "sha512-+dhVvQi6brHq14L/XHNRQ+TLuVE76VjRmMt61wVEtS+Od8xUslfMHWJN/ZjIIt3RtTG6vPuA+x9cOh7KrkBJsA==" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bare-http-parser/-/bare-http-parser-1.1.4.tgz", + "integrity": "sha512-DL+7fTEUWzAEj/Baw9e/BwNAidARbxuUf5bonQ/Wt3VPUdJNyf562ydaono9ZkQBAUw0NydzYEI97rSs/93ruA==", + "license": "Apache-2.0" }, "node_modules/bare-http1": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/bare-http1/-/bare-http1-4.5.5.tgz", - "integrity": "sha512-ADITiRo0huP76JGMbv6Arsh9KehHqjEBoYcmjvAo67IY78+/9mV2MeKLLCkiJSFxA85T/m8cTaE44OwJQCcwdw==", + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/bare-http1/-/bare-http1-4.5.6.tgz", + "integrity": "sha512-31OAwMkSU+z1VuUOCk65hx3aWQgzCfH/zQ6LGxbJtmiy2Czsw0+uvOBM9YkqaL6zUSTSYG2pLbL0v/TjME3Buw==", + "license": "Apache-2.0", "dependencies": { "bare-events": "^2.6.0", "bare-http-parser": "^1.1.1", @@ -8464,19 +8087,21 @@ } }, "node_modules/bare-https": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-https/-/bare-https-2.1.3.tgz", - "integrity": "sha512-0TI/mJXQGYXmG7UUyWEG+KCJusayIAQLywUjFAskDoKuxfqVnGF+M/mTMrEV8J64DaIdU+5x761FvgmT7M68tA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-https/-/bare-https-3.0.0.tgz", + "integrity": "sha512-W1GRSCzn+xXKf5bMcPs/hg6Ga1bxPqb7owGfS+tvlBQfPe5Q2STcanRuKZrgU60v5uKrhXH5cgWwM+DLqvXZgQ==", + "license": "Apache-2.0", "dependencies": { "bare-http1": "^4.4.0", "bare-tcp": "^2.2.0", - "bare-tls": "^2.0.0" + "bare-tls": "^3.0.0" } }, "node_modules/bare-inspect": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/bare-inspect/-/bare-inspect-3.1.4.tgz", "integrity": "sha512-jfW5KRA84o3REpI6Vr4nbvMn+hqVAw8GU1mMdRwUsY5yJovQamxYeKGVKGqdzs+8ZbG4jRzGUXP/3Ji/DnqfPg==", + "license": "Apache-2.0", "dependencies": { "bare-ansi-escapes": "^2.1.0", "bare-type": "^1.0.0" @@ -8485,27 +8110,17 @@ "bare": ">=1.18.0" } }, - "node_modules/bare-module-resolve": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz", - "integrity": "sha512-hbmAPyFpEq8FoZMd5sFO3u6MC5feluWoGE8YKlA8fCrl6mNtx68Wjg4DTiDJcqRJaovTvOYKfYngoBUnbaT7eg==", - "optional": true, - "dependencies": { - "bare-semver": "^1.0.0" - }, - "peerDependencies": { - "bare-url": "*" - }, - "peerDependenciesMeta": { - "bare-url": { - "optional": true - } - } - }, + "node_modules/bare-mime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bare-mime/-/bare-mime-1.0.0.tgz", + "integrity": "sha512-lUOswzBkfqham4zjLDueKOd4Qj3gS56BiZ3q2f0g0adoFhF+HFNupvTUfZBWoicl7fWJ7Hp2RUZjmkY47dxxOQ==", + "license": "Apache-2.0" + }, "node_modules/bare-net": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.3.1.tgz", "integrity": "sha512-MypSqDKpDU2Xt7FIfazn5yGvRnV09gFcIPHGWstW0gxuzA4tucTcwJSZeos97C4F89vtU5oGwXDN/HrGN6Y4Jw==", + "license": "Apache-2.0", "dependencies": { "bare-events": "^2.2.2", "bare-pipe": "^4.0.0", @@ -8514,9 +8129,10 @@ } }, "node_modules/bare-os": { - "version": "3.8.6", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.6.tgz", - "integrity": "sha512-l8xaNWWb/bXuzgsrlF5jaa5QYDJ9S0ddd54cP6CH+081+5iPrbJiCfBWQqrWYzmUhCbsH+WR6qxo9MeHVCr0MQ==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", + "license": "Apache-2.0", "engines": { "bare": ">=1.14.0" } @@ -8525,6 +8141,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", "dependencies": { "bare-os": "^3.0.1" } @@ -8533,6 +8150,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.1.5.tgz", "integrity": "sha512-6OfxaG8JSkRh3Gc4hzHRsxNt+yu2PpN7lrv1V+T78GdknWQkVGwiEvu4m+1nbfk8cMVQ0TGxRvQ90XA4rhnTuw==", + "license": "Apache-2.0", "dependencies": { "bare-events": "^2.0.0", "bare-stream": "^2.0.0" @@ -8541,16 +8159,11 @@ "bare": ">=1.16.0" } }, - "node_modules/bare-semver": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.2.tgz", - "integrity": "sha512-ESVaN2nzWhcI5tf3Zzcq9aqCZ676VWzqw07eEZ0qxAcEOAFYBa0pWq8sK34OQeHLY3JsfKXZS9mDyzyxGjeLzA==", - "optional": true - }, "node_modules/bare-stream": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.11.0.tgz", - "integrity": "sha512-Y/+iQ49fL3rIn6w/AVxI/2+BRrpmzJvdWt5Jv8Za6Ngqc6V227c+pYjYYgLdpR3MwQ9ObVXD0ZrqoBztakM0rw==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", + "license": "Apache-2.0", "dependencies": { "streamx": "^2.25.0", "teex": "^1.0.1" @@ -8572,20 +8185,11 @@ } } }, - "node_modules/bare-stream/node_modules/streamx": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", - "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", - "dependencies": { - "events-universal": "^1.0.0", - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - } - }, "node_modules/bare-tcp": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.2.7.tgz", - "integrity": "sha512-rjpqNQ2cOCkNo3NeYA/W4GTK3DRkl8sDHO3uos+AEswUjLC8XXMQF8WrJCSjlIowCbS6NUVxKE92X5RGXjyefg==", + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.2.13.tgz", + "integrity": "sha512-4KQPgqYugvK6QxcSnVGbl87XslBebxmXlv7Glf4M9iwwoSCDKtYmC1t6zsMctTNhzKXbWCId7mB4R9qLWj3JMw==", + "license": "Apache-2.0", "dependencies": { "bare-dns": "^2.0.4", "bare-events": "^2.5.4", @@ -8596,9 +8200,10 @@ } }, "node_modules/bare-tls": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bare-tls/-/bare-tls-2.2.1.tgz", - "integrity": "sha512-hZ+ZqwrUO4dyH7/6WYkYWjgAFNJKjzwEYJiDaMnMs+eRleBDjQ3CvNZawpkw0Ar9jnM9NZK6+f6GqjkZ2FLGmQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/bare-tls/-/bare-tls-3.1.5.tgz", + "integrity": "sha512-yoOtW3MyJF1mMwavLeuqOE7+qTKZ9cl1GRPxCUOXMUvYCfGltvXyRH48R4EKrRIfgUG6vil6n4Ea1i81fwmgZA==", + "license": "Apache-2.0", "dependencies": { "bare-net": "^2.0.1", "bare-stream": "^2.6.4" @@ -8611,43 +8216,40 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/bare-type/-/bare-type-1.1.0.tgz", "integrity": "sha512-LdtnnEEYldOc87Dr4GpsKnStStZk3zfgoEMXy8yvEZkXrcCv9RtYDrUYWFsBQHtaB0s1EUWmcvS6XmEZYIj3Bw==", + "license": "Apache-2.0", "engines": { "bare": ">=1.2.0" } }, "node_modules/bare-url": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz", - "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.3.tgz", + "integrity": "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==", + "license": "Apache-2.0", "dependencies": { "bare-path": "^3.0.0" } }, "node_modules/bare-zlib": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/bare-zlib/-/bare-zlib-1.3.1.tgz", - "integrity": "sha512-VP93GFzhrTdWh9mXNocn7XsP/nF5JQluiiSsbTvsQ4yIYlhEHRMF9lQmZZDXwzK9PNYaVGUV1bdQuqp0Mj7MHw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/bare-zlib/-/bare-zlib-1.3.3.tgz", + "integrity": "sha512-rXNczo+SQg6cn20olmh/mUiGeJK9maipFH/zI/QwYgwhEmOns1R7fl1GV5apNO+aAp4x2d4uUa7HLhO4mhOnBQ==", + "license": "Apache-2.0", "dependencies": { "bare-stream": "^2.0.0" } }, "node_modules/base-x": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", - "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz", + "integrity": "sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==", + "license": "MIT" }, "node_modules/base32-encoding": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base32-encoding/-/base32-encoding-1.0.0.tgz", - "integrity": "sha512-k1gA7f00ODLY7YtuEQFz0Kn3huTCmL/JW+oQtw51ID+zxs5chj/YQ1bXN+Q0JsqiKB2Yn0oA0AA8uipFYgpagQ==" - }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "engines": { - "node": ">= 0.6.0" - } + "integrity": "sha512-k1gA7f00ODLY7YtuEQFz0Kn3huTCmL/JW+oQtw51ID+zxs5chj/YQ1bXN+Q0JsqiKB2Yn0oA0AA8uipFYgpagQ==", + "license": "ISC" }, "node_modules/base64-js": { "version": "1.5.1", @@ -8666,12 +8268,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz", - "integrity": "sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==", + "version": "2.10.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", + "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==", + "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" }, @@ -8682,37 +8286,21 @@ "node_modules/bech32": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", - "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==", + "license": "MIT" }, "node_modules/before-after-hook": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", - "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==" - }, - "node_modules/bencode": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bencode/-/bencode-4.0.0.tgz", - "integrity": "sha512-AERXw18df0pF3ziGOCyUjqKZBVNH8HV3lBxnx5w0qtgMIk4a1wb9BkcCQbkp9Zstfrn/dzRwl7MmUHHocX3sRQ==", - "dependencies": { - "uint8-util": "^2.2.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/bep53-range": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bep53-range/-/bep53-range-2.0.0.tgz", - "integrity": "sha512-sMm2sV5PRs0YOVk0LTKtjuIprVzxgTQUsrGX/7Yph2Rm4FO2Fqqtq7hNjsOB5xezM4v4+5rljCgK++UeQJZguA==", - "engines": { - "node": ">=12.20.0" - } + "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", + "license": "Apache-2.0" }, "node_modules/bidi-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", "dev": true, + "license": "MIT", "dependencies": { "require-from-string": "^2.0.2" } @@ -8721,6 +8309,7 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", "engines": { "node": "*" } @@ -8729,6 +8318,7 @@ "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" }, @@ -8736,19 +8326,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/bip174": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bip174/-/bip174-3.0.0.tgz", "integrity": "sha512-N3vz3rqikLEu0d6yQL8GTrSkpYb35NQKWMR7Hlza0lOj6ZOlvQ3Xr7N9Y+JPebaCVoEUHdBeBSuLxcHr71r+Lw==", + "license": "MIT", "dependencies": { "uint8array-tools": "^0.0.9", "varuint-bitcoin": "^2.0.0" @@ -8761,349 +8343,75 @@ "version": "0.0.9", "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.9.tgz", "integrity": "sha512-9vqDWmoSXOoi+K14zNaf6LBV51Q8MayF0/IiQs3GlygIKUYtog603e6virExkjjFosfJUBI4LhbQK1iq8IG11A==", + "license": "MIT", "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/bip32": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz", - "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==", - "dependencies": { - "@noble/hashes": "^1.2.0", - "@scure/base": "^1.1.1", - "typeforce": "^1.11.5", - "wif": "^2.0.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/bip39": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", - "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", - "dependencies": { - "@noble/hashes": "^1.2.0" - } - }, - "node_modules/bitcoinjs-lib": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.7.tgz", - "integrity": "sha512-tlf/r2DGMbF7ky1MgUqXHzypYHakkEnm0SZP23CJKIqNY/5uNAnMbFhMJdhjrL/7anfb/U8+AlpdjPWjPnAalg==", - "dependencies": { - "@noble/hashes": "^1.2.0", - "bech32": "^2.0.0", - "bip174": "^2.1.1", - "bs58check": "^3.0.1", - "typeforce": "^1.11.3", - "varuint-bitcoin": "^1.1.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/bitcoinjs-lib/node_modules/base-x": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz", - "integrity": "sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==" - }, - "node_modules/bitcoinjs-lib/node_modules/bip174": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.1.tgz", - "integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ==", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/bitcoinjs-lib/node_modules/bs58": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", - "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", - "dependencies": { - "base-x": "^4.0.0" - } - }, - "node_modules/bitcoinjs-lib/node_modules/bs58check": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", - "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", - "dependencies": { - "@noble/hashes": "^1.2.0", - "bs58": "^5.0.0" - } - }, - "node_modules/bitcoinjs-lib/node_modules/varuint-bitcoin": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", - "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", - "dependencies": { - "safe-buffer": "^5.1.1" - } - }, - "node_modules/bitfield": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/bitfield/-/bitfield-4.2.0.tgz", - "integrity": "sha512-kUTatQb/mBd8uhvdLrUkouGDBUQiJaIOvPlptUwOWp6MFqih4d1MiVf0m3ATxfZSzu+LjW/awFeABltYa62uIA==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/bittorrent-dht": { - "version": "11.0.11", - "resolved": "https://registry.npmjs.org/bittorrent-dht/-/bittorrent-dht-11.0.11.tgz", - "integrity": "sha512-5rWMoK/2XjcPSx9nfqiL6mHxsXLwohX+81aL4a3qUyGU1992mBqARQE/evZ+a6eWb5DeRjeDU+qFZm11rmPZnQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "bencode": "^4.0.0", - "debug": "^4.4.3", - "k-bucket": "^5.1.0", - "k-rpc": "^5.1.0", - "last-one-wins": "^1.0.4", - "lru": "^3.1.0", - "randombytes": "^2.1.0", - "record-cache": "^1.2.0" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/bittorrent-lsd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bittorrent-lsd/-/bittorrent-lsd-2.0.0.tgz", - "integrity": "sha512-jV+SMTGNY1iGWjf5cPA2HMeA6axuMQRWwWELtsuZ1FmQmZwC74we92nwtDTfv1WMnLx+oqEjWRri42IHjZitSQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "chrome-dgram": "^3.0.6", - "debug": "^4.2.0" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/bittorrent-peerid": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/bittorrent-peerid/-/bittorrent-peerid-1.3.6.tgz", - "integrity": "sha512-VyLcUjVMEOdSpHaCG/7odvCdLbAB1y3l9A2V6WIje24uV7FkJPrQrH/RrlFmKxP89pFVDEnE+YlHaFujlFIZsg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bittorrent-protocol": { - "version": "4.1.21", - "resolved": "https://registry.npmjs.org/bittorrent-protocol/-/bittorrent-protocol-4.1.21.tgz", - "integrity": "sha512-CcuPt6BL7gXa8BF+0GckYcQmr44ARfSPM0rYwMeYgWg+jftekWgy5vuxX6wJDpC5bKFvqNG+74bPBjyM7Swxrw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "bencode": "^4.0.0", - "bitfield": "^4.2.0", - "debug": "^4.4.3", - "rc4": "^0.1.5", - "streamx": "^2.22.1", - "throughput": "^1.0.2", - "uint8-util": "^2.2.5", - "unordered-array-remove": "^1.0.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/bittorrent-tracker": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/bittorrent-tracker/-/bittorrent-tracker-11.2.2.tgz", - "integrity": "sha512-pVjpd6tPtLByrYwtDOo+cVx9zQZ2XUvlaWrlm57+9yvVDKHuNL+TFEAtyfXuIutghG7Bde/uWXGfoVWpPYY+8A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "@thaunknown/simple-peer": "^10.0.8", - "@thaunknown/simple-websocket": "^9.1.3", - "bencode": "^4.0.0", - "bittorrent-peerid": "^1.3.6", - "chrome-dgram": "^3.0.6", - "compact2string": "^1.4.1", - "cross-fetch-ponyfill": "^1.0.3", - "debug": "^4.3.4", - "ip": "^2.0.1", - "lru": "^3.1.0", - "minimist": "^1.2.8", - "once": "^1.4.0", - "queue-microtask": "^1.2.3", - "random-iterate": "^1.0.1", - "run-parallel": "^1.2.0", - "run-series": "^1.1.9", - "socks": "^2.8.3", - "string2compact": "^2.0.1", - "uint8-util": "^2.2.5", - "unordered-array-remove": "^1.0.2", - "ws": "^8.17.0" - }, - "bin": { - "bittorrent-tracker": "bin/cmd.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "optionalDependencies": { - "bufferutil": "^4.0.8", - "utf-8-validate": "^6.0.4" + "node": ">=14.0.0" } }, - "node_modules/bittorrent-tracker/node_modules/utf-8-validate": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.6.tgz", - "integrity": "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==", - "hasInstallScript": true, - "optional": true, + "node_modules/bip32": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz", + "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==", + "license": "MIT", "dependencies": { - "node-gyp-build": "^4.3.0" + "@noble/hashes": "^1.2.0", + "@scure/base": "^1.1.1", + "typeforce": "^1.11.5", + "wif": "^2.0.6" }, "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/bittorrent-tracker/node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "node": ">=6.0.0" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/bip39": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", + "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", + "license": "ISC", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "@noble/hashes": "^1.2.0" } }, - "node_modules/bl/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/bitcoinjs-lib": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.7.tgz", + "integrity": "sha512-tlf/r2DGMbF7ky1MgUqXHzypYHakkEnm0SZP23CJKIqNY/5uNAnMbFhMJdhjrL/7anfb/U8+AlpdjPWjPnAalg==", + "license": "MIT", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "@noble/hashes": "^1.2.0", + "bech32": "^2.0.0", + "bip174": "^2.1.1", + "bs58check": "^3.0.1", + "typeforce": "^1.11.3", + "varuint-bitcoin": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, + "node_modules/bitcoinjs-lib/node_modules/bip174": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.1.tgz", + "integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ==", + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=8.0.0" } }, - "node_modules/bl/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/bitcoinjs-lib/node_modules/varuint-bitcoin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", + "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "^5.1.1" } }, "node_modules/blake2b": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz", "integrity": "sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==", + "license": "ISC", "dependencies": { "blake2b-wasm": "^2.4.0", "nanoassert": "^2.0.0" @@ -9113,15 +8421,17 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz", "integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==", + "license": "MIT", "dependencies": { "b4a": "^1.0.1", "nanoassert": "^2.0.0" } }, "node_modules/blake2b-wasm/node_modules/b4a": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" }, @@ -9134,23 +8444,21 @@ "node_modules/blakejs": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" - }, - "node_modules/block-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/block-iterator/-/block-iterator-1.1.2.tgz", - "integrity": "sha512-yAHUP44v2K25xLPdrgVTgwtuQctlullzjczu9CoUZom5AP3g4p1R1+aWHjS1GHG9JtcSUVUnbEPiuXiW5YZ24w==" + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "license": "MIT" }, "node_modules/bn.js": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==" + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -9160,6 +8468,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -9168,9 +8477,10 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -9185,12 +8495,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -9204,6 +8515,7 @@ "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, + "license": "MIT", "dependencies": { "fast-json-stable-stringify": "2.x" }, @@ -9212,20 +8524,22 @@ } }, "node_modules/bs58": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", - "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "license": "MIT", "dependencies": { - "base-x": "^5.0.0" + "base-x": "^4.0.0" } }, "node_modules/bs58check": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", - "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", + "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", + "license": "MIT", "dependencies": { "@noble/hashes": "^1.2.0", - "bs58": "^6.0.0" + "bs58": "^5.0.0" } }, "node_modules/bser": { @@ -9233,6 +8547,7 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } @@ -9255,6 +8570,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -9263,26 +8579,15 @@ "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/bufferutil": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", - "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } + "dev": true, + "license": "MIT" }, "node_modules/busboy": { "version": "1.6.0", @@ -9300,6 +8605,7 @@ "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", "devOptional": true, + "license": "MIT", "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", @@ -9323,37 +8629,15 @@ } } }, - "node_modules/cache-chunk-store": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/cache-chunk-store/-/cache-chunk-store-3.2.2.tgz", - "integrity": "sha512-2lJdWbgHFFxcSth9s2wpId3CR3v1YC63KjP4T9WhpW7LWlY7Hiiei3QwwqzkWqlJTfR8lSy9F5kRQECeyj+yQA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "lru": "^3.1.0", - "queue-microtask": "^1.2.3" - } - }, "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" }, "engines": { @@ -9367,6 +8651,7 @@ "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==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -9379,6 +8664,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" @@ -9393,13 +8679,15 @@ "node_modules/call-me-maybe": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "license": "MIT" }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -9409,6 +8697,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -9417,6 +8706,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", "engines": { "node": ">= 6" } @@ -9426,14 +8716,15 @@ "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.10.1.tgz", "integrity": "sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==", "dev": true, + "license": "MIT", "peerDependencies": { "three": ">=0.126.1" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001782", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz", - "integrity": "sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "funding": [ { "type": "opencollective", @@ -9447,12 +8738,14 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/canonicalize": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-2.1.0.tgz", "integrity": "sha512-F705O3xrsUtgt98j7leetNhTWPe+5S72rlL5O4jA1pKqBVQ/dT1O1D6PFxmSXvc0SUOinWS57DKx0I3CHrXJHQ==", + "license": "Apache-2.0", "bin": { "canonicalize": "bin/canonicalize.js" } @@ -9461,6 +8754,7 @@ "version": "2.1.13", "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==", + "license": "MIT", "engines": { "node": ">=12.13" }, @@ -9472,6 +8766,7 @@ "version": "10.0.12", "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.12.tgz", "integrity": "sha512-exQDevYd7ZQLP4moMQcZkKCVZsXLAtUSflObr3xTh4xzFIv/xBCdvCd6L259kQOUP2kcTC0jvC6PpZIf/WmRXA==", + "license": "MIT", "dependencies": { "nofilter": "^3.0.2" }, @@ -9483,6 +8778,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -9492,6 +8788,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/chacha/-/chacha-2.1.0.tgz", "integrity": "sha512-FhVtqaZOiHlOKUkAWfDlJ+oe/O8iPQbCC0pFXJqphr4YQBCZPXa8Mv3j35+W4eWFWCoTUcW2u5IWDDkknygvVA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "readable-stream": "^1.0.33" @@ -9500,23 +8797,12 @@ "chacha-native": "^2.0.0" } }, - "node_modules/chacha-native": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/chacha-native/-/chacha-native-2.0.3.tgz", - "integrity": "sha512-93h+osfjhR2sMHAaapTLlL/COoBPEZ6upicPBQ4GfUyadoMb8t9/M0PKK8kC+F+DEA/Oy3Kg9w3HzY3J1foP3g==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "bindings": "^1.2.1", - "inherits": "^2.0.1", - "nan": "^2.4.0" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9533,6 +8819,7 @@ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -9541,6 +8828,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -9550,108 +8838,46 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "devOptional": true, - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "node_modules/chrome-dgram": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/chrome-dgram/-/chrome-dgram-3.0.6.tgz", - "integrity": "sha512-bqBsUuaOiXiqxXt/zA/jukNJJ4oaOtc7ciwqJpZVEaaXwwxqgI2/ZdG02vXYWUhHGziDlvGMQWk0qObgJwVYKA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "inherits": "^2.0.4", - "run-series": "^1.1.9" - } - }, - "node_modules/chrome-dns": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chrome-dns/-/chrome-dns-1.0.1.tgz", - "integrity": "sha512-HqsYJgIc8ljJJOqOzLphjAs79EUuWSX3nzZi2LNkzlw3GIzAeZbaSektC8iT/tKvLqZq8yl1GJu5o6doA4TRbg==", - "dependencies": { - "chrome-net": "^3.3.2" - } - }, - "node_modules/chrome-net": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/chrome-net/-/chrome-net-3.3.4.tgz", - "integrity": "sha512-Jzy2EnzmE+ligqIZUsmWnck9RBXLuUy6CaKyuNMtowFG3ZvLt8d+WBJCTPEludV0DHpIKjAOlwjFmTaEdfdWCw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "inherits": "^2.0.1" + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chunk-store-iterator": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chunk-store-iterator/-/chunk-store-iterator-1.0.4.tgz", - "integrity": "sha512-LGjzJNmk7W1mrdaBoJNztPumT2ACmgjHmI1AMm8aeGYOl4+LKaYC/yfnx27i++LiAtoe/dR+3jC8HRzb6gW4/A==", + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", "dependencies": { - "block-iterator": "^1.1.1" + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/ci-info": { @@ -9665,6 +8891,7 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } @@ -9673,6 +8900,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", @@ -9687,6 +8915,7 @@ "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", "devOptional": true, + "license": "MIT", "dependencies": { "consola": "^3.2.3" } @@ -9695,12 +8924,14 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", "dependencies": { "clsx": "^2.1.1" }, @@ -9711,17 +8942,20 @@ "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -9735,6 +8969,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -9744,6 +8979,7 @@ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -9753,12 +8989,14 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -9769,12 +9007,14 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -9786,6 +9026,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -9795,35 +9036,31 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", + "license": "MIT", "engines": { "node": ">= 6" } }, - "node_modules/compact2string": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/compact2string/-/compact2string-1.4.1.tgz", - "integrity": "sha512-3D+EY5nsRhqnOwDxveBv5T8wGo4DEvYxjDtPGmdOX+gfr5gE92c2RC0w2wa+xEefm07QuVqqcF3nZJUZ92l/og==", - "dependencies": { - "ipaddr.js": ">= 0.1.5" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/confbox": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/consola": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "devOptional": true, + "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" } @@ -9831,12 +9068,15 @@ "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==" + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "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" } @@ -9845,6 +9085,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "license": "MIT", "dependencies": { "is-what": "^5.2.0" }, @@ -9859,6 +9100,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", "dependencies": { "toggle-selection": "^1.0.6" } @@ -9868,6 +9110,7 @@ "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.49.0.tgz", "integrity": "sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==", "hasInstallScript": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -9876,12 +9119,14 @@ "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==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" }, "node_modules/cors": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -9894,29 +9139,11 @@ "url": "https://opencollective.com/express" } }, - "node_modules/cpus": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cpus/-/cpus-1.0.3.tgz", - "integrity": "sha512-PXHBvGLuL69u55IkLa5e5838fLhIMHxmkV4ge42a8alGyn7BtawYgI0hQ849EedvtHIOLNNH3i6eQU1BiE9SUA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -9929,6 +9156,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -9938,50 +9166,12 @@ "sha.js": "^2.4.8" } }, - "node_modules/create-torrent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/create-torrent/-/create-torrent-6.1.0.tgz", - "integrity": "sha512-War593HCsg4TotHgMGWTJqnDHN0pmEU2RM13xUzzSZ78TpRNOC2bbcsC5yMO3pqIkedHEWFzYNqH1yhwuuBYTg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "bencode": "^4.0.0", - "block-iterator": "^1.1.1", - "fast-readable-async-iterator": "^2.0.0", - "is-file": "^1.0.0", - "join-async-iterator": "^1.1.1", - "junk": "^4.0.1", - "minimist": "^1.2.8", - "once": "^1.4.0", - "piece-length": "^2.0.1", - "queue-microtask": "^1.2.3", - "run-parallel": "^1.2.0", - "uint8-util": "^2.2.5" - }, - "bin": { - "create-torrent": "bin/cmd.js" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.1" }, @@ -9999,40 +9189,16 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", "dependencies": { "node-fetch": "^2.7.0" } }, - "node_modules/cross-fetch-ponyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cross-fetch-ponyfill/-/cross-fetch-ponyfill-1.0.3.tgz", - "integrity": "sha512-uOBkDhUAGAbx/FEzNKkOfx3w57H8xReBBXoZvUnOKTI0FW0Xvrj3GrYv2iZXUqlffC1LMGfQzhmBM/ke+6eTDA==", - "dependencies": { - "abort-controller": "^3.0.0", - "node-fetch": "^3.3.0" - } - }, - "node_modules/cross-fetch-ponyfill/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -10045,12 +9211,14 @@ "node_modules/css.escape": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "license": "MIT" }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -10061,12 +9229,14 @@ "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" }, "node_modules/d3-array": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "dependencies": { "internmap": "1 - 2" }, @@ -10078,6 +9248,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -10086,6 +9257,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", "dependencies": { "delaunator": "5" }, @@ -10097,6 +9269,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { "node": ">=12" } @@ -10105,6 +9278,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -10113,6 +9287,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", "dependencies": { "d3-array": "2.5.0 - 3" }, @@ -10124,6 +9299,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/d3-geo-voronoi/-/d3-geo-voronoi-2.1.0.tgz", "integrity": "sha512-kqE4yYuOjPbKdBXG0xztCacPwkVSK2REF1opSNrnqqtXJmNcM++UbwQ8SxvwP6IQTj9RvIjjK4qeiVsEfj0Z2Q==", + "license": "ISC", "dependencies": { "d3-array": "3", "d3-delaunay": "6", @@ -10138,6 +9314,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3" }, @@ -10148,12 +9325,14 @@ "node_modules/d3-octree": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-octree/-/d3-octree-1.1.0.tgz", - "integrity": "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==" + "integrity": "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==", + "license": "MIT" }, "node_modules/d3-path": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "engines": { "node": ">=12" } @@ -10162,6 +9341,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -10177,6 +9357,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" @@ -10189,6 +9370,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "dependencies": { "d3-path": "^3.1.0" }, @@ -10200,6 +9382,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", "dependencies": { "d3-array": "2 - 3" }, @@ -10211,6 +9394,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { "d3-time": "1 - 3" }, @@ -10222,6 +9406,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -10230,6 +9415,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-tricontour/-/d3-tricontour-1.1.0.tgz", "integrity": "sha512-G7gHKj89n2owmkGb6WX6ixcnQ0Kf/0wpa9VIh9DGdbHu8wdrlaHU4ir3/bFNERl8N8nn4G7e7qbtBG8N9caihQ==", + "license": "ISC", "dependencies": { "d3-delaunay": "6", "d3-scale": "4" @@ -10242,12 +9428,14 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/data-bind-mapper": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/data-bind-mapper/-/data-bind-mapper-1.0.3.tgz", "integrity": "sha512-QmU3lyEnbENQPo0M1F9BMu4s6cqNNp8iJA+b/HP2sSb7pf3dxwF3+EP1eO69rwBfH9kFJ1apmzrtogAmVt2/Xw==", + "license": "MIT", "dependencies": { "accessor-fn": "1" }, @@ -10255,19 +9443,12 @@ "node": ">=12" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -10285,6 +9466,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -10302,6 +9484,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -10317,18 +9500,21 @@ "node_modules/dayjs": { "version": "1.11.20", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", - "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==" + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "license": "MIT" }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -10344,12 +9530,14 @@ "node_modules/decimal.js-light": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", - "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" }, "node_modules/decode-named-character-reference": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", "dependencies": { "character-entities": "^2.0.0" }, @@ -10358,25 +9546,12 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", "dev": true, + "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -10390,155 +9565,42 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", "engines": { "node": ">=4.0.0" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deepmerge-ts": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", - "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", - "devOptional": true, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/default-gateway": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-7.2.2.tgz", - "integrity": "sha512-AD7TrdNNPXRZIGw63dw+lnGmT4v7ggZC5NHNJgAYWm5njrwoze1q5JSAW9YuLy2tjnoLUG/r8FEB93MCh9QJPg==", - "dependencies": { - "execa": "^7.1.1" - }, - "engines": { - "node": ">= 16" - } - }, - "node_modules/default-gateway/node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-gateway/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/default-gateway/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/default-gateway/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/default-gateway/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16.0.0" } }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -10556,6 +9618,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -10569,15 +9632,17 @@ } }, "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "devOptional": true + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "devOptional": true, + "license": "MIT" }, "node_modules/delaunator": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", "dependencies": { "robust-predicates": "^3.0.2" } @@ -10586,6 +9651,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -10594,6 +9660,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -10602,7 +9669,8 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/detect-europe-js": { "version": "0.1.2", @@ -10621,13 +9689,15 @@ "type": "paypal", "url": "https://paypal.me/faisalman" } - ] + ], + "license": "MIT" }, "node_modules/detect-gpu": { "version": "5.0.70", "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz", "integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==", "dev": true, + "license": "MIT", "dependencies": { "webgl-constants": "^1.1.1" } @@ -10636,6 +9706,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, "engines": { "node": ">=8" } @@ -10645,6 +9717,7 @@ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10652,12 +9725,14 @@ "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", "dependencies": { "dequal": "^2.0.0" }, @@ -10667,14 +9742,16 @@ } }, "node_modules/dexie": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.4.1.tgz", - "integrity": "sha512-4Xec5+yrS+TgyFAnMrneFOt/QG8sD3FxlkUVpfypui3SriRN80UN0SZBWmkNAY7ulfKgk0ilvv7M6pBURprdgA==" + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.4.2.tgz", + "integrity": "sha512-zMtV8q79EFE5U8FKZvt0Y/77PCU/Hr/RDxv1EDeo228L+m/HTbeN2AjoQm674rhQCX8n3ljK87lajt7UQuZfvw==", + "license": "Apache-2.0" }, "node_modules/dezalgo": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "license": "ISC", "dependencies": { "asap": "^2.0.0", "wrappy": "1" @@ -10683,18 +9760,21 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -10706,6 +9786,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" @@ -10717,9 +9798,10 @@ "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" }, "node_modules/dompurify": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", - "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.5.tgz", + "integrity": "sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==", + "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" } @@ -10729,6 +9811,7 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "devOptional": true, + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -10740,6 +9823,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz", "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==", + "license": "MIT", "dependencies": { "detect-libc": "^1.0.3" } @@ -10748,6 +9832,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -10759,12 +9844,14 @@ "version": "1.5.7", "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/drange": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==", + "license": "MIT", "engines": { "node": ">=4" } @@ -10773,6 +9860,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -10786,17 +9874,20 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/earcut": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", - "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==" + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", + "license": "ISC" }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" } @@ -10805,6 +9896,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz", "integrity": "sha512-cL/mh3MtJutFOvFc27GPZE2pWL3a3k4YvzUWEOvilnfZVlH3Jwgx/7d6tlD7/75tNk8TG2m+7Kgtz0SI1tWcqw==", + "license": "MIT", "dependencies": { "randombytes": "^2.1.0", "typeforce": "^1.18.0", @@ -10815,25 +9907,29 @@ } }, "node_modules/effect": { - "version": "3.18.4", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", - "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.21.0.tgz", + "integrity": "sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ==", "devOptional": true, + "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "node_modules/electron-to-chromium": { - "version": "1.5.328", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.328.tgz", - "integrity": "sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==" + "version": "1.5.361", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.361.tgz", + "integrity": "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==", + "dev": true, + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -10845,44 +9941,35 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/empathic": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=14" } }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", @@ -10950,6 +10037,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -10958,20 +10046,22 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-iterator-helpers": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.1.tgz", - "integrity": "sha512-zWwRvqWiuBPr0muUG/78cW3aHROFCNIQ3zpmYDpwdbnt2m+xlNyRWpHBpa2lJjSBit7BQ+RXA1iwbSmu5yJ/EQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", + "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", + "call-bind": "^1.0.9", "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.24.1", + "es-abstract": "^1.24.2", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", @@ -10983,17 +10073,17 @@ "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", - "math-intrinsics": "^1.1.0", - "safe-array-concat": "^1.1.3" + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { - "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==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -11005,6 +10095,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", @@ -11020,6 +10111,7 @@ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -11032,6 +10124,7 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", @@ -11048,20 +10141,17 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "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==" - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11074,6 +10164,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -11129,12 +10220,13 @@ } }, "node_modules/eslint-config-next": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.1.tgz", - "integrity": "sha512-qhabwjQZ1Mk53XzXvmogf8KQ0tG0CQXF0CZ56+2/lVhmObgmaqj7x5A1DSrWdZd3kwI7GTPGUjFne+krRxYmFg==", + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.6.tgz", + "integrity": "sha512-z2ELYSkyrrJ6cuunTU8vhsT/RpouPkjaSah06nVW6Rg2Hpg0Vs8s497/e5s8G8qtdp4ccsiovz5P1rv+5VSW2Q==", "dev": true, + "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "16.2.1", + "@next/eslint-plugin-next": "16.2.6", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", @@ -11159,6 +10251,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -11167,14 +10260,15 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -11182,6 +10276,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -11191,6 +10286,7 @@ "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", "dev": true, + "license": "ISC", "dependencies": { "@nolyfill/is-core-module": "1.0.39", "debug": "^4.4.0", @@ -11225,6 +10321,7 @@ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -11242,6 +10339,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -11251,6 +10349,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, + "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -11284,15 +10383,27 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", "dev": true, + "license": "MIT", "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", @@ -11322,6 +10433,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -11350,10 +10462,11 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", - "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", @@ -11365,30 +10478,17 @@ "node": ">=18" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", - "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "node-exports-info": "^1.6.0", - "object-keys": "^1.1.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, + "license": "ISC", "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "semver": "bin/semver.js" } }, "node_modules/eslint-scope": { @@ -11396,6 +10496,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -11412,6 +10513,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -11424,6 +10526,7 @@ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -11436,6 +10539,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -11448,6 +10552,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", @@ -11465,6 +10570,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -11477,6 +10583,7 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -11490,6 +10597,7 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -11502,6 +10610,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -11514,6 +10623,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -11522,6 +10632,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -11531,27 +10642,22 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, "node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==" + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" }, "node_modules/events-universal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", "dependencies": { "bare-events": "^2.7.0" } @@ -11561,6 +10667,7 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -11583,37 +10690,32 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/exit-x": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "engines": { - "node": ">=6" - } - }, "node_modules/expect": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz", - "integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", + "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.3.0", + "@jest/expect-utils": "30.4.1", "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.3.0", - "jest-message-util": "30.3.0", - "jest-mock": "30.3.0", - "jest-util": "30.3.0" + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-util": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -11623,12 +10725,14 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", - "devOptional": true + "devOptional": true, + "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==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" }, "node_modules/fast-check": { "version": "3.23.2", @@ -11645,6 +10749,7 @@ "url": "https://opencollective.com/fast-check" } ], + "license": "MIT", "dependencies": { "pure-rand": "^6.1.0" }, @@ -11666,7 +10771,8 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ] + ], + "license": "MIT" }, "node_modules/fast-content-type-parse": { "version": "2.0.1", @@ -11681,18 +10787,20 @@ "type": "opencollective", "url": "https://opencollective.com/fastify" } - ] + ], + "license": "MIT" }, "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-equals": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -11700,13 +10808,15 @@ "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -11723,6 +10833,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -11733,29 +10844,44 @@ "node_modules/fast-json-patch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", - "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/fast-readable-async-iterator": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-readable-async-iterator/-/fast-readable-async-iterator-2.0.0.tgz", - "integrity": "sha512-8Sld+DuyWRIftl86ZguJxR2oXCBccOiJxrY/Rj9/7ZBynW8pYMWzIcqxFL1da+25jaWJZVa+HHX/8SsA21JdTA==" + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "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.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -11764,6 +10890,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "license": "MIT", "dependencies": { "format": "^0.2.0" }, @@ -11777,6 +10904,7 @@ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } @@ -11785,6 +10913,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", "engines": { "node": ">=12.0.0" }, @@ -11797,39 +10926,19 @@ } } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/fflate": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "dev": true + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "dev": true, + "license": "MIT" }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" }, @@ -11841,6 +10950,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz", "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==", + "license": "MIT", "dependencies": { "tslib": "^2.7.0" }, @@ -11848,27 +10958,11 @@ "node": ">= 12" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "optional": true - }, - "node_modules/filename-reserved-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", - "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -11881,6 +10975,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -11897,6 +10992,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" @@ -11909,18 +11005,20 @@ "version": "3.4.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true + "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==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -11934,6 +11032,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", "dependencies": { "is-callable": "^1.2.7" }, @@ -11948,6 +11047,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" @@ -11963,6 +11063,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -11982,21 +11083,11 @@ "node": ">=0.4.x" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/formidable": { "version": "3.5.4", "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "license": "MIT", "dependencies": { "@paralleldrive/cuid2": "^2.2.2", "dezalgo": "^1.0.4", @@ -12013,6 +11104,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.1.tgz", "integrity": "sha512-NQYzZw8MUsxSZFQo6E8tKOlmSd/BlDTNOR4puXFSHSwFwNaIlmbortQy5PDN/KnVQ4xWG2NtN0J0hjPw7eE06A==", + "license": "MIT OR GPL-2.0", "engines": { "node": "*" } @@ -12021,6 +11113,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/frame-ticker/-/frame-ticker-1.0.3.tgz", "integrity": "sha512-E0X2u2JIvbEMrqEg5+4BpTqaD22OwojJI63K7MdKHdncjtAhGRbCR8nJCr2vwEt9NWBPCPcu70X9smPviEBy8Q==", + "license": "MIT", "dependencies": { "simplesignal": "^2.1.6" } @@ -12029,6 +11122,7 @@ "version": "11.18.2", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "license": "MIT", "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", @@ -12051,81 +11145,11 @@ } } }, - "node_modules/freelist": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/freelist/-/freelist-1.0.3.tgz", - "integrity": "sha512-Ji7fEnMdZDGbS5oXElpRJsn9jPvBR8h/037D3bzreNmS8809cISq/2D9//JbA/TaZmkkN8cmecXwmQHmM+NHhg==" - }, - "node_modules/fs-chunk-store": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fs-chunk-store/-/fs-chunk-store-5.0.0.tgz", - "integrity": "sha512-tKlT0joU9KmsLn0dTbVYVUa7VNqYQhl0X2qPPsN9lPEc3guXOmQJWY5/7kpo34Sk273qyWT5mqEhROCQPF+JKw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "filename-reserved-regex": "^3.0.0", - "queue-microtask": "^1.2.2", - "random-access-file": "^4.0.0", - "run-parallel": "^1.1.2", - "thunky": "^1.0.1", - "uint8-util": "^2.2.5" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "node_modules/fs-native-extensions": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/fs-native-extensions/-/fs-native-extensions-1.4.5.tgz", - "integrity": "sha512-ekV0T//iDm4AvhOcuPaHpxub4DI7HvY5ucLJVDvi7T2J+NZkQ9S6MuvgP0yeQvoqNUaAGyLjVYb1905BF9bpmg==", - "optional": true, - "dependencies": { - "require-addon": "^1.1.0", - "which-runtime": "^1.2.0" - } - }, - "node_modules/fsa-chunk-store": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fsa-chunk-store/-/fsa-chunk-store-1.3.0.tgz", - "integrity": "sha512-0WCfuxqqSB6Tz/g7Ar/nwAxMoigXaIXuvfrnLIEFYIA9uc6w9eNaHuBGzU1X3lyM4cpLKCOTUmKAA/gCiTvzMQ==", - "dependencies": { - "filename-reserved-regex": "^3.0.0" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12135,6 +11159,7 @@ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -12155,14 +11180,16 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/geist": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/geist/-/geist-1.7.0.tgz", - "integrity": "sha512-ZaoiZwkSf0DwwB1ncdLKp+ggAldqxl5L1+SXaNIBGkPAqcu+xjVJLxlf3/S8vLt9UHx1xu5fz3lbzKCj5iOVdQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/geist/-/geist-1.7.1.tgz", + "integrity": "sha512-XF8DM30ODhDu0Ng5S2kOS8j4ZkG/6z2fKWAiFJA7wG0Hc92ZXgjYLrwbD9bVU4nGVzwboPtG+QtaPGsfgnXLaA==", + "license": "SIL OPEN FONT LICENSE", "peerDependencies": { "next": ">=13.2.0" } @@ -12171,6 +11198,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -12179,6 +11207,8 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -12187,6 +11217,7 @@ "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.*" } @@ -12195,6 +11226,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -12218,6 +11250,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", "engines": { "node": ">=6" } @@ -12227,6 +11260,7 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -12235,6 +11269,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -12247,6 +11282,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/get-random-values/-/get-random-values-2.1.0.tgz", "integrity": "sha512-q2yOLpLyA8f9unfv2LV8KVRUFeOIrQVS5cnqpbv6N+ea9j1rmW5dFKj/2Q7CK3juEfDYQgPxGt941VJcmw0jKg==", + "license": "MIT", "dependencies": { "global": "^4.4.0" }, @@ -12254,21 +11290,12 @@ "node": "14 || 16 || >=18" } }, - "node_modules/get-stdin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", - "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -12281,6 +11308,7 @@ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -12294,10 +11322,11 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, + "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -12310,6 +11339,7 @@ "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", "devOptional": true, + "license": "MIT", "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", @@ -12322,16 +11352,12 @@ "giget": "dist/cli.mjs" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, "node_modules/glob": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "BlueOak-1.0.0", "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", @@ -12354,6 +11380,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -12365,14 +11392,16 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", "engines": { "node": "18 || 20 || >=22" } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, @@ -12381,11 +11410,12 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -12398,6 +11428,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "license": "MIT", "dependencies": { "min-document": "^2.19.0", "process": "^0.11.10" @@ -12408,6 +11439,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -12420,6 +11452,7 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" @@ -12435,12 +11468,14 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/gopd": { "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" }, @@ -12452,12 +11487,14 @@ "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==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphql": { - "version": "16.13.2", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.13.2.tgz", - "integrity": "sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==", + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.0.tgz", + "integrity": "sha512-BBvQ/406p+4CZbTpCbVPSxfzrZrbnuWSP1ELYgyS6B+hNeKzgrdB4JczCa5VZUBQrDa9hUngm0KnexY6pJRN5Q==", + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -12466,6 +11503,7 @@ "version": "5.16.2", "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.2.tgz", "integrity": "sha512-E1uccsZxt/96jH/OwmLPuXMACILs76pKF2i3W861LpKBCYtGIyPQGtWLuBLkND4ox1KHns70e83PS4te50nvPQ==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -12478,6 +11516,7 @@ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", "dev": true, + "license": "MIT", "dependencies": { "duplexer": "^0.1.2" }, @@ -12492,6 +11531,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-4.4.0.tgz", "integrity": "sha512-DvJh07MhGgY2KcC4OeZc8SSyA+ZXpdvoh6uCzGpoKvWtZxJB+g6VXXC1+eWYkaMIsLz7J/ErhOalHCpcs1KYog==", + "license": "Apache-2.0", "engines": { "node": ">=4", "npm": ">=3", @@ -12503,6 +11543,7 @@ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", @@ -12524,6 +11565,7 @@ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -12536,6 +11578,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -12544,6 +11587,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -12556,6 +11600,7 @@ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "license": "MIT", "dependencies": { "dunder-proto": "^1.0.0" }, @@ -12570,6 +11615,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -12581,6 +11627,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -12595,6 +11642,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", "dependencies": { "inherits": "^2.0.4", "readable-stream": "^2.3.8", @@ -12608,12 +11656,14 @@ "node_modules/hash-base/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" }, "node_modules/hash-base/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", @@ -12627,12 +11677,14 @@ "node_modules/hash-base/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==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/hash-base/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" } @@ -12640,12 +11692,14 @@ "node_modules/hash-base/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==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -12654,12 +11708,14 @@ "node_modules/hashlru": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz", - "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==" + "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==", + "license": "MIT" }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -12671,6 +11727,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -12683,6 +11740,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", @@ -12709,6 +11767,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -12721,6 +11780,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", @@ -12737,13 +11797,15 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hermes-parser": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", "dev": true, + "license": "MIT", "dependencies": { "hermes-estree": "0.25.1" } @@ -12752,6 +11814,7 @@ "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", "engines": { "node": "*" } @@ -12759,39 +11822,52 @@ "node_modules/highlightjs-vue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", - "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==" + "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", + "license": "CC0-1.0" }, "node_modules/hls.js": { - "version": "1.6.15", - "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz", - "integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==", - "dev": true + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.16.tgz", + "integrity": "sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/html-url-attributes": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/http-parser-js": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz", - "integrity": "sha512-u8u5ZaG0Tr/VvHlucK2ufMuOp4/5bvwgneXle+y228K5rMbJOlVjThONcaAw3ikAy8b2OO9RfEucdMHFz3UWMA==" + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -12805,9 +11881,10 @@ } }, "node_modules/idb-keyval": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", - "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==" + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.4.tgz", + "integrity": "sha512-D/NzHWUmYJGXi++z67aMSrnisb9A3621CyRK5G89JyTlN13C8xf0g04DLxUKMufPem3e3L2JAXR6Z00OWy183Q==", + "license": "Apache-2.0" }, "node_modules/ieee754": { "version": "1.2.1", @@ -12826,13 +11903,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -12841,34 +11920,14 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true - }, - "node_modules/immediate-chunk-store": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/immediate-chunk-store/-/immediate-chunk-store-2.2.0.tgz", - "integrity": "sha512-1bHBna0hCa6arRXicu91IiL9RvvkbNYLVq+mzWdaLGZC3hXvX4doh8e1dLhMKez5siu63CYgO5NrGJbRX5lbPA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.3" - } + "dev": true, + "license": "MIT" }, "node_modules/immutable": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.3.tgz", "integrity": "sha512-AUY/VyX0E5XlibOmWt10uabJzam1zlYjwiEgQSDc5+UIkFNaF9WM0JxXKaNMGf+F/ffUF+7kRKXM9A7C0xXqMg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -12878,6 +11937,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -12893,6 +11953,7 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz", "integrity": "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==", + "license": "Apache-2.0", "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", @@ -12903,13 +11964,15 @@ "node_modules/import-in-the-middle/node_modules/cjs-module-lexer": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==" + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "license": "MIT" }, "node_modules/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -12929,6 +11992,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -12937,6 +12001,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/index-array-by/-/index-array-by-1.4.2.tgz", "integrity": "sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw==", + "license": "MIT", "engines": { "node": ">=12" } @@ -12944,23 +12009,21 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/inline-style-parser": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==" + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", @@ -12974,6 +12037,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -12982,19 +12046,16 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", "dependencies": { "loose-envify": "^1.0.0" } }, - "node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" - }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -13003,18 +12064,11 @@ "node": ">= 12" } }, - "node_modules/ip-set": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ip-set/-/ip-set-2.2.0.tgz", - "integrity": "sha512-NmmY3BfY4pejh6GOqNcNWRsBNdR+I7pUVtXRgZlkZdcnLtlG4X6HNtu2FZoCGyvGRzyroP1fJ+SJZBZ65JJl/Q==", - "dependencies": { - "ip": "^2.0.1" - } - }, "node_modules/ipaddr.js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", - "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", + "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", + "license": "MIT", "engines": { "node": ">= 10" } @@ -13023,6 +12077,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -13032,6 +12087,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" @@ -13045,6 +12101,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" @@ -13061,6 +12118,7 @@ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -13077,13 +12135,15 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-async-function": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, + "license": "MIT", "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", @@ -13103,6 +12163,7 @@ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", "dependencies": { "has-bigints": "^1.0.2" }, @@ -13117,6 +12178,7 @@ "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" }, @@ -13129,6 +12191,7 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -13145,26 +12208,16 @@ "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.7.1" } }, - "node_modules/is-bun-module/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -13173,11 +12226,12 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -13191,6 +12245,7 @@ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", @@ -13208,6 +12263,7 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" @@ -13223,6 +12279,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -13232,20 +12289,17 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/is-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-file/-/is-file-1.0.0.tgz", - "integrity": "sha512-ZGMuc+xA8mRnrXtmtf2l/EkIW2zaD2LSBWlaOVEF6yH4RTndHob65V4SwWWdtGKVthQfXPVKsXqw4TDUjbVxVQ==" - }, "node_modules/is-finalizationregistry": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3" }, @@ -13260,6 +12314,7 @@ "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" } @@ -13269,6 +12324,7 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -13277,6 +12333,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", @@ -13295,6 +12352,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -13306,6 +12364,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -13316,6 +12375,7 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -13328,6 +12388,7 @@ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -13339,6 +12400,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -13348,6 +12410,7 @@ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -13363,6 +12426,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -13375,6 +12439,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -13383,12 +12448,14 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-regex": { "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==", + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", @@ -13407,6 +12474,7 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -13419,6 +12487,7 @@ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3" }, @@ -13446,13 +12515,15 @@ "type": "paypal", "url": "https://paypal.me/faisalman" } - ] + ], + "license": "MIT" }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -13465,6 +12536,7 @@ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -13481,6 +12553,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", @@ -13497,6 +12570,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" }, @@ -13512,6 +12586,7 @@ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -13524,6 +12599,7 @@ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3" }, @@ -13539,6 +12615,7 @@ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" @@ -13554,6 +12631,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "license": "MIT", "engines": { "node": ">=18" }, @@ -13564,17 +12642,20 @@ "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==" + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/iso-url": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-1.2.1.tgz", "integrity": "sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng==", + "license": "MIT", "engines": { "node": ">=12" } @@ -13583,6 +12664,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", "peerDependencies": { "ws": "*" } @@ -13592,6 +12674,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } @@ -13601,6 +12684,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -13612,23 +12696,12 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -13643,6 +12716,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", @@ -13657,6 +12731,7 @@ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -13670,6 +12745,7 @@ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", @@ -13687,6 +12763,7 @@ "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.2.5.tgz", "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", "dev": true, + "license": "MIT", "dependencies": { "@types/react-reconciler": "^0.28.0" }, @@ -13699,6 +12776,7 @@ "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", "dev": true, + "license": "MIT", "peerDependencies": { "@types/react": "*" } @@ -13707,6 +12785,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^9.0.0" }, @@ -13718,15 +12797,16 @@ } }, "node_modules/jest": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-30.3.0.tgz", - "integrity": "sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.4.2.tgz", + "integrity": "sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/core": "30.3.0", - "@jest/types": "30.3.0", + "@jest/core": "30.4.2", + "@jest/types": "30.4.1", "import-local": "^3.2.0", - "jest-cli": "30.3.0" + "jest-cli": "30.4.2" }, "bin": { "jest": "bin/jest.js" @@ -13744,13 +12824,14 @@ } }, "node_modules/jest-changed-files": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.3.0.tgz", - "integrity": "sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.4.1.tgz", + "integrity": "sha512-IuctmYrxi21iOSOaIXpJWalHyPAsVv0GeBHKDn8C1CA4W5htHn7INL+wdnL4Bo0+olEndvAFkmb++tIQJG+vvg==", "dev": true, + "license": "MIT", "dependencies": { "execa": "^5.1.1", - "jest-util": "30.3.0", + "jest-util": "30.4.1", "p-limit": "^3.1.0" }, "engines": { @@ -13758,28 +12839,29 @@ } }, "node_modules/jest-circus": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.3.0.tgz", - "integrity": "sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.4.2.tgz", + "integrity": "sha512-rvHH7VlY6LgbJXJTQ87GW62g1FntOtbhh0zT+v04kC+pgL6aBKyYINXxWukCpj3dcIBMw5/XUbtDS9dU9JTXeQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "30.3.0", - "@jest/expect": "30.3.0", - "@jest/test-result": "30.3.0", - "@jest/types": "30.3.0", + "@jest/environment": "30.4.1", + "@jest/expect": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", "co": "^4.6.0", "dedent": "^1.6.0", "is-generator-fn": "^2.1.0", - "jest-each": "30.3.0", - "jest-matcher-utils": "30.3.0", - "jest-message-util": "30.3.0", - "jest-runtime": "30.3.0", - "jest-snapshot": "30.3.0", - "jest-util": "30.3.0", + "jest-each": "30.4.1", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-runtime": "30.4.2", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", "p-limit": "^3.1.0", - "pretty-format": "30.3.0", + "pretty-format": "30.4.1", "pure-rand": "^7.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" @@ -13789,20 +12871,21 @@ } }, "node_modules/jest-cli": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.3.0.tgz", - "integrity": "sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.4.2.tgz", + "integrity": "sha512-jfA2ocvVHMXS2QijrJ0d31ektP+d/W0T5RpcTX2Pq+3sVqHlsXVCM2+FmwpL+bdY8OfHpIg9xMxLF17Zg0U49Q==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/core": "30.3.0", - "@jest/test-result": "30.3.0", - "@jest/types": "30.3.0", + "@jest/core": "30.4.2", + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", "chalk": "^4.1.2", "exit-x": "^0.2.2", "import-local": "^3.2.0", - "jest-config": "30.3.0", - "jest-util": "30.3.0", - "jest-validate": "30.3.0", + "jest-config": "30.4.2", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", "yargs": "^17.7.2" }, "bin": { @@ -13821,32 +12904,33 @@ } }, "node_modules/jest-config": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.3.0.tgz", - "integrity": "sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.4.2.tgz", + "integrity": "sha512-rNHAShJQqQwFNoL0hbf3BphSBOWnpOUAKvidLS/AjNVLPfoj5mSf4jQMfW3cYOs6hXeZC7nF7mDHaBnbxELOzg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", "@jest/get-type": "30.1.0", - "@jest/pattern": "30.0.1", - "@jest/test-sequencer": "30.3.0", - "@jest/types": "30.3.0", - "babel-jest": "30.3.0", + "@jest/pattern": "30.4.0", + "@jest/test-sequencer": "30.4.1", + "@jest/types": "30.4.1", + "babel-jest": "30.4.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "deepmerge": "^4.3.1", "glob": "^10.5.0", "graceful-fs": "^4.2.11", - "jest-circus": "30.3.0", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.3.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.3.0", - "jest-runner": "30.3.0", - "jest-util": "30.3.0", - "jest-validate": "30.3.0", + "jest-circus": "30.4.2", + "jest-docblock": "30.4.0", + "jest-environment-node": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-runner": "30.4.2", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", "parse-json": "^5.2.0", - "pretty-format": "30.3.0", + "pretty-format": "30.4.1", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -13871,25 +12955,27 @@ } }, "node_modules/jest-diff": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", - "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", + "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/diff-sequences": "30.3.0", + "@jest/diff-sequences": "30.4.0", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "pretty-format": "30.3.0" + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-docblock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", - "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.4.0.tgz", + "integrity": "sha512-ZPMabUZCx5MpbZ2eBYSvZ0J8fvo3dR9oM+eeUpb3aKNQFuS2tu3Duw1TNlMoP8k3WQgKGJuhcMFvwcVuq6T7oA==", "dev": true, + "license": "MIT", "dependencies": { "detect-newline": "^3.1.0" }, @@ -13898,53 +12984,56 @@ } }, "node_modules/jest-each": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.3.0.tgz", - "integrity": "sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.4.1.tgz", + "integrity": "sha512-/8MJbH6fuj48TstjrMf+u/pd06Qezz5xOXvZA6442heNOWr8bdeoGZX2d9fCn028CoMgYmroH9//zky5GfyYmA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "@jest/types": "30.3.0", + "@jest/types": "30.4.1", "chalk": "^4.1.2", - "jest-util": "30.3.0", - "pretty-format": "30.3.0" + "jest-util": "30.4.1", + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-environment-node": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.3.0.tgz", - "integrity": "sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.4.1.tgz", + "integrity": "sha512-4FZYVOk85hz2AyT6BbarKy9u37g6DbrDyCdFhsnDdXqyrueYQvB+0zO4f/kqLCRD0BsPRXPMNJeQwihKZV8naw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "30.3.0", - "@jest/fake-timers": "30.3.0", - "@jest/types": "30.3.0", + "@jest/environment": "30.4.1", + "@jest/fake-timers": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", - "jest-mock": "30.3.0", - "jest-util": "30.3.0", - "jest-validate": "30.3.0" + "jest-mock": "30.4.1", + "jest-util": "30.4.1", + "jest-validate": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-haste-map": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.3.0.tgz", - "integrity": "sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.4.1.tgz", + "integrity": "sha512-rFrcONd8jeFsyw+Z9CrScJgglRf2+NFmNam8dKu7n+SoHqNYT47mn0DdEcVUZJpvh7Iz6/si7f7yUH7GJHVgnw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "30.3.0", + "@jest/types": "30.4.1", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", - "jest-regex-util": "30.0.1", - "jest-util": "30.3.0", - "jest-worker": "30.3.0", + "jest-regex-util": "30.4.0", + "jest-util": "30.4.1", + "jest-worker": "30.4.1", "picomatch": "^4.0.3", "walker": "^1.0.8" }, @@ -13956,46 +13045,50 @@ } }, "node_modules/jest-leak-detector": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.3.0.tgz", - "integrity": "sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.4.1.tgz", + "integrity": "sha512-IpmyiioeHxiWDhesHnUFmOxcTzwCwKpgACgWajtAP+nYQXiY7DakTxB6Bx9JFiRMljr0AX1PvnQdaU1KFoz6NQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "pretty-format": "30.3.0" + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz", - "integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", + "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", "dev": true, + "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "jest-diff": "30.3.0", - "pretty-format": "30.3.0" + "jest-diff": "30.4.1", + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-message-util": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz", - "integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", + "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.3.0", + "@jest/types": "30.4.1", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", + "jest-util": "30.4.1", "picomatch": "^4.0.3", - "pretty-format": "30.3.0", + "pretty-format": "30.4.1", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -14004,14 +13097,15 @@ } }, "node_modules/jest-mock": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz", - "integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", + "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "30.3.0", + "@jest/types": "30.4.1", "@types/node": "*", - "jest-util": "30.3.0" + "jest-util": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -14022,6 +13116,7 @@ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -14035,26 +13130,28 @@ } }, "node_modules/jest-regex-util": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", - "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", + "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", "dev": true, + "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-resolve": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.3.0.tgz", - "integrity": "sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.4.1.tgz", + "integrity": "sha512-Zry8Yq/yJcNAZ7dJ5F2heic8AheXvbFZ7XI5V+h28nrYZ7Qoyy4dItq8OodjnYD270mvX+ZudmrNV9cysqhW5Q==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.3.0", + "jest-haste-map": "30.4.1", "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.3.0", - "jest-validate": "30.3.0", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", "slash": "^3.0.0", "unrs-resolver": "^1.7.11" }, @@ -14063,44 +13160,46 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.3.0.tgz", - "integrity": "sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.4.2.tgz", + "integrity": "sha512-gDiVh1I+GxYzz9oXlyw+1wv6VOYX1WYxMOfjsA3iGKePV2oxmbHhwxfkALxNxYy1ciw6APWwkW2zZONwP97aEQ==", "dev": true, + "license": "MIT", "dependencies": { - "jest-regex-util": "30.0.1", - "jest-snapshot": "30.3.0" + "jest-regex-util": "30.4.0", + "jest-snapshot": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-runner": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.3.0.tgz", - "integrity": "sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.4.2.tgz", + "integrity": "sha512-2dw0PslVYXxffXGpLo+Ejad+KcI1Qkjn7f4X4619gf21oCUmL+SPfjqIa/losUem3yEOvfNZe/F1HWUcNpODcg==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "30.3.0", - "@jest/environment": "30.3.0", - "@jest/test-result": "30.3.0", - "@jest/transform": "30.3.0", - "@jest/types": "30.3.0", + "@jest/console": "30.4.1", + "@jest/environment": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", "emittery": "^0.13.1", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.3.0", - "jest-haste-map": "30.3.0", - "jest-leak-detector": "30.3.0", - "jest-message-util": "30.3.0", - "jest-resolve": "30.3.0", - "jest-runtime": "30.3.0", - "jest-util": "30.3.0", - "jest-watcher": "30.3.0", - "jest-worker": "30.3.0", + "jest-docblock": "30.4.0", + "jest-environment-node": "30.4.1", + "jest-haste-map": "30.4.1", + "jest-leak-detector": "30.4.1", + "jest-message-util": "30.4.1", + "jest-resolve": "30.4.1", + "jest-runtime": "30.4.2", + "jest-util": "30.4.1", + "jest-watcher": "30.4.1", + "jest-worker": "30.4.1", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -14109,31 +13208,32 @@ } }, "node_modules/jest-runtime": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.3.0.tgz", - "integrity": "sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.4.2.tgz", + "integrity": "sha512-3/5e8iPz2k/VLqlr8DgTftYyLUv8Su3FkCAO2/Od81UsUTpSxOrS6O5x5KkoQwyUjmpYyDJKeyAvg2T2nvpNkQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "30.3.0", - "@jest/fake-timers": "30.3.0", - "@jest/globals": "30.3.0", + "@jest/environment": "30.4.1", + "@jest/fake-timers": "30.4.1", + "@jest/globals": "30.4.1", "@jest/source-map": "30.0.1", - "@jest/test-result": "30.3.0", - "@jest/transform": "30.3.0", - "@jest/types": "30.3.0", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", "cjs-module-lexer": "^2.1.0", "collect-v8-coverage": "^1.0.2", "glob": "^10.5.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.3.0", - "jest-message-util": "30.3.0", - "jest-mock": "30.3.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.3.0", - "jest-snapshot": "30.3.0", - "jest-util": "30.3.0", + "jest-haste-map": "30.4.1", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -14142,30 +13242,31 @@ } }, "node_modules/jest-snapshot": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.3.0.tgz", - "integrity": "sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.4.1.tgz", + "integrity": "sha512-tEOkkfOMppUyeiHwjZswOQ3lcnoTnws/q5FnGIaeIh/jmoU0ZlgMYRR8sTlTj+nNGCoJ0RDq6SfxGxCsyMTPmw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.3.0", + "@jest/expect-utils": "30.4.1", "@jest/get-type": "30.1.0", - "@jest/snapshot-utils": "30.3.0", - "@jest/transform": "30.3.0", - "@jest/types": "30.3.0", + "@jest/snapshot-utils": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", - "expect": "30.3.0", + "expect": "30.4.1", "graceful-fs": "^4.2.11", - "jest-diff": "30.3.0", - "jest-matcher-utils": "30.3.0", - "jest-message-util": "30.3.0", - "jest-util": "30.3.0", - "pretty-format": "30.3.0", + "jest-diff": "30.4.1", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", + "pretty-format": "30.4.1", "semver": "^7.7.2", "synckit": "^0.11.8" }, @@ -14173,25 +13274,14 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-util": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz", - "integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", + "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "30.3.0", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -14203,17 +13293,18 @@ } }, "node_modules/jest-validate": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", - "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.4.1.tgz", + "integrity": "sha512-PDWi4SOwLnwqNDfHZjOcsEFyZ4fc/2W2gVL3DEoyqnB6jCQMLRtfBong8s6omIw3lI0HWOus12xfnFmQtjW3fw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "@jest/types": "30.3.0", + "@jest/types": "30.4.1", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "30.3.0" + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -14224,6 +13315,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -14232,18 +13324,19 @@ } }, "node_modules/jest-watcher": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.3.0.tgz", - "integrity": "sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.4.1.tgz", + "integrity": "sha512-/l9UonmvCwjHH7d2h3iAwIloLc1H0S8mJZ/LNK3i86hqwPAz8otUJjP9MfYtz9Tt77Su5FD2xGjZn8d31IZHlw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/test-result": "30.3.0", - "@jest/types": "30.3.0", + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "emittery": "^0.13.1", - "jest-util": "30.3.0", + "jest-util": "30.4.1", "string-length": "^4.0.2" }, "engines": { @@ -14251,14 +13344,15 @@ } }, "node_modules/jest-worker": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.3.0.tgz", - "integrity": "sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.1.tgz", + "integrity": "sha512-SHynN/q/QD++iNyvMdy+WMmbCGk8jIsNcRxycXbWubSOhvo6T+j2afcfUSl+3hYsiBebOTo0cT7c2H7CXugu1g==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.3.0", + "jest-util": "30.4.1", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" }, @@ -14271,6 +13365,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -14282,23 +13377,20 @@ } }, "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "devOptional": true, + "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/join-async-iterator": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/join-async-iterator/-/join-async-iterator-1.1.1.tgz", - "integrity": "sha512-ATse+nuNeKZ9K1y27LKdvPe/GCe9R/u9dw9vI248e+vILeRK3IcJP4JUPAlSmKRCDK0cKhEwfmiw4Skqx7UnGQ==" - }, "node_modules/jose": { "version": "4.15.9", "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } @@ -14306,22 +13398,26 @@ "node_modules/js-base64": { "version": "3.7.8", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", - "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==" + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "license": "BSD-3-Clause" }, "node_modules/js-file-download": { "version": "0.4.12", "resolved": "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz", - "integrity": "sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==" + "integrity": "sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==", + "license": "MIT" }, "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==" + "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", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -14332,12 +13428,15 @@ "node_modules/jsbn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" }, "node_modules/jsesc": { "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" }, @@ -14349,6 +13448,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", "dependencies": { "bignumber.js": "^9.0.0" } @@ -14357,30 +13457,36 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -14392,6 +13498,7 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-9.0.0.tgz", "integrity": "sha512-pjMIdkXfC1T2wrX9B9i2uXhGdyCmgec3qgMht+TDj+S0qX3bjWMQUfL7NeqEhuRTi8G5ESzmL9uGlST7nzSEWg==", + "license": "BSD-3-Clause", "dependencies": { "@digitalbazaar/http-client": "^4.2.0", "canonicalize": "^2.1.0", @@ -14406,6 +13513,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -14416,12 +13524,14 @@ "node_modules/jsonld/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" }, "node_modules/jsonwebtoken": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", @@ -14439,22 +13549,12 @@ "npm": ">=6" } }, - "node_modules/jsonwebtoken/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -14465,21 +13565,11 @@ "node": ">=4.0" } }, - "node_modules/junk": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.1.tgz", - "integrity": "sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jwa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -14490,49 +13580,17 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, - "node_modules/k-bucket": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/k-bucket/-/k-bucket-5.1.0.tgz", - "integrity": "sha512-Fac7iINEovXIWU20GPnOMLUbjctiS+cnmyjC4zAUgvs3XPf1vo9akfCHkigftSic/jiKqKl+KA3a/vFcJbHyCg==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/k-rpc": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/k-rpc/-/k-rpc-5.1.0.tgz", - "integrity": "sha512-FGc+n70Hcjoa/X2JTwP+jMIOpBz+pkRffHnSl9yrYiwUxg3FIgD50+u1ePfJUOnRCnx6pbjmVk5aAeB1wIijuQ==", - "dependencies": { - "k-bucket": "^5.0.0", - "k-rpc-socket": "^1.7.2", - "randombytes": "^2.0.5" - } - }, - "node_modules/k-rpc-socket": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/k-rpc-socket/-/k-rpc-socket-1.11.1.tgz", - "integrity": "sha512-8xtA8oqbZ6v1Niryp2/g4GxW16EQh5MvrUylQoOG+zcrDff5CKttON2XUXvMwlIHq4/2zfPVFiinAccJ+WhxoA==", - "dependencies": { - "bencode": "^2.0.0", - "chrome-dgram": "^3.0.2", - "chrome-dns": "^1.0.0", - "chrome-net": "^3.3.2" - } - }, - "node_modules/k-rpc-socket/node_modules/bencode": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/bencode/-/bencode-2.0.3.tgz", - "integrity": "sha512-D/vrAD4dLVX23NalHwb8dSvsUsxeRPO8Y7ToKA015JQYq69MLDOMkC0uGZYA/MPpltLO8rt8eqFC2j8DxjTZ/w==" - }, "node_modules/kapsule": { "version": "1.16.3", "resolved": "https://registry.npmjs.org/kapsule/-/kapsule-1.16.3.tgz", "integrity": "sha512-4+5mNNf4vZDSwPhKprKwz3330iisPrb08JyMgbsdFrimBCKNHecua/WBwvVg3n7vwx0C1ARjfhwIpbrbd9n5wg==", + "license": "MIT", "dependencies": { "lodash-es": "4" }, @@ -14545,6 +13603,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -14553,6 +13612,7 @@ "version": "1.14.3", "resolved": "https://registry.npmjs.org/ky/-/ky-1.14.3.tgz", "integrity": "sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==", + "license": "MIT", "engines": { "node": ">=18" }, @@ -14564,13 +13624,15 @@ "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/language-tags": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dev": true, + "license": "MIT", "dependencies": { "language-subtag-registry": "^0.3.20" }, @@ -14578,16 +13640,12 @@ "node": ">=0.10" } }, - "node_modules/last-one-wins": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/last-one-wins/-/last-one-wins-1.0.4.tgz", - "integrity": "sha512-t+KLJFkHPQk8lfN6WBOiGkiUXoub+gnb2XTYI2P3aiISL+94xgZ1vgz1SXN/N4hthuOoLXarXfBZPUruyjQtfA==" - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -14597,6 +13655,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -14608,12 +13667,14 @@ "node_modules/libsodium-sumo": { "version": "0.7.16", "resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.16.tgz", - "integrity": "sha512-x6atrz2AdXCJg6G709x9W9TTJRI6/0NcL5dD0l5GGVqNE48UJmDsjO4RUWYTeyXXUpg+NXZ2SHECaZnFRYzwGA==" + "integrity": "sha512-x6atrz2AdXCJg6G709x9W9TTJRI6/0NcL5dD0l5GGVqNE48UJmDsjO4RUWYTeyXXUpg+NXZ2SHECaZnFRYzwGA==", + "license": "ISC" }, "node_modules/libsodium-wrappers-sumo": { "version": "0.7.10", "resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.10.tgz", "integrity": "sha512-1noz8Mcl/LUzO/iSO/FJzoJyIaPwxl+/+E4CoTIXtsPiEEXQx2sxalmrVWxteLpynqgX0ASo28ChB9NEVRh0Pg==", + "license": "ISC", "dependencies": { "libsodium-sumo": "^0.7.0" } @@ -14623,6 +13684,7 @@ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, + "license": "MIT", "dependencies": { "immediate": "~3.0.5" } @@ -14631,6 +13693,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/light-bolt11-decoder/-/light-bolt11-decoder-3.2.0.tgz", "integrity": "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==", + "license": "MIT", "dependencies": { "@scure/base": "1.1.1" } @@ -14644,12 +13707,14 @@ "type": "individual", "url": "https://paulmillr.com/funding/" } - ] + ], + "license": "MIT" }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", "engines": { "node": ">=14" }, @@ -14657,51 +13722,18 @@ "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/limiter": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", - "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/load-ip-set": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/load-ip-set/-/load-ip-set-3.0.1.tgz", - "integrity": "sha512-ZFZt1g4Exq01SFtKjffqau+L4Qibt+51utymHHiWo8Iu/W7LYSqE7fiZ/iAZ6dIqbmeU6ICSIK02IizSScBkLQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "cross-fetch-ponyfill": "^1.0.1", - "ip-set": "^2.1.0", - "netmask": "^2.0.1", - "once": "^1.4.0", - "queue-microtask": "^1.2.3", - "split": "^1.0.1" - }, - "engines": { - "node": ">=12.20.0" - } + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -14713,98 +13745,102 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "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==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead." + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead." + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" }, "node_modules/lodash.isnumber": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" }, "node_modules/lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.mergewith": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" }, "node_modules/long": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -14814,6 +13850,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -14825,6 +13862,7 @@ "version": "1.20.0", "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "license": "MIT", "dependencies": { "fault": "^1.0.0", "highlight.js": "~10.7.0" @@ -14834,106 +13872,48 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/lru": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lru/-/lru-3.1.0.tgz", - "integrity": "sha512-5OUtoiVIGU4VXBOshidmtOsvBIvcQR6FD/RzWSvaeHyxCGB+PCUCu+52lqMfdc0h/2CLvHhZS4TwUmMQrrMbBQ==", - "dependencies": { - "inherits": "^2.0.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, - "node_modules/lt_donthave": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lt_donthave/-/lt_donthave-2.0.6.tgz", - "integrity": "sha512-ZVcaRbZpNB6ugwa5T9gUN0Jg9XGT9cyVjZJvdbN3V27rOQ170rEs//zaQXEQkTCBhh3i/JnCRF472KWHJu74Yg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "debug": "^4.2.0", - "unordered-array-remove": "^1.0.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/lucide-react": { "version": "0.439.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.439.0.tgz", "integrity": "sha512-PafSWvDTpxdtNEndS2HIHxcNAbd54OaqSYJO90/b63rab2HWYqDbH194j0i82ZFdWOAcf0AHinRykXRRK2PJbw==", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" - } - }, - "node_modules/maath": { - "version": "0.10.8", - "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz", - "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", - "dev": true, - "peerDependencies": { - "@types/three": ">=0.134.0", - "three": ">=0.134.0" - } - }, - "node_modules/magnet-uri": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/magnet-uri/-/magnet-uri-7.0.7.tgz", - "integrity": "sha512-z/+dB2NQsXaDuxVBjoPLpZT8ePaacUmoontoFheRBl++nALHYs4qV9MmhTur9e4SaMbkCR/uPX43UMzEOoeyaw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "@thaunknown/thirty-two": "^1.0.5", - "bep53-range": "^2.0.0", - "uint8-util": "^2.2.5" - }, - "engines": { - "node": ">=12.20.0" + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/maath": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz", + "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/three": ">=0.134.0", + "three": ">=0.134.0" } }, "node_modules/main-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/main-event/-/main-event-1.0.1.tgz", - "integrity": "sha512-NWtdGrAca/69fm6DIVd8T9rtfDII4Q8NQbIbsKQq2VzS9eqOGYs8uaNQjcuaCq/d9H/o625aOTJX2Qoxzqw0Pw==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/main-event/-/main-event-1.0.4.tgz", + "integrity": "sha512-sKazUjIy2Jalv5lkQ446iOcrx8Q7TkaCuk6xfnzg5uUqMusMLDMPmRDmSNE2kjSVpSTJo4j1bQZusS+Ib7Bvrg==", + "license": "Apache-2.0 OR MIT" }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -14944,29 +13924,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } @@ -14975,6 +13945,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -14984,6 +13955,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -14992,6 +13964,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -15002,6 +13975,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", @@ -15017,6 +13991,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -15028,6 +14003,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -15051,6 +14027,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", @@ -15069,6 +14046,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", @@ -15085,6 +14063,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", @@ -15101,6 +14080,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -15115,6 +14095,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -15131,6 +14112,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -15146,6 +14128,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -15163,6 +14146,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -15186,6 +14170,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -15203,6 +14188,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" @@ -15216,6 +14202,7 @@ "version": "13.2.1", "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -15236,6 +14223,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -15256,6 +14244,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" }, @@ -15264,23 +14253,18 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/memory-chunk-store": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/memory-chunk-store/-/memory-chunk-store-1.3.5.tgz", - "integrity": "sha512-E1Xc1U4ifk/FkC2ZsWhCaW1xg9HbE/OBmQTLe2Tr9c27YPSLbW7kw1cnb3kQWD1rDtErFJHa7mB9EVrs7aTx9g==", - "dependencies": { - "queue-microtask": "^1.2.3" - } - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", "engines": { "node": ">= 8" } @@ -15290,20 +14274,23 @@ "resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz", "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==", "dev": true, + "license": "MIT", "peerDependencies": { "three": ">=0.137" } }, "node_modules/meshoptimizer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz", - "integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.1.1.tgz", + "integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==", + "dev": true, + "license": "MIT" }, "node_modules/micro-packed": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", + "license": "MIT", "dependencies": { "@scure/base": "~1.2.5" }, @@ -15325,6 +14312,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -15359,6 +14347,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", @@ -15382,6 +14371,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", @@ -15401,6 +14391,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", @@ -15416,6 +14407,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", @@ -15435,6 +14427,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -15452,6 +14445,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", @@ -15468,6 +14462,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" }, @@ -15480,6 +14475,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", @@ -15506,6 +14502,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -15526,6 +14523,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -15547,6 +14545,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -15566,6 +14565,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -15587,6 +14587,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -15608,6 +14609,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -15627,6 +14629,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } @@ -15645,6 +14648,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -15665,6 +14669,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -15684,6 +14689,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } @@ -15702,6 +14708,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -15722,7 +14729,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.1", @@ -15737,7 +14745,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-normalize-identifier": { "version": "2.0.1", @@ -15753,6 +14762,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } @@ -15771,6 +14781,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" } @@ -15789,6 +14800,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", @@ -15809,6 +14821,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -15829,7 +14842,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-types": { "version": "2.0.2", @@ -15844,12 +14858,14 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -15862,6 +14878,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -15869,21 +14886,11 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.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" } @@ -15892,6 +14899,7 @@ "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" }, @@ -15904,25 +14912,16 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-document": { "version": "2.19.2", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz", "integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==", + "license": "MIT", "dependencies": { "dom-walk": "^0.1.0" } @@ -15931,6 +14930,7 @@ "version": "0.23.8", "resolved": "https://registry.npmjs.org/minim/-/minim-0.23.8.tgz", "integrity": "sha512-bjdr2xW1dBCMsMGGsUeqM4eFI60m94+szhxWys+B1ztIt6gWSfeGBdSVCIawezeHYLYn0j6zrsXdQS/JllBzww==", + "license": "MIT", "dependencies": { "lodash": "^4.15.0" }, @@ -15941,13 +14941,15 @@ "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" }, "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -15959,6 +14961,8 @@ "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" } @@ -15967,24 +14971,22 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, "node_modules/module-details-from-path": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", - "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==" + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" }, "node_modules/motion-dom": { "version": "11.18.1", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", "dependencies": { "motion-utils": "^11.18.1" } @@ -15992,13 +14994,15 @@ "node_modules/motion-utils": { "version": "11.18.1", "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", - "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==" + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -16006,44 +15010,43 @@ "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==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/multiformats": { "version": "13.4.2", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.4.2.tgz", - "integrity": "sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ==" + "integrity": "sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ==", + "license": "Apache-2.0 OR MIT" }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, - "node_modules/nan": { - "version": "2.26.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", - "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", - "optional": true - }, "node_modules/nanoassert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", - "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==" + "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==", + "license": "ISC" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -16051,22 +15054,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==" - }, - "node_modules/napi-macros": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", - "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", - "optional": true - }, "node_modules/napi-postinstall": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", "dev": true, + "license": "MIT", "bin": { "napi-postinstall": "lib/cli.js" }, @@ -16081,34 +15074,30 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/neotraverse": { "version": "0.6.18", "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "license": "MIT", "engines": { "node": ">= 10" } }, - "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/next": { "version": "16.1.6", "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", + "license": "MIT", "dependencies": { "@next/env": "16.1.6", "@swc/helpers": "0.5.15", @@ -16158,9 +15147,10 @@ } }, "node_modules/next-auth": { - "version": "4.24.13", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.13.tgz", - "integrity": "sha512-sgObCfcfL7BzIK76SS5TnQtc3yo2Oifp/yIpfv6fMfeBOiBJkDWF3A2y9+yqnmJ4JKc2C+nMjSjmgDeTwgN1rQ==", + "version": "4.24.14", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.14.tgz", + "integrity": "sha512-YRz6xFDXKUwiXSMMChbrBEWyFktZ1qZXEgeSHQQ3nsy08B4c/xLk6REeutRsIFwkjY/1+ShHnu07DN3JeJguig==", + "license": "ISC", "dependencies": { "@babel/runtime": "^7.20.13", "@panva/hkdf": "^1.0.2", @@ -16192,6 +15182,8 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -16214,6 +15206,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -16224,135 +15217,115 @@ } }, "node_modules/nice-grpc": { - "version": "2.1.14", - "resolved": "https://registry.npmjs.org/nice-grpc/-/nice-grpc-2.1.14.tgz", - "integrity": "sha512-GK9pKNxlvnU5FAdaw7i2FFuR9CqBspcE+if2tqnKXBcE0R8525wj4BZvfcwj7FjvqbssqKxRHt2nwedalbJlww==", + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/nice-grpc/-/nice-grpc-2.1.16.tgz", + "integrity": "sha512-Cl3Pn00212Hl8/U6bpgMxmhZj5lyv3nWoJov4cd3FjWarktrMHP4DNvSjCnDwkMWYx4W1tyscEia4JX6Y4GVCQ==", + "license": "MIT", "dependencies": { "@grpc/grpc-js": "^1.14.0", - "abort-controller-x": "^0.4.0", - "nice-grpc-common": "^2.0.2" + "abort-controller-x": "^0.5.0", + "nice-grpc-common": "^2.0.3" } }, "node_modules/nice-grpc-client-middleware-retry": { - "version": "3.1.13", - "resolved": "https://registry.npmjs.org/nice-grpc-client-middleware-retry/-/nice-grpc-client-middleware-retry-3.1.13.tgz", - "integrity": "sha512-Q9I/wm5lYkDTveKFirrTHBkBY137yavXZ4xQDXTPIycUp7aLXD8xPTHFhqtAFWUw05aS91uffZZRgdv3HS0y/g==", + "version": "3.1.15", + "resolved": "https://registry.npmjs.org/nice-grpc-client-middleware-retry/-/nice-grpc-client-middleware-retry-3.1.15.tgz", + "integrity": "sha512-fXfNNdtjCQzc3O/w3WsK1AOU+xdE1V7FCm4FEQWS/UUVsV1616S2oryvWqsZAF8aOvuMir8lFtNmgH3DeP+PBg==", + "license": "MIT", "dependencies": { - "abort-controller-x": "^0.4.0", - "nice-grpc-common": "^2.0.2" + "abort-controller-x": "^0.5.0", + "nice-grpc-common": "^2.0.3" } }, + "node_modules/nice-grpc-client-middleware-retry/node_modules/abort-controller-x": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.5.0.tgz", + "integrity": "sha512-yTt9CI0x+nRfX6BFMenEGP8ooPvErGH6AbFz20C2IeOLIlDsrw/VHpgne3GsCEuTA410IiFiaLVFKmgM4bKEPQ==", + "license": "MIT" + }, "node_modules/nice-grpc-common": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/nice-grpc-common/-/nice-grpc-common-2.0.2.tgz", - "integrity": "sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/nice-grpc-common/-/nice-grpc-common-2.0.3.tgz", + "integrity": "sha512-MEhnD3JMah0mgyivpb9hpRDbOBuXBxI/TVO+OK1h6rC97WM42HsPMR+zzRNQ0C5BqYJTw1nyWiQRD0DucO+pjQ==", + "license": "MIT", "dependencies": { "ts-error": "^1.0.6" } }, "node_modules/nice-grpc-opentelemetry": { - "version": "0.1.20", - "resolved": "https://registry.npmjs.org/nice-grpc-opentelemetry/-/nice-grpc-opentelemetry-0.1.20.tgz", - "integrity": "sha512-dRH6lmm8OgqY21WRo9BP6cHHqIhbG5UT/INFne0qIDSlSseYc6s1+qNTE3Up0z/4zY50V8tVTOH30yyhkwNXTw==", + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/nice-grpc-opentelemetry/-/nice-grpc-opentelemetry-0.1.22.tgz", + "integrity": "sha512-Azmn6JhkDeenXk6jag5tq7cRrp7UqIOsNVjtchmXjZp3BaSMI3E8FVk1DSaT+QjO59ftU0tqOofeE/5MixiZKw==", + "license": "MIT", "dependencies": { "@opentelemetry/api": "^1.8.0", "@opentelemetry/semantic-conventions": "^1.22.0", - "abort-controller-x": "^0.4.0", + "abort-controller-x": "^0.5.0", "ipaddr.js": "^2.0.1", - "nice-grpc-common": "^2.0.2" + "nice-grpc-common": "^2.0.3" } }, + "node_modules/nice-grpc-opentelemetry/node_modules/abort-controller-x": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.5.0.tgz", + "integrity": "sha512-yTt9CI0x+nRfX6BFMenEGP8ooPvErGH6AbFz20C2IeOLIlDsrw/VHpgne3GsCEuTA410IiFiaLVFKmgM4bKEPQ==", + "license": "MIT" + }, "node_modules/nice-grpc-web": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/nice-grpc-web/-/nice-grpc-web-3.3.9.tgz", - "integrity": "sha512-CiCQLdLTux9D4try8XlHW9tHIP/uLB+aciNKErDNLUM6kzhPFaVh8q+oTkoVGOjxOacEzlOwQRRjwQETAx5lVw==", + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/nice-grpc-web/-/nice-grpc-web-3.3.10.tgz", + "integrity": "sha512-8XyCtbs7uL0mWQEjpkjZy57bnLbtheRbIWgj8p98XPbjFqXOBkTLu+ebj5H4fUu/yxqt+6ULPPDHT/icUsyieA==", + "license": "MIT", "dependencies": { - "abort-controller-x": "^0.4.0", + "abort-controller-x": "^0.5.0", "isomorphic-ws": "^5.0.0", "js-base64": "^3.7.2", - "nice-grpc-common": "^2.0.2" + "nice-grpc-common": "^2.0.3" } }, + "node_modules/nice-grpc-web/node_modules/abort-controller-x": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.5.0.tgz", + "integrity": "sha512-yTt9CI0x+nRfX6BFMenEGP8ooPvErGH6AbFz20C2IeOLIlDsrw/VHpgne3GsCEuTA410IiFiaLVFKmgM4bKEPQ==", + "license": "MIT" + }, "node_modules/nice-grpc-web/node_modules/isomorphic-ws": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "license": "MIT", "peerDependencies": { "ws": "*" } }, - "node_modules/node-abi": { - "version": "3.89.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", - "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "node_modules/nice-grpc/node_modules/abort-controller-x": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.5.0.tgz", + "integrity": "sha512-yTt9CI0x+nRfX6BFMenEGP8ooPvErGH6AbFz20C2IeOLIlDsrw/VHpgne3GsCEuTA410IiFiaLVFKmgM4bKEPQ==", + "license": "MIT" }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "license": "MIT" }, "node_modules/node-addon-api": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", - "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.8.0.tgz", + "integrity": "sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA==", + "license": "MIT", "optional": true, "engines": { "node": "^18 || ^20 || >= 21" } }, - "node_modules/node-datachannel": { - "version": "0.32.1", - "resolved": "https://registry.npmjs.org/node-datachannel/-/node-datachannel-0.32.1.tgz", - "integrity": "sha512-r4UdtA0lCsz6XrG84pJ6lntAyw/MHpmBOhEkg5UQcmWTEpANqCPkMos6rj/QZDdq3GBUsdI/wst5acwWUiibCA==", - "hasInstallScript": true, - "dependencies": { - "prebuild-install": "^7.1.3" - }, - "engines": { - "node": ">=18.20.0" - } - }, - "node_modules/node-domexception": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-2.0.2.tgz", - "integrity": "sha512-Qf9vHK9c5MGgUXj8SnucCIS4oEPuUstjRaMplLGeZpbWMfNV1rvEcXuwoXfN51dUfD1b4muPHPQtCx/5Dj/QAA==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=16" - } - }, "node_modules/node-exports-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", "dev": true, + "license": "MIT", "dependencies": { "array.prototype.flatmap": "^1.3.3", "es-errors": "^1.3.0", @@ -16366,10 +15339,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -16385,32 +15369,18 @@ } } }, - "node_modules/node-fetch-commonjs": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch-commonjs/-/node-fetch-commonjs-3.3.2.tgz", - "integrity": "sha512-VBlAiynj3VMLrotgwOS3OyECFxas5y7ltLcK4t41lMUZeaK15Ym4QRkqN0EQKAFL42q9i21EPKjzLUPfltR72A==", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/node-fetch-native": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/node-gyp-build": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -16422,17 +15392,24 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==" + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/nofilter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "license": "MIT", "engines": { "node": ">=12.19" } @@ -16441,14 +15418,16 @@ "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/nostr-tools": { - "version": "2.23.3", - "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.23.3.tgz", - "integrity": "sha512-AALyt9k8xPdF4UV2mlLJ2mgCn4kpTB0DZ8t2r6wjdUh6anfx2cTVBsHUlo9U0EY/cKC5wcNyiMAmRJV5OVEalA==", + "version": "2.23.5", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.23.5.tgz", + "integrity": "sha512-Fa7ZlUdjfUW1P4E7H3yBexhOHYi18XNyvd2n7eNHkYR085xADX6Y8V8Vm7nT/XQajaFOBrptXmVIGkJ2E4vfVw==", + "license": "Unlicense", "dependencies": { "@noble/ciphers": "2.1.1", "@noble/curves": "2.0.1", @@ -16458,19 +15437,35 @@ "@scure/bip39": "2.0.1", "nostr-wasm": "0.1.0" }, - "peerDependencies": { - "typescript": ">=5.0.0" + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/nostr-tools/node_modules/@noble/curves": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", + "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.0.1" + }, + "engines": { + "node": ">= 20.19.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/nostr-tools/node_modules/@noble/hashes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", + "license": "MIT", "engines": { "node": ">= 20.19.0" }, @@ -16482,6 +15477,34 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.0.0.tgz", "integrity": "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/nostr-tools/node_modules/@scure/bip32": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-2.0.1.tgz", + "integrity": "sha512-4Md1NI5BzoVP+bhyJaY3K6yMesEFzNS1sE/cP+9nuvE7p/b0kx9XbpDHHFl8dHtufcbdHRUUQdRqLIPHN/s7yA==", + "license": "MIT", + "dependencies": { + "@noble/curves": "2.0.1", + "@noble/hashes": "2.0.1", + "@scure/base": "2.0.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/nostr-tools/node_modules/@scure/bip39": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-2.0.1.tgz", + "integrity": "sha512-PsxdFj/d2AcJcZDX1FXN3dDgitDDTmwf78rKZq1a6c1P1Nan1X/Sxc7667zU3U+AN60g7SxxP0YCVw2H/hBycg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.0.1", + "@scure/base": "2.0.0" + }, "funding": { "url": "https://paulmillr.com/funding/" } @@ -16489,7 +15512,8 @@ "node_modules/nostr-wasm": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/nostr-wasm/-/nostr-wasm-0.1.0.tgz", - "integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==" + "integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==", + "license": "MIT" }, "node_modules/npm": { "version": "9.9.4", @@ -16567,6 +15591,7 @@ "which", "write-file-atomic" ], + "license": "Artistic-2.0", "workspaces": [ "docs", "smoke-tests", @@ -16659,6 +15684,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -19527,14 +18553,15 @@ "license": "ISC" }, "node_modules/nypm": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.5.tgz", - "integrity": "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.6.tgz", + "integrity": "sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q==", "devOptional": true, + "license": "MIT", "dependencies": { - "citty": "^0.2.0", + "citty": "^0.2.2", "pathe": "^2.0.3", - "tinyexec": "^1.0.2" + "tinyexec": "^1.1.1" }, "bin": { "nypm": "dist/cli.mjs" @@ -19544,20 +18571,23 @@ } }, "node_modules/nypm/node_modules/citty": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.1.tgz", - "integrity": "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==", - "devOptional": true + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", + "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", + "devOptional": true, + "license": "MIT" }, "node_modules/oauth": { "version": "0.9.15", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", - "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==", + "license": "MIT" }, "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" } @@ -19566,6 +18596,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "license": "MIT", "engines": { "node": ">= 6" } @@ -19575,6 +18606,7 @@ "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" }, @@ -19587,6 +18619,7 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -19596,6 +18629,7 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -19616,6 +18650,7 @@ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -19631,6 +18666,7 @@ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -19649,6 +18685,7 @@ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -19663,6 +18700,7 @@ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -19680,12 +18718,14 @@ "version": "2.0.11", "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/oidc-token-hash": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.2.0.tgz", "integrity": "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw==", + "license": "MIT", "engines": { "node": "^10.13.0 || >=12.0.0" } @@ -19694,6 +18734,7 @@ "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" } @@ -19703,6 +18744,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -19717,6 +18759,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/openapi-path-templating/-/openapi-path-templating-2.2.1.tgz", "integrity": "sha512-eN14VrDvl/YyGxxrkGOHkVkWEoPyhyeydOUrbvjoz8K5eIGgELASwN1eqFOJ2CTQMGCy2EntOK1KdtJ8ZMekcg==", + "license": "Apache-2.0", "dependencies": { "apg-lite": "^1.0.4" }, @@ -19728,6 +18771,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/openapi-server-url-templating/-/openapi-server-url-templating-1.3.0.tgz", "integrity": "sha512-DPlCms3KKEbjVQb0spV6Awfn6UWNheuG/+folQPzh/wUaKwuqvj8zt5gagD7qoyxtE03cIiKPgLFS3Q8Bz00uQ==", + "license": "Apache-2.0", "dependencies": { "apg-lite": "^1.0.4" }, @@ -19739,6 +18783,7 @@ "version": "12.1.3", "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "license": "MIT", "peer": true }, "node_modules/opener": { @@ -19746,6 +18791,7 @@ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true, + "license": "(WTFPL OR MIT)", "bin": { "opener": "bin/opener-bin.js" } @@ -19754,6 +18800,7 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz", "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==", + "license": "MIT", "dependencies": { "jose": "^4.15.9", "lru-cache": "^6.0.0", @@ -19768,6 +18815,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -19778,13 +18826,15 @@ "node_modules/openid-client/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -19802,6 +18852,7 @@ "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", @@ -19819,6 +18870,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -19834,6 +18886,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -19845,11 +18898,12 @@ } }, "node_modules/p-queue": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.1.0.tgz", - "integrity": "sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.0.tgz", + "integrity": "sha512-7NED7xhQ74Ngp4JP/2e0VZHp7vSWfJfqeiR92jPgxsz6m0Se4P03YoTKa9dDXyZ3r6P616gUXttrB6nnHYKang==", + "license": "MIT", "dependencies": { - "eventemitter3": "^5.0.1", + "eventemitter3": "^5.0.4", "p-timeout": "^7.0.0" }, "engines": { @@ -19863,6 +18917,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", + "license": "MIT", "engines": { "node": ">=20" }, @@ -19875,6 +18930,7 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -19882,18 +18938,21 @@ "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" }, "node_modules/papaparse": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", - "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==" + "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==", + "license": "MIT" }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -19905,6 +18964,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", @@ -19922,13 +18982,15 @@ "node_modules/parse-entities/node_modules/@types/unist": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -19942,44 +19004,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-torrent": { - "version": "11.0.19", - "resolved": "https://registry.npmjs.org/parse-torrent/-/parse-torrent-11.0.19.tgz", - "integrity": "sha512-T0lEkDdFVQsy0YxHIKjzDHSgt/yl57f3INs5jl7OZqAm77XDF0FgRgrv3LCKgSqsTOrMwYaF0t2761WKdvhgig==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "bencode": "^4.0.0", - "cross-fetch-ponyfill": "^1.0.3", - "get-stdin": "^9.0.0", - "magnet-uri": "^7.0.7", - "queue-microtask": "^1.2.3", - "uint8-util": "^2.2.5" - }, - "bin": { - "parse-torrent": "bin/cmd.js" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -19988,6 +19018,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -19995,12 +19026,14 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" }, "node_modules/path-scurry": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" @@ -20013,9 +19046,10 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.0.tgz", + "integrity": "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } @@ -20024,12 +19058,14 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/pbkdf2": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "license": "MIT", "dependencies": { "create-hash": "^1.2.0", "create-hmac": "^1.1.7", @@ -20042,21 +19078,62 @@ "node": ">= 0.10" } }, + "node_modules/peerjs": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/peerjs/-/peerjs-1.5.5.tgz", + "integrity": "sha512-viMUCPDL6CSfOu0ZqVcFqbWRXNHIbv2lPqNbrBIjbFYrflebOjItJ4hPfhjnuUCstqciHVu9vVJ7jFqqKi/EuQ==", + "license": "MIT", + "dependencies": { + "@msgpack/msgpack": "^2.8.0", + "eventemitter3": "^4.0.7", + "peerjs-js-binarypack": "^2.1.0", + "webrtc-adapter": "^9.0.0" + }, + "engines": { + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/peer" + } + }, + "node_modules/peerjs-js-binarypack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/peerjs-js-binarypack/-/peerjs-js-binarypack-2.1.0.tgz", + "integrity": "sha512-YIwCC+pTzp3Bi8jPI9UFKO0t0SLo6xALnHkiNt/iUFmUUZG0fEEmEyFKvjsDKweiFitzHRyhuh6NvyJZ4nNxMg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/peer" + } + }, + "node_modules/peerjs/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/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -20064,15 +19141,11 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/piece-length": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/piece-length/-/piece-length-2.0.1.tgz", - "integrity": "sha512-dBILiDmm43y0JPISWEmVGKBETQjwJe6mSU9GND+P9KW0SJGUwoU/odyH1nbalOP9i8WSYuqf1lQnaj92Bhw+Ug==" - }, "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -20081,6 +19154,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", "engines": { "node": ">= 6" } @@ -20090,6 +19164,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -20102,6 +19177,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -20115,6 +19191,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -20127,6 +19204,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -20142,6 +19220,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -20150,13 +19229,14 @@ } }, "node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", "devOptional": true, + "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", + "confbox": "^0.2.4", + "exsolve": "^1.0.8", "pathe": "^2.0.3" } }, @@ -20164,6 +19244,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/point-in-polygon-hao/-/point-in-polygon-hao-1.2.4.tgz", "integrity": "sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==", + "license": "MIT", "dependencies": { "robust-predicates": "^3.0.2" } @@ -20172,14 +19253,15 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -20194,8 +19276,9 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -20207,6 +19290,7 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -20219,6 +19303,27 @@ "postcss": "^8.0.0" } }, + "node_modules/postcss-import/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/postcss-js": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", @@ -20233,6 +19338,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" }, @@ -20243,47 +19349,6 @@ "postcss": "^8.4.21" } }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, "node_modules/postcss-nested": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", @@ -20298,6 +19363,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.1.1" }, @@ -20312,6 +19378,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -20323,18 +19390,21 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" }, "node_modules/potpack": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/preact": { "version": "10.24.3", "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -20344,6 +19414,7 @@ "version": "5.2.6", "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz", "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==", + "license": "MIT", "dependencies": { "pretty-format": "^3.8.0" }, @@ -20354,48 +19425,25 @@ "node_modules/preact-render-to-string/node_modules/pretty-format": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", - "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" - }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==", + "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -20411,6 +19459,7 @@ "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.14.tgz", "integrity": "sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.21.3" }, @@ -20493,14 +19542,16 @@ } }, "node_modules/pretty-format": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", - "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", + "@jest/schemas": "30.4.1", "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -20511,6 +19562,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -20519,14 +19571,15 @@ } }, "node_modules/prisma": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.2.tgz", - "integrity": "sha512-XTKeKxtQElcq3U9/jHyxSPgiRgeYDKxWTPOf6NkXA0dNj5j40MfEsZkMbyNpwDWCUv7YBFUl7I2VK/6ALbmhEg==", + "version": "6.19.3", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.3.tgz", + "integrity": "sha512-++ZJ0ijLrDJF6hNB4t4uxg2br3fC4H9Yc9tcbjr2fcNFP3rh/SBNrAgjhsqBU4Ght8JPrVofG/ZkXfnSfnYsFg==", "devOptional": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/config": "6.19.2", - "@prisma/engines": "6.19.2" + "@prisma/config": "6.19.3", + "@prisma/engines": "6.19.3" }, "bin": { "prisma": "build/index.js" @@ -20547,6 +19600,7 @@ "version": "1.30.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", "engines": { "node": ">=6" } @@ -20555,6 +19609,7 @@ "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -20562,18 +19617,21 @@ "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==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" }, "node_modules/progress-events": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.1.tgz", - "integrity": "sha512-MOzLIwhpt64KIVN64h1MwdKWiyKFNc/S6BoYKPIVUHFg0/eIEyBulhWCgn678v/4c0ri3FdGuzXymNCv02MUIw==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.1.0.tgz", + "integrity": "sha512-82DVc5tI36neVB3IjdXR11ztwGuoBc98em9ijzubeZKxI47OlV2Znq6mlPqE5xPDzO2Uw98GHiQSjj2favBCRQ==", + "license": "Apache-2.0 OR MIT" }, "node_modules/promise-worker-transferable": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "is-promise": "^2.1.0", "lie": "^3.0.2" @@ -20583,44 +19641,42 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/protobufjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", - "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.1.tgz", + "integrity": "sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg==", "hasInstallScript": true, + "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", + "@protobufjs/inquire": "^1.1.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", - "long": "^5.0.0" + "long": "^5.3.2" }, "engines": { "node": ">=12.0.0" @@ -20630,17 +19686,9 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "license": "MIT", + "engines": { + "node": ">=10" } }, "node_modules/punycode": { @@ -20648,6 +19696,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -20666,12 +19715,14 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ] + ], + "license": "MIT" }, "node_modules/pvtsutils": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", "dependencies": { "tslib": "^2.8.1" } @@ -20680,6 +19731,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", "engines": { "node": ">=16.0.0" } @@ -20688,6 +19740,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/qrcode-svg/-/qrcode-svg-1.1.0.tgz", "integrity": "sha512-XyQCIXux1zEIA3NPb0AeR8UMYvXZzWEhgdBgBjH9gO7M48H9uoHzviNz8pXw3UzrAcxRRRn9gxHewAVK7bn9qw==", + "license": "MIT", "bin": { "qrcode-svg": "bin/qrcode-svg.js" } @@ -20695,7 +19748,8 @@ "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -20714,17 +19768,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + ], + "license": "MIT" }, "node_modules/ramda": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz", "integrity": "sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/ramda" @@ -20734,6 +19785,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ramda-adjunct/-/ramda-adjunct-5.1.0.tgz", "integrity": "sha512-8qCpl2vZBXEJyNbi4zqcgdfHtcdsWjOGbiNSEnEBrM6Y0OKOT8UxJbIVGm1TIcjaSu2MxaWcgtsNlKlCk7o7qg==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.3" }, @@ -20749,6 +19801,7 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz", "integrity": "sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==", + "license": "MIT", "dependencies": { "drange": "^1.0.2", "ret": "^0.2.0" @@ -20757,84 +19810,21 @@ "node": ">=4" } }, - "node_modules/random-access-file": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/random-access-file/-/random-access-file-4.1.2.tgz", - "integrity": "sha512-GQM6R78DceZDcQod8KxlDFwXIiUvlvuy1EOzxTDsjuDjW5NlnlZi0MOk6iI4itAj/2vcvdqcEExYbVpC/dJcEw==", - "dependencies": { - "bare-fs": "^4.0.1", - "bare-path": "^3.0.0", - "random-access-storage": "^3.0.0" - }, - "optionalDependencies": { - "fs-native-extensions": "^1.3.1" - } - }, - "node_modules/random-access-storage": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/random-access-storage/-/random-access-storage-3.0.2.tgz", - "integrity": "sha512-Es9maUyWdJXWKckKy9s1+vT+DEgAt+PBb9lxPaake/0EDUsHehloKGv9v1zimS2V3gpFAcQXubvc1Rgci2sDPQ==", - "dependencies": { - "bare-events": "^2.2.0", - "queue-tick": "^1.0.0" - } - }, - "node_modules/random-iterate": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/random-iterate/-/random-iterate-1.0.1.tgz", - "integrity": "sha512-Jdsdnezu913Ot8qgKgSgs63XkAjEsnMcS1z+cC6D6TNXsUXsMxy0RpclF2pzGZTEiTXL9BiArdGTEexcv4nqcA==" - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } }, - "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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rc4": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/rc4/-/rc4-0.1.5.tgz", - "integrity": "sha512-xdDTNV90z5x5u25Oc871Xnvu7yAr4tV7Eluh0VSvrhUkry39q1k+zkz7xroqHbRq+8PiazySHJPArqifUvz9VA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rc9": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", "devOptional": true, + "license": "MIT", "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" @@ -20844,6 +19834,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-5.0.0.tgz", "integrity": "sha512-g8OUrgMXAR9ys/ZuJVfBr05sPPoMA7nHIVs8VEvg9QwM5W4GR2qSFEEHjsyHF1eWlBaf8Ev40WNjQFQ+nJTO3w==", + "license": "BSD-3-Clause", "dependencies": { "setimmediate": "^1.0.5" }, @@ -20855,6 +19846,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -20867,6 +19859,7 @@ "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.3.tgz", "integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==", "dev": true, + "license": "MIT", "dependencies": { "prop-types": "^15.6.0" }, @@ -20878,6 +19871,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", + "license": "MIT", "dependencies": { "copy-to-clipboard": "^3.3.1", "prop-types": "^15.8.1" @@ -20890,6 +19884,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.3.0.tgz", "integrity": "sha512-VEqkvs8JvY/IIZvh71Z0TC+mdbxERvYF33RcebnodlsUZ8RSgyKe2VWaHXv4+/8aoOgXLxWrdsYs2hDhcwbUgA==", + "license": "MIT", "dependencies": { "lodash.debounce": "^4", "prop-types": "^15.8.1" @@ -20902,6 +19897,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -20914,6 +19910,7 @@ "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } @@ -20922,6 +19919,7 @@ "version": "14.4.1", "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.4.1.tgz", "integrity": "sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==", + "license": "MIT", "dependencies": { "attr-accept": "^2.2.4", "file-selector": "^2.1.0", @@ -20935,9 +19933,10 @@ } }, "node_modules/react-hook-form": { - "version": "7.72.0", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.72.0.tgz", - "integrity": "sha512-V4v6jubaf6JAurEaVnT9aUPKFbNtDgohj5CIgVGyPHvT9wRx5OZHVjz31GsxnPNI278XMu+ruFz+wGOscHaLKw==", + "version": "7.76.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.76.1.tgz", + "integrity": "sha512-rYM7tPiWlu3nZchkR/ex7piyzui2vFPyaLnXnI/RnblB/L4qfMmyses8llJVtF1NpE9WBBsJlGtcSZzPCXW1qQ==", + "license": "MIT", "engines": { "node": ">=18.0.0" }, @@ -20953,6 +19952,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/react-immutable-proptypes/-/react-immutable-proptypes-2.2.0.tgz", "integrity": "sha512-Vf4gBsePlwdGvSZoLSBfd4HAP93HDauMY4fDjXhreg/vg6F3Fj/MXDNyTbltPC/xZKmZc+cjLu3598DdYK6sgQ==", + "license": "MIT", "dependencies": { "invariant": "^2.2.2" }, @@ -20964,6 +19964,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/react-immutable-pure-component/-/react-immutable-pure-component-2.2.2.tgz", "integrity": "sha512-vkgoMJUDqHZfXXnjVlG3keCxSO/U6WeDQ5/Sl0GK2cH8TOxEzQ5jXqDXHEL/jqk6fsNxV05oH5kD7VNMUE2k+A==", + "license": "MIT", "peerDependencies": { "immutable": ">= 2 || >= 4.0.0-rc", "react": ">= 16.6", @@ -20974,19 +19975,38 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==", + "license": "MIT", "peerDependencies": { "react": "^16.8.4 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-is-18": { + "name": "react-is", "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is-19": { + "name": "react-is", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", + "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", + "dev": true, + "license": "MIT" }, "node_modules/react-markdown": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -21014,6 +20034,7 @@ "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.21.0" @@ -21026,9 +20047,10 @@ } }, "node_modules/react-redux": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", - "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", + "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", + "license": "MIT", "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -21051,6 +20073,7 @@ "version": "2.7.2", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", @@ -21075,6 +20098,7 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" @@ -21096,6 +20120,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", @@ -21110,6 +20135,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" @@ -21131,6 +20157,7 @@ "version": "16.1.1", "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-16.1.1.tgz", "integrity": "sha512-PjVawBGy80C6YbC5DDZJeUjBmC7skaoEUdvfFQediQHgCL7aKyVHe57SaJGfQsloGDac+gCpTfRdtxzWWKmCXA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", "highlight.js": "^10.4.1", @@ -21150,6 +20177,7 @@ "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -21166,6 +20194,7 @@ "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz", "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", "dev": true, + "license": "MIT", "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13" @@ -21180,6 +20209,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", "dependencies": { "pify": "^2.3.0" } @@ -21188,6 +20218,7 @@ "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", @@ -21200,6 +20231,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "devOptional": true, + "license": "MIT", "engines": { "node": ">= 14.18.0" }, @@ -21212,6 +20244,8 @@ "version": "2.15.4", "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "deprecated": "1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide", + "license": "MIT", "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", @@ -21234,6 +20268,7 @@ "version": "0.4.5", "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", "dependencies": { "decimal.js-light": "^2.4.1" } @@ -21241,38 +20276,26 @@ "node_modules/recharts/node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "node_modules/record-cache": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/record-cache/-/record-cache-1.2.0.tgz", - "integrity": "sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw==", - "dependencies": { - "b4a": "^1.3.1" - } + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" }, - "node_modules/record-cache/node_modules/b4a": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } - } + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" }, "node_modules/redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" }, "node_modules/redux-immutable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/redux-immutable/-/redux-immutable-4.0.0.tgz", "integrity": "sha512-SchSn/DWfGb3oAejd+1hhHx01xUoxY+V7TeK0BKqpkLKiQPVFf7DYzEaKmrEVxsWxielKfSK9/Xq66YyxgR1cg==", + "license": "BSD-3-Clause", "peerDependencies": { "immutable": "^3.8.1 || ^4.0.0-rc.1" } @@ -21282,6 +20305,7 @@ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -21303,6 +20327,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/refractor/-/refractor-5.0.0.tgz", "integrity": "sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/prismjs": "^1.0.0", @@ -21319,6 +20344,7 @@ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -21338,6 +20364,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", @@ -21355,6 +20382,7 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -21370,6 +20398,7 @@ "version": "11.1.2", "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -21386,6 +20415,7 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", @@ -21400,6 +20430,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz", "integrity": "sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==", + "license": "MIT", "dependencies": { "argparse": "^1.0.10", "autolinker": "^3.11.0" @@ -21415,6 +20446,7 @@ "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" } @@ -21422,32 +20454,23 @@ "node_modules/remarkable/node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" }, "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", "engines": { "node": ">=0.10" } }, - "node_modules/require-addon": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz", - "integrity": "sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA==", - "optional": true, - "dependencies": { - "bare-addon-resolve": "^1.3.0" - }, - "engines": { - "bare": ">=1.10.0" - } - }, "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" } @@ -21456,7 +20479,7 @@ "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" } @@ -21465,6 +20488,7 @@ "version": "7.5.2", "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "license": "MIT", "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", @@ -21474,22 +20498,50 @@ "node": ">=8.6.0" } }, + "node_modules/require-in-the-middle/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "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==" + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" }, "node_modules/reselect": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", - "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz", + "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==", + "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -21508,6 +20560,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -21520,6 +20573,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -21529,6 +20583,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -21538,6 +20593,7 @@ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -21546,6 +20602,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "license": "MIT", "engines": { "node": ">=4" } @@ -21554,6 +20611,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -21563,6 +20621,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "license": "MIT", "dependencies": { "hash-base": "^3.1.2", "inherits": "^2.0.4" @@ -21574,7 +20633,8 @@ "node_modules/robust-predicates": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", - "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==" + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" }, "node_modules/run-parallel": { "version": "1.2.0", @@ -21594,68 +20654,30 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, - "node_modules/run-parallel-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", - "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/run-series": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", - "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, @@ -21670,7 +20692,8 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/safe-buffer": { "version": "5.2.1", @@ -21689,13 +20712,15 @@ "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", "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" @@ -21711,12 +20736,14 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/safe-regex-test": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -21729,45 +20756,51 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "engines": { - "node": ">=11.0.0" - } - }, "node_modules/scalus": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/scalus/-/scalus-0.14.2.tgz", - "integrity": "sha512-dobDMIUDUVhtxoX3ceGlaykKQGkph4HOE9hjkLsmwVgYf24fIik6YrZzVFrZSNCTvI2WN7hjEknehIrEJo1CMQ==" + "integrity": "sha512-dobDMIUDUVhtxoX3ceGlaykKQGkph4HOE9hjkLsmwVgYf24fIik6YrZzVFrZSNCTvI2WN7hjEknehIrEJo1CMQ==", + "license": "Apache-2.0" }, "node_modules/scheduler": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } }, + "node_modules/sdp": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.2.tgz", + "integrity": "sha512-xZocWwfyp4hkbN4hLWxMjmv2Q8aNa9MhmOZ7L9aCZPT+dZsgRr6wZRrSYE3HTdyk/2pZKPSgqI7ns7Een1xMSA==", + "license": "MIT" + }, "node_modules/seed-random": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", - "integrity": "sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==" + "integrity": "sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==", + "license": "MIT" }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "license": "ISC", "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/serialize-error": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -21782,6 +20815,7 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -21793,6 +20827,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -21810,6 +20845,7 @@ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -21825,6 +20861,7 @@ "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "dev": true, + "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", @@ -21837,12 +20874,14 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" }, "node_modules/sha.js": { "version": "2.4.12", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", @@ -21863,6 +20902,7 @@ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", "hasInstallScript": true, + "license": "Apache-2.0", "optional": true, "dependencies": { "@img/colour": "^1.0.0", @@ -21897,27 +20937,16 @@ "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" - } - }, - "node_modules/sharp/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" } }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -21929,6 +20958,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } @@ -21937,6 +20967,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/short-unique-id/-/short-unique-id-5.3.2.tgz", "integrity": "sha512-KRT/hufMSxXKEDSQujfVE0Faa/kZ51ihUcZQAcmP04t00DvPj7Ox5anHke1sJYUtzSuiT/Y5uyzg/W7bBEGhCg==", + "license": "Apache-2.0", "bin": { "short-unique-id": "bin/short-unique-id", "suid": "bin/short-unique-id" @@ -21947,6 +20978,7 @@ "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", "object-inspect": "^1.13.3", @@ -21962,13 +20994,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -21982,6 +21015,7 @@ "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", "es-errors": "^1.3.0", @@ -22000,6 +21034,7 @@ "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", "es-errors": "^1.3.0", @@ -22018,6 +21053,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { "node": ">=14" }, @@ -22025,59 +21061,18 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/simplesignal": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/simplesignal/-/simplesignal-2.1.7.tgz", - "integrity": "sha512-PEo2qWpUke7IMhlqiBxrulIFvhJRLkl1ih52Rwa+bPjzhJepcd4GIjn2RiQmFSx3dQvsEAgF0/lXMwMN7vODaA==" + "integrity": "sha512-PEo2qWpUke7IMhlqiBxrulIFvhJRLkl1ih52Rwa+bPjzhJepcd4GIjn2RiQmFSx3dQvsEAgF0/lXMwMN7vODaA==", + "license": "MIT" }, "node_modules/sirv": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", "dev": true, + "license": "MIT", "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", @@ -22092,45 +21087,17 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks/node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", - "engines": { - "node": ">= 12" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -22139,6 +21106,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -22148,6 +21116,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -22157,47 +21126,31 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/speed-limiter": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/speed-limiter/-/speed-limiter-1.0.2.tgz", - "integrity": "sha512-Ax+TbUOho84bWUc3AKqWtkIvAIVws7d6QI4oJkgH4yQ5Yil+lR3vjd/7qd51dHKGzS5bFxg0++QwyNRN7s6rZA==", - "dependencies": { - "limiter": "^1.1.5", - "streamx": "^2.10.3" - } - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -22210,6 +21163,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -22219,6 +21173,7 @@ "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz", "integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/three": "*", "three": "^0.170.0" @@ -22232,19 +21187,22 @@ "version": "0.170.0", "resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz", "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/stats.js": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" @@ -22262,27 +21220,28 @@ } }, "node_modules/streamx": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", - "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", + "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", + "license": "MIT", "dependencies": { + "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" } }, "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==" + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -22295,6 +21254,7 @@ "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", @@ -22307,13 +21267,15 @@ "node_modules/string-width/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==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -22328,6 +21290,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -22355,6 +21318,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, + "license": "MIT", "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -22365,6 +21329,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", @@ -22386,6 +21351,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", @@ -22404,6 +21370,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -22416,22 +21383,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string2compact": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/string2compact/-/string2compact-2.0.1.tgz", - "integrity": "sha512-Bm/T8lHMTRXw+u83LE+OW7fXmC/wM+Mbccfdo533ajSBNxddDHlRrvxE49NdciGHgXkUQM5WYskJ7uTkbBUI0A==", - "dependencies": { - "addr-to-ip-port": "^2.0.0", - "ipaddr.js": "^2.0.0" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/stringify-entities": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" @@ -22445,6 +21401,7 @@ "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" }, @@ -22457,6 +21414,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -22466,6 +21424,7 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -22475,6 +21434,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -22486,6 +21446,7 @@ "version": "1.1.21", "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", "dependencies": { "style-to-object": "1.0.14" } @@ -22494,6 +21455,7 @@ "version": "1.0.14", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", "dependencies": { "inline-style-parser": "0.2.7" } @@ -22502,6 +21464,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", "dependencies": { "client-only": "0.0.1" }, @@ -22524,6 +21487,7 @@ "version": "3.35.1", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -22545,6 +21509,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", "engines": { "node": ">= 6" } @@ -22553,6 +21518,7 @@ "version": "2.2.6", "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "license": "MIT", "dependencies": { "copy-anything": "^4" }, @@ -22565,6 +21531,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -22576,6 +21543,7 @@ "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==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -22588,59 +21556,65 @@ "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", "dev": true, + "license": "MIT", "peerDependencies": { "react": ">=17.0" } }, "node_modules/swagger-client": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.37.1.tgz", - "integrity": "sha512-WCRU7wfyqTyB0vOpVK1vHFm4aCqnmqcXycDcWVmHa784Nd4cABaQeSITtjWMOnjJoIkTqG8TLArYn4SAv+wj2w==", + "version": "3.37.4", + "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.37.4.tgz", + "integrity": "sha512-3xxqc9s99Vsf47ket2j7D4Tw6b6T7ObNvTqSP009yBeoAo0fy0yprqOVxFISTrvRxN7jgfrEi8GXMhsjzb1M0g==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.22.15", "@scarf/scarf": "=1.4.0", - "@swagger-api/apidom-core": "^1.7.0", - "@swagger-api/apidom-error": "^1.7.0", - "@swagger-api/apidom-json-pointer": "^1.7.0", - "@swagger-api/apidom-ns-openapi-3-1": "^1.7.0", - "@swagger-api/apidom-ns-openapi-3-2": "^1.7.0", - "@swagger-api/apidom-reference": "^1.7.0", + "@swagger-api/apidom-core": "^1.11.0", + "@swagger-api/apidom-error": "^1.11.0", + "@swagger-api/apidom-json-pointer": "^1.11.0", + "@swagger-api/apidom-ns-openapi-3-1": "^1.11.0", + "@swagger-api/apidom-ns-openapi-3-2": "^1.11.0", + "@swagger-api/apidom-reference": "^1.11.0", "@swaggerexpert/cookie": "^2.0.2", "deepmerge": "~4.3.0", "fast-json-patch": "^3.0.0-1", "js-yaml": "^4.1.0", "neotraverse": "=0.6.18", "node-abort-controller": "^3.1.1", - "node-fetch-commonjs": "^3.3.2", "openapi-path-templating": "^2.2.1", "openapi-server-url-templating": "^1.3.0", "ramda": "^0.30.1", "ramda-adjunct": "^5.1.0" + }, + "engines": { + "node": ">=22" } }, "node_modules/swagger-jsdoc": { - "version": "6.2.8", - "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", - "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.3.0.tgz", + "integrity": "sha512-I+iQjVGV3t28pOkQUJv2MncthvOtkEactOn8R76SvSYhxgtIn7FoqfDHwQaN+GBnQdXQLrhgDXseKitmJcHMsA==", + "license": "MIT", "dependencies": { + "@apidevtools/swagger-parser": "^12.1.0", "commander": "6.2.0", "doctrine": "3.0.0", - "glob": "7.1.6", + "glob": "11.1.0", "lodash.mergewith": "^4.6.2", - "swagger-parser": "^10.0.3", "yaml": "2.0.0-1" }, "bin": { "swagger-jsdoc": "bin/swagger-jsdoc.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=20.0.0" } }, "node_modules/swagger-jsdoc/node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -22652,25 +21626,16 @@ "version": "2.0.0-1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==", + "license": "ISC", "engines": { "node": ">= 6" } }, - "node_modules/swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", - "dependencies": { - "@apidevtools/swagger-parser": "10.0.3" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/swagger-ui-react": { - "version": "5.32.1", - "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-5.32.1.tgz", - "integrity": "sha512-qW93qqMhVKrdOgwrsZ5AUh1SUgedXjQK442JEOjCelbm5o7rhI0XdgSlEHT/aOZ6wE7QAJOtTbV5NIf/pbomGg==", + "version": "5.32.6", + "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-5.32.6.tgz", + "integrity": "sha512-2q2kXd6eDR+syyWV5HE2CkWANyr2MHPkNezG4M7fC0FPlBUZEsNgyA/2dcb9dIwgE5xd995dO42h89fNMF5/ng==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.27.1", "@scarf/scarf": "=1.4.0", @@ -22679,12 +21644,12 @@ "classnames": "^2.5.1", "css.escape": "1.5.1", "deep-extend": "0.6.0", - "dompurify": "^3.3.2", + "dompurify": "^3.4.0", "ieee754": "^1.2.1", "immutable": "^3.x.x", "js-file-download": "^0.4.12", "js-yaml": "=4.1.1", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "prop-types": "^15.8.1", "randexp": "^0.5.3", "randombytes": "^2.1.0", @@ -22701,7 +21666,7 @@ "reselect": "^5.1.1", "serialize-error": "^8.1.0", "sha.js": "^2.4.12", - "swagger-client": "^3.37.1", + "swagger-client": "^3.37.4", "url-parse": "^1.5.10", "xml": "=1.0.1", "xml-but-prettier": "^1.0.1", @@ -22717,6 +21682,7 @@ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, + "license": "MIT", "dependencies": { "@pkgr/core": "^0.2.9" }, @@ -22731,6 +21697,7 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/dcastil" @@ -22740,6 +21707,7 @@ "version": "3.4.19", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -22776,6 +21744,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } @@ -22784,6 +21753,7 @@ "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", @@ -22807,6 +21777,7 @@ "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" }, @@ -22818,6 +21789,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -22833,6 +21805,7 @@ "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" }, @@ -22844,6 +21817,7 @@ "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } @@ -22852,6 +21826,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", "engines": { "node": ">= 6" } @@ -22860,6 +21835,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -22867,10 +21843,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, "node_modules/tailwindcss/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" }, @@ -22878,57 +21897,32 @@ "node": ">=8.10.0" } }, - "node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/tailwindcss/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "bin": { + "resolve": "bin/resolve" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/tar-stream/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/teex": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", "dependencies": { "streamx": "^2.12.5" } @@ -22938,6 +21932,7 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -22951,14 +21946,16 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" } }, "node_modules/text-decoder/node_modules/b4a": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" }, @@ -22972,6 +21969,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", "dependencies": { "any-promise": "^1.0.0" } @@ -22980,6 +21978,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -22990,12 +21989,14 @@ "node_modules/three": { "version": "0.168.0", "resolved": "https://registry.npmjs.org/three/-/three-0.168.0.tgz", - "integrity": "sha512-6m6jXtDwMJEK/GGMbAOTSAmxNdzKvvBzgd7q8bE/7Tr6m7PaBh5kKLrN7faWtlglXbzj7sVba48Idwx+NRsZXw==" + "integrity": "sha512-6m6jXtDwMJEK/GGMbAOTSAmxNdzKvvBzgd7q8bE/7Tr6m7PaBh5kKLrN7faWtlglXbzj7sVba48Idwx+NRsZXw==", + "license": "MIT" }, "node_modules/three-conic-polygon-geometry": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/three-conic-polygon-geometry/-/three-conic-polygon-geometry-2.1.2.tgz", - "integrity": "sha512-NaP3RWLJIyPGI+zyaZwd0Yj6rkoxm4FJHqAX1Enb4L64oNYLCn4bz1ESgOEYavgcUwCNYINu1AgEoUBJr1wZcA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/three-conic-polygon-geometry/-/three-conic-polygon-geometry-2.1.3.tgz", + "integrity": "sha512-7KYcgd7rYg91L8AnCEddeyhw4qlv9+8NAI0luHq7QGt26icWUGNCsvLyD+u6FPKjP+un3zGBi4JGzqgGpmBSWA==", + "license": "MIT", "dependencies": { "@turf/boolean-point-in-polygon": "^7.2", "d3-array": "1 - 3", @@ -23016,6 +22017,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/three-geojson-geometry/-/three-geojson-geometry-2.1.1.tgz", "integrity": "sha512-dC7bF3ri1goDcihYhzACHOBQqu7YNNazYLa2bSydVIiJUb3jDFojKSy+gNj2pMkqZNSVjssSmdY9zlmnhEpr1w==", + "license": "MIT", "dependencies": { "d3-geo": "1 - 3", "d3-interpolate": "1 - 3", @@ -23029,9 +22031,10 @@ } }, "node_modules/three-globe": { - "version": "2.45.1", - "resolved": "https://registry.npmjs.org/three-globe/-/three-globe-2.45.1.tgz", - "integrity": "sha512-82idHCkN8YOn+I93I6Tv9KtIb67Cgc3JFOLxvk0hL3iFhzIproT+XsreoI56ofYB3dSvD4FxZnk8jj6JjajrsQ==", + "version": "2.45.2", + "resolved": "https://registry.npmjs.org/three-globe/-/three-globe-2.45.2.tgz", + "integrity": "sha512-3qJE2LAdyHsUPt02mgMRc+PG3j9kGEA0fUYrwKPGIVtvMR1XjDn9hCXu31AWocdgHOFcXkrRVz7jJZzTIvR0eQ==", + "license": "MIT", "dependencies": { "@tweenjs/tween.js": "18 - 25", "accessor-fn": "1", @@ -23059,18 +22062,20 @@ } }, "node_modules/three-mesh-bvh": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.9.9.tgz", - "integrity": "sha512-FJKitcjvbALmeQRK+Sc+nLGorCpkrZBrbgJZFzhdyWboak37DZikn46hvQkNqSbJPm227ahYmS6k3N/GXaAyXw==", + "version": "0.9.10", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.9.10.tgz", + "integrity": "sha512-UOlTgPIeqUURcwaG8knxvBaruwZlC4X3/WSHEFO7rYvMVv/YNUrkfFEszvfj36pXV88dCHoHNnIp0PifkirnTQ==", "dev": true, + "license": "MIT", "peerDependencies": { "three": ">= 0.159.0" } }, "node_modules/three-slippy-map-globe": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/three-slippy-map-globe/-/three-slippy-map-globe-1.0.5.tgz", - "integrity": "sha512-e5ZUKclpflaX+0Nc9CQko3vYq4VLrjHiyMQsVpdtE4ztxpw/T9+LHzcxBgp7pvkTfo51UQV2BII+DZCclJOPHg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/three-slippy-map-globe/-/three-slippy-map-globe-1.0.6.tgz", + "integrity": "sha512-PCUR+X+1kYFYtQBf8+b/ct8xBHtnkeu7FItRYBeFxyIe3ksnGuLi0H9RAxAfVSSUsZVbKIKNz9q1atEjynrrkg==", + "license": "MIT", "dependencies": { "d3-geo": "1 - 3", "d3-octree": "^1.1", @@ -23088,6 +22093,7 @@ "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.36.1.tgz", "integrity": "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==", "dev": true, + "license": "MIT", "dependencies": { "@types/draco3d": "^1.4.0", "@types/offscreencanvas": "^2019.6.4", @@ -23104,55 +22110,39 @@ "version": "0.6.10", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "node_modules/throughput": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/throughput/-/throughput-1.0.2.tgz", - "integrity": "sha512-jvK1ZXuhsggjb3qYQjMiU/AVYYiTeqT5thWvYR2yuy2LGM84P5MSSyAinwHahGsdBYKR9m9HncVR/3f3nFKkxg==" - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "node_modules/timeout-refresh": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-1.0.3.tgz", - "integrity": "sha512-Mz0CX4vBGM5lj8ttbIFt7o4ZMxk/9rgudJRh76EvB7xXZMur7T/cjRiH2w4Fmkq0zxf2QpM8IFvOSRn8FEu3gA==", - "optional": true + "dev": true, + "license": "MIT" }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" }, "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", - "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", - "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.2.tgz", + "integrity": "sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -23165,12 +22155,14 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/to-buffer": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", @@ -23183,12 +22175,14 @@ "node_modules/to-buffer/node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" }, "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==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -23199,67 +22193,15 @@ "node_modules/toggle-selection": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" - }, - "node_modules/torrent-discovery": { - "version": "11.0.19", - "resolved": "https://registry.npmjs.org/torrent-discovery/-/torrent-discovery-11.0.19.tgz", - "integrity": "sha512-BLhdj7o0px+u72UuhJmq6CB0LBkZOa1nwgbd5ktyTELJlvcRL8EoxSSmSpzMOIScLGgslh1uLaAy/POhLpagtg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "bittorrent-dht": "^11.0.11", - "bittorrent-lsd": "^2.0.0", - "bittorrent-tracker": "^11.2.2", - "debug": "^4.4.3", - "run-parallel": "^1.2.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/torrent-piece": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/torrent-piece/-/torrent-piece-3.0.2.tgz", - "integrity": "sha512-K1A5tZ3BolFrUtnBpk9iDg8av1na0OgQ7E0IlA9tj0bcsPhLhzvln+oMtMmtkqAwmUsbNCilRm2ymUdZg0rVbQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "uint8-util": "^2.1.9" - }, - "engines": { - "node": ">=12.20.0" - } + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", + "license": "MIT" }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -23267,13 +22209,15 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, "node_modules/tree-sitter": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz", "integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==", "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "node-addon-api": "^8.0.0", @@ -23285,6 +22229,7 @@ "resolved": "https://registry.npmjs.org/tree-sitter-json/-/tree-sitter-json-0.24.8.tgz", "integrity": "sha512-Tc9ZZYwHyWZ3Tt1VEw7Pa2scu1YO7/d2BCBbKTx5hXwig3UfdQjsOPkPyLpDJOn/m1UBEWYAtSdGAwCSyagBqQ==", "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "node-addon-api": "^8.2.2", @@ -23303,6 +22248,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -23313,6 +22259,7 @@ "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz", "integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==", "dev": true, + "license": "MIT", "dependencies": { "bidi-js": "^1.0.2", "troika-three-utils": "^0.52.4", @@ -23328,6 +22275,7 @@ "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.4.tgz", "integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==", "dev": true, + "license": "MIT", "peerDependencies": { "three": ">=0.125.0" } @@ -23336,12 +22284,14 @@ "version": "0.52.0", "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/trough": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -23352,6 +22302,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.12" }, @@ -23363,6 +22314,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.3.1.tgz", "integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==", + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -23370,26 +22322,29 @@ "node_modules/ts-error": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/ts-error/-/ts-error-1.0.6.tgz", - "integrity": "sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==" + "integrity": "sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==", + "license": "MIT" }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" }, "node_modules/ts-jest": { - "version": "29.4.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", - "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "version": "29.4.11", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz", + "integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==", "dev": true, + "license": "MIT", "dependencies": { "bs-logger": "^0.2.6", "fast-json-stable-stringify": "^2.1.0", - "handlebars": "^4.7.8", + "handlebars": "^4.7.9", "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.7.3", + "semver": "^7.8.0", "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, @@ -23406,7 +22361,7 @@ "babel-jest": "^29.0.0 || ^30.0.0", "jest": "^29.0.0 || ^30.0.0", "jest-util": "^29.0.0 || ^30.0.0", - "typescript": ">=4.3 <6" + "typescript": ">=4.3 <7" }, "peerDependenciesMeta": { "@babel/core": { @@ -23429,23 +22384,12 @@ } } }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ts-jest/node_modules/type-fest": { "version": "4.41.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" }, @@ -23456,25 +22400,29 @@ "node_modules/ts-log": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.7.tgz", - "integrity": "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==" + "integrity": "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==", + "license": "MIT" }, "node_modules/ts-mixer": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", - "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==", + "license": "MIT" }, "node_modules/ts-poet": { "version": "6.12.0", "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz", "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==", + "license": "Apache-2.0", "dependencies": { "dprint-node": "^1.0.8" } }, "node_modules/ts-proto": { - "version": "2.11.6", - "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.11.6.tgz", - "integrity": "sha512-2rPkH5W/KeXOyVUC6o06RdRabVK8zSDmQpnRz4XbRiYMHRdI12KqDjAdGW7ebxzzMNE5cw/j+ptA0WMVqZILrQ==", + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.11.8.tgz", + "integrity": "sha512-+5hzECnyVB33jxjG1BIdzAHcRBm7hjnm8womdJVp2A7xJWihP0drHHVsXYTr9i/LpWNGfh80I+AVVNzFM5AwJw==", + "license": "ISC", "dependencies": { "@bufbuild/protobuf": "^2.10.2", "case-anything": "^2.1.13", @@ -23489,30 +22437,35 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.1.0.tgz", "integrity": "sha512-S5EZYEQ6L9KLFfjSRpZWDIXDV/W7tAj8uW7pLsihIxyr62EAVSiKuVPwE8iWnr849Bqa53enex1jhDUcpgquzA==", + "license": "ISC", "dependencies": { "@bufbuild/protobuf": "^2.0.0" } }, "node_modules/ts-proto-descriptors/node_modules/@bufbuild/protobuf": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", - "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==" + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.0.tgz", + "integrity": "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==", + "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/ts-proto/node_modules/@bufbuild/protobuf": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", - "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==" + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.0.tgz", + "integrity": "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==", + "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/ts-toolbelt": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", - "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==" + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "license": "Apache-2.0" }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -23525,6 +22478,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -23537,6 +22491,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -23544,38 +22499,25 @@ "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/tunnel-rat": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", "dev": true, + "license": "MIT", "dependencies": { "zustand": "^4.3.2" } }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -23588,17 +22530,18 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -23608,6 +22551,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -23622,6 +22566,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", @@ -23641,6 +22586,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", @@ -23662,6 +22608,7 @@ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -23680,12 +22627,14 @@ "node_modules/typeforce": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", - "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==", + "license": "MIT" }, "node_modules/types-ramda": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/types-ramda/-/types-ramda-0.30.1.tgz", "integrity": "sha512-1HTsf5/QVRmLzcGfldPFvkVsAdi1db1BBKzi7iW3KBUlOICg/nKnFS+jGqDJS3YD8VsWbAh7JiHeBvbsw8RPxA==", + "license": "MIT", "dependencies": { "ts-toolbelt": "^9.6.0" } @@ -23694,6 +22643,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -23703,15 +22653,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.2.tgz", - "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.4.tgz", + "integrity": "sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2" + "@typescript-eslint/eslint-plugin": "8.59.4", + "@typescript-eslint/parser": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4", + "@typescript-eslint/utils": "8.59.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -23722,7 +22673,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/ua-is-frozen": { @@ -23742,12 +22693,13 @@ "type": "paypal", "url": "https://paypal.me/faisalman" } - ] + ], + "license": "MIT" }, "node_modules/ua-parser-js": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-2.0.9.tgz", - "integrity": "sha512-OsqGhxyo/wGdLSXMSJxuMGN6H4gDnKz6Fb3IBm4bxZFMnyy0sdf6MN96Ie8tC6z/btdO+Bsy8guxlvLdwT076w==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-2.0.10.tgz", + "integrity": "sha512-t+3Ktbq0Ies2vaSezfOaWiolH4OigQIO1dk+1xDpOydB1COVPocVYOrEV5rqZ0kFY9XYG1v9LutCyMgYBpABcw==", "funding": [ { "type": "opencollective", @@ -23762,6 +22714,7 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "AGPL-3.0-or-later", "dependencies": { "detect-europe-js": "^0.1.2", "is-standalone-pwa": "^0.1.1", @@ -23779,6 +22732,7 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -23787,18 +22741,11 @@ "node": ">=0.8.0" } }, - "node_modules/uint8-util": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/uint8-util/-/uint8-util-2.2.6.tgz", - "integrity": "sha512-r+ZjS8CzPhtPF771ROOadUoqC40OVdiMKBI8lTfJQWb4W7+73sMBwMYmai/uvNcmZ7tBJJyZSad03yMWIt3RQg==", - "dependencies": { - "base64-arraybuffer": "^1.0.2" - } - }, "node_modules/uint8-varint": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.4.tgz", - "integrity": "sha512-FwpTa7ZGA/f/EssWAb5/YV6pHgVF1fViKdW8cWaEarjB8t7NyofSWBdOTyFPaGuUG4gx3v1O3PQ8etsiOs3lcw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.5.tgz", + "integrity": "sha512-jeFLbL/x30wBRnWjKE1qVBXeumG46r7XmYkpis955lTQ+blccGKFrOsSMHlxePwYB1pI7L8YPHz1t4jLxEs3nA==", + "license": "Apache-2.0 OR MIT", "dependencies": { "uint8arraylist": "^2.0.0", "uint8arrays": "^5.0.0" @@ -23808,22 +22755,25 @@ "version": "0.0.7", "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==", + "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/uint8arraylist": { - "version": "2.4.8", - "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.4.8.tgz", - "integrity": "sha512-vc1PlGOzglLF0eae1M8mLRTBivsvrGsdmJ5RbK3e+QRvRLOZfZhQROTwH/OfyF3+ZVUg9/8hE8bmKP2CvP9quQ==", + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.4.9.tgz", + "integrity": "sha512-KxWjyEFzchzik3aoQlK66oaoxIReoMo5bQRm1fcjBUZvE8xv/tyR3CTKhjh6K/faV8VaF6hd5pjr45CzbwuwkA==", + "license": "Apache-2.0 OR MIT", "dependencies": { "uint8arrays": "^5.0.1" } }, "node_modules/uint8arrays": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", - "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.1.tgz", + "integrity": "sha512-9muQwa4wZG4dKi9gMAIBtnk2Pw87SRpvWTH6lOGm19V2Uqxr4uomUf2PGqPnWc+qs06sN8owUU4jfcoWOcfwVQ==", + "license": "Apache-2.0 OR MIT", "dependencies": { "multiformats": "^13.0.0" } @@ -23833,6 +22783,7 @@ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", @@ -23847,9 +22798,10 @@ } }, "node_modules/undici": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", - "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz", + "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", + "license": "MIT", "engines": { "node": ">=18.17" } @@ -23857,12 +22809,14 @@ "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -23881,6 +22835,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -23893,6 +22848,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -23905,6 +22861,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -23917,6 +22874,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", @@ -23931,6 +22889,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -23943,62 +22902,58 @@ "node_modules/universal-user-agent": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", - "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==" - }, - "node_modules/unordered-array-remove": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", - "integrity": "sha512-45YsfD6svkgaCBNyvD+dFHm4qFX9g3wRSIVgWVPtm2OCnphvPxzJoe20ATsiNpNJrmzHifnxm+BN5F7gFT/4gw==" - }, - "node_modules/unordered-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", - "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==", - "optional": true + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" }, "node_modules/unraw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unraw/-/unraw-3.0.0.tgz", - "integrity": "sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==" + "integrity": "sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==", + "license": "MIT" }, "node_modules/unrs-resolver": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", - "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { - "napi-postinstall": "^0.3.0" + "napi-postinstall": "^0.3.4" }, "funding": { "url": "https://opencollective.com/unrs-resolver" }, "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.11.1", - "@unrs/resolver-binding-android-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-x64": "1.11.1", - "@unrs/resolver-binding-freebsd-x64": "1.11.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-musl": "1.11.1", - "@unrs/resolver-binding-wasm32-wasi": "1.11.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" } }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, "funding": [ { "type": "opencollective", @@ -24013,6 +22968,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -24029,6 +22985,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -24037,6 +22994,7 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -24046,6 +23004,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -24066,6 +23025,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" @@ -24087,147 +23047,55 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/ut_metadata": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/ut_metadata/-/ut_metadata-4.0.3.tgz", - "integrity": "sha512-2tovup0VDYpT8t8+EhhhKBmbgIyiYyJQZ+Hf+/61+SvjuRS2MEeA5CiSARP4q+9/83Wu09OsGrUre/Zv6OI5NA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "bencode": "^4.0.0", - "bitfield": "^4.0.0", - "debug": "^4.2.0", - "uint8-util": "^2.1.3" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/ut_pex": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/ut_pex/-/ut_pex-4.0.4.tgz", - "integrity": "sha512-isVTbp2TKGoMOu+4Zh/i6ijpYr0VG83xjRPgCXaUjKzgXXndjCMWg32/9kZjubD+kxEXcmXMkoS8IttS9FZE8g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "bencode": "^4.0.0", - "compact2string": "^1.4.1", - "string2compact": "^2.0.1" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/utf8-codec": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/utf8-codec/-/utf8-codec-1.0.0.tgz", - "integrity": "sha512-S/QSLezp3qvG4ld5PUfXiH7mCFxLKjSVZRFkB3DOjgwHuJPFDkInAXc/anf7BAbHt/D38ozDzL+QMZ6/7gsI6w==" + "integrity": "sha512-S/QSLezp3qvG4ld5PUfXiH7mCFxLKjSVZRFkB3DOjgwHuJPFDkInAXc/anf7BAbHt/D38ozDzL+QMZ6/7gsI6w==", + "license": "MIT" }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/utility-types": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", - "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/utp-native": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/utp-native/-/utp-native-2.5.3.tgz", - "integrity": "sha512-sWTrWYXPhhWJh+cS2baPzhaZc89zwlWCfwSthUjGhLkZztyPhcQllo+XVVCbNGi7dhyRlxkWxN4NKU6FbA9Y8w==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "napi-macros": "^2.0.0", - "node-gyp-build": "^4.2.0", - "readable-stream": "^3.0.2", - "timeout-refresh": "^1.0.0", - "unordered-set": "^2.0.1" - }, - "bin": { - "ucat": "ucat.js" - }, - "engines": { - "node": ">=8.12" - } - }, - "node_modules/utp-native/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" } }, - "node_modules/utp-native/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "optional": true, - "dependencies": { - "safe-buffer": "~5.2.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/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" } }, "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/esm/bin/uuid" } @@ -24236,6 +23104,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/uuidv7/-/uuidv7-1.2.1.tgz", "integrity": "sha512-4kPkK3/XTQW9Hbm4CaqfICn+kY9LJtDVEOfgsRRra/+n2Ofg4NqzRFceAkxvQ/Ud/6BpHOPzj8cirqM7TzTN5Q==", + "license": "Apache-2.0", "bin": { "uuidv7": "cli.js" } @@ -24245,6 +23114,7 @@ "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -24254,18 +23124,11 @@ "node": ">=10.12.0" } }, - "node_modules/validator": { - "version": "13.15.26", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", - "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/varuint-bitcoin": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-2.0.0.tgz", "integrity": "sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==", + "license": "MIT", "dependencies": { "uint8array-tools": "^0.0.8" } @@ -24274,6 +23137,7 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz", "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==", + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -24282,6 +23146,7 @@ "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" } @@ -24290,6 +23155,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" @@ -24303,6 +23169,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" @@ -24316,6 +23183,7 @@ "version": "36.9.2", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", @@ -24333,16 +23201,12 @@ "d3-timer": "^3.0.1" } }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } @@ -24351,6 +23215,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "license": "MIT", "dependencies": { "util": "^0.12.3" }, @@ -24358,36 +23223,31 @@ "@zxing/text-encoding": "0.9.0" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, "node_modules/web-tree-sitter": { "version": "0.24.5", "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.24.5.tgz", "integrity": "sha512-+J/2VSHN8J47gQUAvF8KDadrfz6uFYVjxoxbKWDoXVsH2u7yLdarCnIURnrMA6uSRkgX3SdmqM5BOoQjPdSh5w==", + "license": "MIT", "optional": true }, "node_modules/webcrypto-core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz", - "integrity": "sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.9.2.tgz", + "integrity": "sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.13", + "@peculiar/asn1-schema": "^2.7.0", "@peculiar/json-schema": "^1.1.12", - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.5", - "tslib": "^2.7.0" + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" } }, "node_modules/webextension-polyfill": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.8.0.tgz", - "integrity": "sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ==" + "integrity": "sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ==", + "license": "MPL-2.0" }, "node_modules/webgl-constants": { "version": "1.1.1", @@ -24399,18 +23259,21 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" }, "node_modules/webpack-bundle-analyzer": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", "dev": true, + "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", @@ -24438,91 +23301,29 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, - "node_modules/webrtc-polyfill": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/webrtc-polyfill/-/webrtc-polyfill-1.2.0.tgz", - "integrity": "sha512-epaVJbKzWOY5Wf3k7DoZLNgHP/5IoALBvjvlZQgX+9vFnf9UfCHv+rc+r/vJ7jxQUwH3cIYx9blHfyWWxGbw1g==", - "dependencies": { - "node-datachannel": "^0.32.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/webtorrent": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/webtorrent/-/webtorrent-2.8.5.tgz", - "integrity": "sha512-oIjpuBrypApJ+RCZ8RRaHEncVSkt2cd25/I4Trb2sk9nlaEF92Dg1u8BCwqA4eJR7wIZQM95GyO7Wo4QTbrUUA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/webrtc-adapter": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-9.0.5.tgz", + "integrity": "sha512-U9vjByy/sK2OMXu5mmfuZFKTMIUQe34c0JXRO+oDrxJTsntdYT2iIFwYMOV7HhMTuktcZLGf2W1N/OcSf9ssWg==", + "license": "BSD-3-Clause", "dependencies": { - "@silentbot1/nat-api": "^0.4.9", - "@thaunknown/simple-peer": "^10.0.11", - "@webtorrent/http-node": "^1.3.0", - "addr-to-ip-port": "^2.0.0", - "bitfield": "^4.2.0", - "bittorrent-dht": "^11.0.10", - "bittorrent-protocol": "^4.1.20", - "cache-chunk-store": "^3.2.2", - "chunk-store-iterator": "^1.0.4", - "cpus": "^1.0.3", - "create-torrent": "^6.1.0", - "cross-fetch-ponyfill": "^1.0.3", - "debug": "^4.4.1", - "escape-html": "^1.0.3", - "fs-chunk-store": "^5.0.0", - "fsa-chunk-store": "^1.3.0", - "immediate-chunk-store": "^2.2.0", - "join-async-iterator": "^1.1.1", - "load-ip-set": "^3.0.1", - "lt_donthave": "^2.0.5", - "memory-chunk-store": "^1.3.5", - "mime": "^3.0.0", - "once": "^1.4.0", - "parse-torrent": "^11.0.18", - "pump": "^3.0.2", - "queue-microtask": "^1.2.3", - "random-iterate": "^1.0.1", - "range-parser": "^1.2.1", - "run-parallel": "^1.2.0", - "run-parallel-limit": "^1.1.0", - "speed-limiter": "^1.0.2", - "streamx": "2.22.1", - "throughput": "^1.0.2", - "torrent-discovery": "^11.0.17", - "torrent-piece": "^3.0.2", - "uint8-util": "^2.2.5", - "unordered-array-remove": "^1.0.2", - "ut_metadata": "^4.0.3", - "ut_pex": "^4.0.4" + "sdp": "^3.2.0" }, "engines": { - "node": ">=16" - }, - "optionalDependencies": { - "utp-native": "^2.5.3" + "node": ">=6.0.0", + "npm": ">=3.10.0" } }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -24532,6 +23333,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -24547,6 +23349,7 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, + "license": "MIT", "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", @@ -24566,6 +23369,7 @@ "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", @@ -24592,13 +23396,15 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -24612,16 +23418,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-runtime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/which-runtime/-/which-runtime-1.3.2.tgz", - "integrity": "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw==", - "optional": true - }, "node_modules/which-typed-array": { "version": "1.1.20", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", @@ -24642,6 +23443,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==", + "license": "MIT", "dependencies": { "bs58check": "<3.0.0" } @@ -24650,6 +23452,7 @@ "version": "3.0.11", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", "dependencies": { "safe-buffer": "^5.0.1" } @@ -24658,6 +23461,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", "dependencies": { "base-x": "^3.0.2" } @@ -24666,6 +23470,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "license": "MIT", "dependencies": { "bs58": "^4.0.0", "create-hash": "^1.1.0", @@ -24677,6 +23482,7 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -24685,12 +23491,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "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", @@ -24706,13 +23514,15 @@ "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==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" @@ -24722,9 +23532,10 @@ } }, "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", + "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -24744,40 +23555,23 @@ "node_modules/xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "license": "MIT" }, "node_modules/xml-but-prettier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml-but-prettier/-/xml-but-prettier-1.0.1.tgz", "integrity": "sha512-C2CJaadHrZTqESlH03WOyw0oZTtoy2uEg6dSDF6YRg+9GnYNub53RRemLpnvtbHDFelxMx4LajiFsYeR6XJHgQ==", + "license": "MIT", "dependencies": { "repeat-string": "^1.5.2" } }, - "node_modules/xml2js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, "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" } @@ -24785,12 +23579,15 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", "bin": { "yaml": "bin.mjs" }, @@ -24805,6 +23602,7 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -24822,6 +23620,7 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", "engines": { "node": ">=12" } @@ -24831,6 +23630,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -24838,43 +23638,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/z-schema": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", - "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", - "dependencies": { - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "validator": "^13.7.0" - }, - "bin": { - "z-schema": "bin/z-schema" - }, - "engines": { - "node": ">=8.0.0" - }, - "optionalDependencies": { - "commander": "^9.4.1" - } - }, - "node_modules/z-schema/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "optional": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/zen-observable": { "version": "0.8.15", "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", - "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==", + "license": "MIT" }, "node_modules/zen-observable-ts": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz", "integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==", + "license": "MIT", "dependencies": { "@types/zen-observable": "0.8.3", "zen-observable": "0.8.15" @@ -24883,12 +23657,14 @@ "node_modules/zenscroll": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/zenscroll/-/zenscroll-4.0.2.tgz", - "integrity": "sha512-jEA1znR7b4C/NnaycInCU6h/d15ZzCd1jmsruqOKnZP6WXQSMH3W2GL+OXbkruslU4h+Tzuos0HdswzRUk/Vgg==" + "integrity": "sha512-jEA1znR7b4C/NnaycInCU6h/d15ZzCd1jmsruqOKnZP6WXQSMH3W2GL+OXbkruslU4h+Tzuos0HdswzRUk/Vgg==", + "license": "Unlicense" }, "node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -24898,6 +23674,7 @@ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.0.0" }, @@ -24909,6 +23686,7 @@ "version": "4.5.7", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", "dependencies": { "use-sync-external-store": "^1.2.2" }, @@ -24936,10 +23714,116 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } diff --git a/package.json b/package.json index ef470275..6dfad937 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,9 @@ "prestart": "prisma migrate deploy", "start": "next start", "test": "jest", + "test:bot:unit": "jest src/__tests__/botAuth.test.ts src/__tests__/botMe.test.ts src/__tests__/createWallet.bot.test.ts src/__tests__/walletIds.bot.test.ts src/__tests__/pendingTransactions.bot.test.ts src/__tests__/freeUtxos.bot.test.ts src/__tests__/addTransaction.bot.test.ts src/__tests__/nativeScript.bot.test.ts src/__tests__/governanceActiveProposals.test.ts src/__tests__/botBallotsUpsert.test.ts src/__tests__/signTransaction.bot.test.ts src/__tests__/submitDatum.bot.test.ts src/__tests__/resolveUtxoRefsFromChain.test.ts src/__tests__/resolveDRepAnchorFromUrl.test.ts src/__tests__/normalizePoolId.test.ts src/__tests__/createPendingMultisigTransaction.test.ts src/__tests__/proxyUtxos.test.ts src/__tests__/proxyTxBuilders.test.ts src/__tests__/proxySetup.bot.test.ts src/__tests__/proxyCleanup.bot.test.ts src/__tests__/proxyAccess.test.ts src/__tests__/proxySetupFinalization.test.ts src/__tests__/proxyCleanupFinalization.test.ts src/__tests__/proxyCiPreflight.test.ts src/__tests__/proxyCiOrphanAdoption.test.ts src/__tests__/proxyCiChainRecovery.test.ts src/__tests__/proxyBotSelection.test.ts src/__tests__/proxyCleanupRuntime.test.ts src/__tests__/ciSigningSelection.test.ts src/__tests__/ciScenarioManifest.test.ts", + "test:bot:integration": "jest src/__tests__/botApi.integration.test.ts --runInBand", + "test:bot": "npm run test:bot:unit && npm run test:bot:integration", "test:watch": "jest --watch", "test:coverage": "jest --coverage", "test:ci": "jest --ci --coverage --watchAll=false", @@ -27,11 +30,11 @@ "@auth/prisma-adapter": "^2.11.1", "@hookform/resolvers": "^3.9.0", "@jinglescode/nostr-chat-plugin": "^0.0.11", - "@meshsdk/core": "^1.9.0-beta.87", - "@meshsdk/core-csl": "^1.9.0-beta.87", - "@meshsdk/core-cst": "^1.9.0-beta.87", - "@meshsdk/provider": "^1.9.0-beta.86", - "@meshsdk/react": "^1.9.0-beta.87", + "@meshsdk/core": "1.9.0-beta.102", + "@meshsdk/core-csl": "1.9.0-beta.102", + "@meshsdk/core-cst": "1.9.0-beta.102", + "@meshsdk/provider": "1.9.0-beta.100", + "@meshsdk/react": "1.9.0-beta-40", "@octokit/core": "^6.1.2", "@prisma/client": "^6.17.1", "@radix-ui/react-accordion": "^1.2.0", @@ -139,6 +142,7 @@ "lodash.get": "^4.4.2", "lodash.isequal": "^4.5.0", "undici": "^6.23.0", - "elliptic": "^6.5.7" + "elliptic": "^6.5.7", + "@peculiar/webcrypto": "1.5.0" } } diff --git a/prisma/migrations/20260510160404_audit_log_and_indexes/migration.sql b/prisma/migrations/20260510160404_audit_log_and_indexes/migration.sql new file mode 100644 index 00000000..058fae30 --- /dev/null +++ b/prisma/migrations/20260510160404_audit_log_and_indexes/migration.sql @@ -0,0 +1,88 @@ +-- AlterTable +ALTER TABLE "Ballot" ALTER COLUMN "anchorUrls" SET DEFAULT ARRAY[]::TEXT[], +ALTER COLUMN "anchorHashes" SET DEFAULT ARRAY[]::TEXT[]; + +-- CreateTable +CREATE TABLE "AuditLog" ( + "id" TEXT NOT NULL, + "actorAddress" TEXT, + "actorType" TEXT NOT NULL, + "action" TEXT NOT NULL, + "resourceType" TEXT, + "resourceId" TEXT, + "ip" TEXT, + "userAgent" TEXT, + "outcome" TEXT NOT NULL, + "reason" TEXT, + "metadata" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "AuditLog_actorAddress_idx" ON "AuditLog"("actorAddress"); + +-- CreateIndex +CREATE INDEX "AuditLog_action_idx" ON "AuditLog"("action"); + +-- CreateIndex +CREATE INDEX "AuditLog_resourceType_resourceId_idx" ON "AuditLog"("resourceType", "resourceId"); + +-- CreateIndex +CREATE INDEX "AuditLog_createdAt_idx" ON "AuditLog"("createdAt"); + +-- CreateIndex +CREATE INDEX "AuditLog_actorAddress_createdAt_idx" ON "AuditLog"("actorAddress", "createdAt"); + +-- CreateIndex +CREATE INDEX "BalanceSnapshot_walletId_idx" ON "BalanceSnapshot"("walletId"); + +-- CreateIndex +CREATE INDEX "BalanceSnapshot_walletId_snapshotDate_idx" ON "BalanceSnapshot"("walletId", "snapshotDate"); + +-- CreateIndex +CREATE INDEX "Ballot_walletId_idx" ON "Ballot"("walletId"); + +-- CreateIndex +CREATE INDEX "NewWallet_ownerAddress_idx" ON "NewWallet"("ownerAddress"); + +-- CreateIndex +CREATE INDEX "NewWallet_signersAddresses_idx" ON "NewWallet" USING GIN ("signersAddresses" array_ops); + +-- CreateIndex +CREATE INDEX "Proxy_walletId_idx" ON "Proxy"("walletId"); + +-- CreateIndex +CREATE INDEX "Proxy_userId_idx" ON "Proxy"("userId"); + +-- CreateIndex +CREATE INDEX "Proxy_walletId_isActive_idx" ON "Proxy"("walletId", "isActive"); + +-- CreateIndex +CREATE INDEX "Proxy_userId_isActive_idx" ON "Proxy"("userId", "isActive"); + +-- CreateIndex +CREATE INDEX "Signable_walletId_idx" ON "Signable"("walletId"); + +-- CreateIndex +CREATE INDEX "Signable_state_idx" ON "Signable"("state"); + +-- CreateIndex +CREATE INDEX "Signable_walletId_state_idx" ON "Signable"("walletId", "state"); + +-- CreateIndex +CREATE INDEX "Transaction_walletId_idx" ON "Transaction"("walletId"); + +-- CreateIndex +CREATE INDEX "Transaction_state_idx" ON "Transaction"("state"); + +-- CreateIndex +CREATE INDEX "Transaction_walletId_state_idx" ON "Transaction"("walletId", "state"); + +-- CreateIndex +CREATE INDEX "Wallet_ownerAddress_idx" ON "Wallet"("ownerAddress"); + +-- CreateIndex +CREATE INDEX "Wallet_signersAddresses_idx" ON "Wallet" USING GIN ("signersAddresses" array_ops); + diff --git a/prisma/migrations/20260510170000_make_user_nostrkey_optional/migration.sql b/prisma/migrations/20260510170000_make_user_nostrkey_optional/migration.sql new file mode 100644 index 00000000..7d33c422 --- /dev/null +++ b/prisma/migrations/20260510170000_make_user_nostrkey_optional/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ALTER COLUMN "nostrKey" DROP NOT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 23d45677..30902c9b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -16,12 +16,12 @@ datasource db { } model User { - id String @id @default(cuid()) - address String @unique - stakeAddress String @unique - drepKeyHash String @default("") - nostrKey String @unique - discordId String @default("") + id String @id @default(cuid()) + address String @unique + stakeAddress String @unique + drepKeyHash String @default("") + nostrKey String? @unique + discordId String @default("") } model Wallet { @@ -257,3 +257,24 @@ model BotClaimToken { @@index([tokenHash]) } + +model AuditLog { + id String @id @default(cuid()) + actorAddress String? // Wallet address that performed the action (null for system/anonymous) + actorType String // "user" | "bot" | "system" + action String // e.g. "wallet.create", "tx.sign", "bot.grant", "auth.login" + resourceType String? // "wallet" | "transaction" | "bot" | "ballot" | etc. + resourceId String? + ip String? + userAgent String? + outcome String // "success" | "denied" | "error" + reason String? // Short reason on denied/error + metadata Json? // Additional context (no secrets, redacted) + createdAt DateTime @default(now()) + + @@index([actorAddress]) + @@index([action]) + @@index([resourceType, resourceId]) + @@index([createdAt]) + @@index([actorAddress, createdAt]) +} diff --git a/railway.toml b/railway.toml new file mode 100644 index 00000000..77cda9e6 --- /dev/null +++ b/railway.toml @@ -0,0 +1,5 @@ +[build] +buildCommand = "npm install && npm run build" + +[deploy] +startCommand = "npm run start" diff --git a/scripts/bot-ref/README.md b/scripts/bot-ref/README.md index 10225ab2..71c3f111 100644 --- a/scripts/bot-ref/README.md +++ b/scripts/bot-ref/README.md @@ -54,7 +54,7 @@ npm install ```bash curl -sS -X POST http://localhost:3000/api/v1/botRegister \ -H "Content-Type: application/json" \ - -d '{"name":"Reference Bot","paymentAddress":"addr1_xxx","scopes":["multisig:read"]}' + -d '{"name":"Reference Bot","paymentAddress":"addr1_xxx","requestedScopes":["multisig:read","multisig:sign"]}' ``` Response includes `pendingBotId` and `claimCode`. @@ -134,11 +134,43 @@ echo '{"name":"Me and Bot","signersAddresses":["addr1_your...","addr1_bot..."]," Optional fields: `description`, `signersDescriptions`, `signersStakeKeys`, `signersDRepKeys`, `numRequiredSigners`, `scriptType` (`atLeast`|`all`|`any`), `stakeCredentialHash`, `network` (0=testnet, 1=mainnet). -### 8. Generate a bot wallet (testing) +### 8. Stake certificate (SDK multisig) + +The bot must have **multisig:sign** and be a **cosigner** on the wallet. The server builds the same Mesh stake certificates as the UI (`register`, `deregister`, `delegate`, `register_and_delegate`). **Legacy and Summon wallets are rejected.** + +1. List free UTxOs and pick inputs; each body field is `txHash` + `outputIndex` as returned by the API. +2. POST `walletId`, `address` (must match JWT / bot payment address), `action`, optional `poolId` (required for `delegate` and `register_and_delegate`; bech32 `pool1...` or 56-char hex), and `utxoRefs`. + +```bash +# stake.json example: +# { +# "walletId": "", +# "address": "", +# "action": "delegate", +# "poolId": "pool1...", +# "utxoRefs": [{ "txHash": "...", "outputIndex": 0 }], +# "description": "Delegate via bot" +# } +export BOT_TOKEN='' +npx tsx bot-client.ts stakeCert stake.json +``` + +If `numRequiredSigners > 1`, the response is a pending `Transaction` row; co-sign with `POST /api/v1/signTransaction` as usual. + +### 9. DRep certificate (register / retire) + +Also requires **multisig:sign**. **Summon** wallets are rejected; **legacy** wallets use payment-script DRep derivation (same as the app). For `register`, send both `anchorUrl` and `anchorJson`; the server does not fetch the URL and computes `hashDrepAnchor(anchorJson)` from the object you provide. + +```bash +# drep-register.json — anchorUrl and anchorJson required for register +npx tsx bot-client.ts drepCert drep-register.json +``` + +### 10. Generate a bot wallet (testing) From **repo root**: `npx tsx scripts/bot-ref/generate-bot-wallet.ts` — creates gitignored `bot-wallet.json` (mnemonic + address) and updates `bot-config.json`. -### 9. Create “Me and Bot” 2-of-2 wallet +### 11. Create “Me and Bot” 2-of-2 wallet ```bash cd scripts/bot-ref && npx tsx create-wallet-us.ts @@ -162,6 +194,40 @@ BOT_TOKEN='...' BOT_CONFIG_PATH=bot-config.json npx tsx bot-client.ts walletIds The reference client only uses **bot-key auth** (POST /api/v1/botAuth). Wallet-based auth (getNonce + sign + authSigner) would require a real Cardano signer; implement that in your bot if needed. +## Proxy bot API + +Proxy routes use the normal pending multisig flow and require `multisig:sign` plus **cosigner** access for mutating calls. `GET /api/v1/proxies` and `GET /api/v1/proxyDRepInfo` allow bot observer access. The reference CLI does not wrap these routes yet; call them directly with `BOT_TOKEN`. + +All proxy transaction builders accept UTxO references, not raw UTxO JSON: + +```json +{ "txHash": "", "outputIndex": 0 } +``` + +Use `GET /api/v1/freeUtxos?walletId=...&address=...&fresh=true` to select wallet inputs. `collateralRef` must be an ADA-only UTxO with at least 5 ADA at the bot payment address. Proxy actions also require a wallet input containing the proxy auth token, returned from setup/finalization metadata as `authTokenId`. + +### Setup and finalize + +1. `POST /api/v1/proxySetup` with `walletId`, `address`, `utxoRefs`, `collateralRef`, optional `initialProxyLovelace`, and optional `description`. +2. Sign the returned pending transaction with the required wallet signers. Proxy transactions are persisted with no initial signed addresses, so the proposer still needs to sign through `signTransaction`. +3. After the setup transaction is confirmed, call `POST /api/v1/proxySetupFinalize` with `walletId`, `address`, `txHash`, `proxyAddress`, `authTokenId`, and `paramUtxo` from the setup response. The server validates the confirmed setup outputs and creates or reactivates the `Proxy` row. +4. `GET /api/v1/proxies?walletId=...&address=...` lists active confirmed proxies. + +### Spend, DRep, and vote + +- `POST /api/v1/proxySpend`: sends proxy-held assets to `outputs[]`. If `proxyUtxoRefs` is omitted, the server selects proxy-address UTxOs sufficient for the requested outputs plus fee buffer. +- `POST /api/v1/proxyDRepCertificate`: `action` is `register`, `update`, or `deregister`. `register` and `update` require both `anchorUrl` and `anchorJson`; the server computes the anchor hash from `anchorJson`. +- `GET /api/v1/proxyDRepInfo`: returns `{ active, dRepId }` for the proxy script DRep credential. +- `POST /api/v1/proxyVote`: votes as the proxy DRep. Each vote uses `proposalId` in `#` form and `voteKind` of `Yes`, `No`, or `Abstain`. + +### Cleanup + +`POST /api/v1/proxyCleanup` is safe to call repeatedly during lifecycle cleanup: + +1. If the proxy address still has UTxOs, it returns cleanup phase `sweep`; sign and submit that transaction, then wait until the proxy address is empty. When `proxyUtxoRefs` is provided, it must include every currently visible proxy UTxO. +2. Call `POST /api/v1/proxyCleanup` again. When cleanup phase is `burn`, sign and submit the burn transaction. +3. After burn confirmation, call `POST /api/v1/proxyCleanupFinalize` with the confirmed burn `txHash`. The server validates that the auth token was spent and not recreated, that the proxy address has no UTxOs, and deactivates the proxy row unless `deactivateProxy` is `false`. + ## Governance bot flow For governance automation, request and approve these bot scopes during register/claim: diff --git a/scripts/bot-ref/bot-client.ts b/scripts/bot-ref/bot-client.ts index 57d8e980..f4e8696d 100644 --- a/scripts/bot-ref/bot-client.ts +++ b/scripts/bot-ref/bot-client.ts @@ -238,11 +238,68 @@ export async function createWallet( return (await res.json()) as { walletId: string; address: string; name: string }; } +/** Build stake certificate tx (SDK wallets; bot needs multisig:sign). */ +export async function botStakeCertificate( + baseUrl: string, + token: string, + body: { + walletId: string; + address: string; + action: "register" | "deregister" | "delegate" | "register_and_delegate"; + poolId?: string; + utxoRefs: { txHash: string; outputIndex: number }[]; + description?: string; + }, +): Promise { + const base = ensureSlash(baseUrl); + const res = await fetch(`${base}/api/v1/botStakeCertificate`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify(body), + }); + if (!res.ok) { + throw new Error(`botStakeCertificate failed ${res.status}: ${await res.text()}`); + } + return res.json(); +} + +/** Build DRep register/retire tx (bot needs multisig:sign). */ +export async function botDRepCertificate( + baseUrl: string, + token: string, + body: { + walletId: string; + address: string; + action: "register" | "retire"; + utxoRefs: { txHash: string; outputIndex: number }[]; + description?: string; + anchorUrl?: string; + anchorDataHash?: string; + }, +): Promise { + const base = ensureSlash(baseUrl); + const res = await fetch(`${base}/api/v1/botDRepCertificate`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify(body), + }); + if (!res.ok) { + throw new Error(`botDRepCertificate failed ${res.status}: ${await res.text()}`); + } + return res.json(); +} + async function main() { const config = await loadConfig(); const cmd = process.argv[2]; if (!cmd) { - console.error("Usage: bot-client.ts [args]"); + console.error("Usage: bot-client.ts [args]"); console.error(" register [scope1,scope2,...] [paymentAddress] - create pending bot + claim code"); console.error(" pickup - pickup botKeyId + secret after human claim"); console.error(" auth - authenticate and print token"); @@ -252,6 +309,8 @@ async function main() { console.error(" ownerInfo - get wallet owner info"); console.error(" botMe - get bot's own info (incl. owner address)"); console.error(" createWallet [file] - create wallet via API (body from file or stdin); bot needs multisig:create"); + console.error(" stakeCert [file] - POST /api/v1/botStakeCertificate (JSON body file or stdin); needs multisig:sign"); + console.error(" drepCert [file] - POST /api/v1/botDRepCertificate (JSON body file or stdin); needs multisig:sign"); console.error("Env: BOT_CONFIG (JSON), BOT_CONFIG_PATH, BOT_TOKEN (after auth)."); process.exit(1); } @@ -402,6 +461,44 @@ async function main() { console.log(JSON.stringify(result, null, 2)); break; } + case "stakeCert": { + const fileArg = process.argv[3]; + let raw: string; + if (fileArg) { + const { readFileSync } = await import("fs"); + const { join } = await import("path"); + raw = readFileSync(fileArg.startsWith("/") ? fileArg : join(process.cwd(), fileArg), "utf8"); + } else { + const { createInterface } = await import("readline"); + const rl = createInterface({ input: process.stdin, terminal: false }); + const lines: string[] = []; + for await (const line of rl) lines.push(line); + raw = lines.join("\n"); + } + const body = JSON.parse(raw) as Parameters[2]; + const result = await botStakeCertificate(config.baseUrl, token, body); + console.log(JSON.stringify(result, null, 2)); + break; + } + case "drepCert": { + const fileArg = process.argv[3]; + let raw: string; + if (fileArg) { + const { readFileSync } = await import("fs"); + const { join } = await import("path"); + raw = readFileSync(fileArg.startsWith("/") ? fileArg : join(process.cwd(), fileArg), "utf8"); + } else { + const { createInterface } = await import("readline"); + const rl = createInterface({ input: process.stdin, terminal: false }); + const lines: string[] = []; + for await (const line of rl) lines.push(line); + raw = lines.join("\n"); + } + const body = JSON.parse(raw) as Parameters[2]; + const result = await botDRepCertificate(config.baseUrl, token, body); + console.log(JSON.stringify(result, null, 2)); + break; + } default: console.error("Unknown command:", cmd); process.exit(1); diff --git a/scripts/ci/README.md b/scripts/ci/README.md new file mode 100644 index 00000000..f760bec5 --- /dev/null +++ b/scripts/ci/README.md @@ -0,0 +1,533 @@ +# CI Route-Chain Test Suite + +This folder contains the real-chain CI smoke system used by `.github/workflows/pr-multisig-v1-smoke.yml`. + +## Why this exists + +- Protects v1 API routes from regressions on pull requests. +- Verifies behavior against real blockchain conditions (preprod), not only mocked/unit paths. +- Keeps wallet bootstrap stable while allowing route tests to grow incrementally. +- Makes it easy to add new API route checks as composable scenario steps. + +## High-level flow + +CI runs these stages in order: + +1. **Bootstrap** (`cli/bootstrap.ts`) + - Derives signer payment addresses from mnemonic secrets and matching stake (reward) addresses from those base addresses. + - Provisions one bot key per signer address. + - Creates test wallets (`legacy`, `hierarchical`, `sdk`). + - For **SDK** wallets, always attaches `signersStakeKeys` so the wallet matches production “SDK multisig” staking (native script role `2` alongside payment `0` and DRep `3`). + - Grants all signer bots cosigner access to created wallets. + - Writes a versioned context JSON consumed by all later steps. + +2. **Route chain** (`cli/route-chain.ts`) + - Loads and validates bootstrap context. + - Loads enabled scenarios from `scenarios/manifest.ts`. + - Executes steps in deterministic order with critical/non-critical failure semantics. + - Emits console summary and machine-readable JSON report. + +3. **Artifacts** + - Route-chain Markdown report is written to `ci-artifacts/ci-route-chain-report.md`. + - Workflow uploads it as an artifact for triage. + - Report contains a run summary header, wallet balance table, scenario summary table, and per-scenario step tables. Failed steps include error/artifact code blocks. + +## Folder structure + +- `cli/` + - `bootstrap.ts`: stable setup stage, writes CI context. + - `wallet-status.ts`: print multisig wallet addresses and on-chain balances (after bootstrap, before route-chain). + - `route-chain.ts`: main orchestrator for scenario execution. + - `inspect-context.ts`: print bootstrap context summary (debug). +- `framework/` + - `types.ts`: shared types for context/scenarios/reports. + - `context.ts`: context loading + validation. + - `env.ts`, `mnemonic.ts`, `walletType.ts`, `preprod.ts`: shared env and Cardano helpers. + - `botProvision.ts`: bot key hashing for bootstrap. + - `botAuth.ts`: bot JWT authentication with in-process token caching (10 s expiry margin) and 429-rate-limit retry. + - `botContext.ts`: bot selection helpers (`getDefaultBot`, `getBotForAddress`, `getBotForSignerIndex`). + - `http.ts`: API caller helper with timeout/retry support. + - `walletAuth.ts`: nonce + signer auth helper (`getNonce`/`authSigner`) and signer data signing. + - `datumSign.ts`: reusable datum signing helper. + - `governance.ts`: deterministic governance proposal selection and ballot payload builder. + - `runner.ts`: scenario/step execution + report writing. + - `walletBalances.ts`: on-chain UTxO balance collection via Blockfrost (used by `walletBalanceSummary` in report). + - `redact.ts`: recursive sensitive-value redaction for log-safe JSON serialisation. +- `scenarios/` + - `manifest.ts`: scenario registry and ordering only. + - `proxyLifecyclePreflight.ts`: proxy lifecycle ADA/UTxO budget constants and shape analysis. + - `flows/`: `signingFlow.ts`, `transferFlow.ts`, `certificateSigningFlow.ts`, `utxoShapeFlow.ts` (reusable multisig sign, real transfer builders, stake-cert signing with dual payment+stake witnesses, and proxy lifecycle self-split shaping). + - `steps/`: route step factories grouped by area (`discovery.ts`, `botIdentity.ts`, `authPlane.ts`, `datum.ts`, `governance.ts`, `transferRing.ts`, `certificates.ts`, `walletLifecycle.ts`, `proxyBot.ts`, …) plus `helpers.ts` (ring wallet-type utilities) and `template-route-step.ts` for new steps. + +### Full scenario execution order + +The manifest runs scenarios in this fixed sequence: + +| # | Scenario ID | Conditional | +|---|-------------|-------------| +| 1 | `scenario.wallet-discovery` | always | +| 2 | `scenario.ada-route-health` | always | +| 3 | `scenario.create-wallet` | always | +| 4 | `scenario.bot-identity` | always | +| 5 | `scenario.auth-plane` | always | +| 6 | `scenario.proxy-smoke` | always | +| 7 | `scenario.submit-datum` | always | +| 8 | `scenario.governance-routes` | always | +| 9 | `scenario.drep-certificates` | legacy + sdk wallets present | +| 10 | `scenario.stake-certificates` | sdk wallet present | +| 11 | `scenario.proxy-full-lifecycle` | legacy, hierarchical, and/or sdk wallets present | +| 12 | `scenario.real-transfer-and-sign` | always (all 3 wallet types required) | +| 13 | `scenario.final-assertions` | always | + +Certificate scenarios (9–10) run before the ring transfer so they spend confirmed UTxOs; the ring transfer would put those UTxOs in the mempool and create a race. + +### Subset runs + +Use a comma-separated `CI_ROUTE_SCENARIOS` filter (same mechanism as the workflow dispatch input). + +Quick auth + discovery smoke (no on-chain transfers, finishes in seconds): + +```bash +CI_ROUTE_SCENARIOS=scenario.wallet-discovery,scenario.ada-route-health,scenario.bot-identity,scenario.auth-plane,scenario.proxy-smoke +``` + +Wallet creation API only: + +```bash +CI_ROUTE_SCENARIOS=scenario.create-wallet +``` + +Ring transfer + final checks only: + +```bash +CI_ROUTE_SCENARIOS=scenario.real-transfer-and-sign,scenario.final-assertions +``` + +Set `CI_ROUTE_CHAIN_REPORT_PATH` if you want a separate report file for that run. + +## Current scenario intent + +The manifest currently covers: + +- route discovery (`walletIds`, `proxies`) +- **pending-transactions zero-check** at bootstrap for each wallet type — catches stale state from a previous incomplete run before the ring transfer begins +- **public wallet lookup** (`lookupMultisigWallet`) — smoke-tests the unauthenticated on-chain metadata lookup endpoint +- route health checks (`freeUtxos`, `nativeScript`) — `nativeScript` now asserts a `payment` script entry is present and, when the root type is `atLeast`, that `required` matches `CI_NUM_REQUIRED_SIGNERS` +- **wallet creation via API** (`createWallet`) — creates a wallet through the bot-authenticated API path and confirms it appears in `walletIds`; runs early to avoid prior default-bot smoke checks consuming the shared bot rate-limit budget +- bot identity (`botAuth` explicit response shape, `botMe`) +- auth-plane checks (`getNonce`, `authSigner`) +- explicit auth negative checks (`walletIds`, `addTransaction`, `pendingTransactions`, `drepInfo`, `stakeAccountInfo`, `createWallet`) — `drepInfo`/`stakeAccountInfo`/`createWallet` check for missing token (401); `walletIds`/`addTransaction` check for address mismatch (403); `pendingTransactions` checks for missing token (401) +- proxy smoke checks (`proxies`, malformed proxy mutating routes) plus full proxy lifecycle coverage (`proxySetup`, `proxySpend`, proxy DRep register/deregister, optional proxy vote, cleanup, finalization) +- **`signTransaction` input validation** — asserts a non-existent `transactionId` returns 404, not 500 (requires `CI_MNEMONIC_2`; step is non-critical and skips gracefully if the env var is absent) +- datum route coverage (`submitDatum`) +- governance routes (`governanceActiveProposals`, `botBallotsUpsert`) +- **DRep certificate registration and retirement** (`botDRepCertificate`) — legacy and SDK wallets +- **stake certificate registration and deregistration** (`botStakeCertificate`) — SDK wallet only +- real multisig-wallet ring transfer + sign path +- pending lifecycle assertions for ring transfer txs only +- final state assertions after transfer/sign progression + +### Proxy bot scenarios + +`scenario.proxy-smoke` runs by default and performs authenticated `proxies` read checks plus negative validation checks that should fail before chain mutation. + +`scenario.proxy-full-lifecycle` runs by default in PR smoke for `legacy`, `hierarchical`, and `sdk` wallets when present. The hierarchical coverage reuses the wallet already created for route-chain context and the ring transfer; it does not add a new bootstrap wallet path. It starts each eligible wallet type with three pre-hygiene steps before normal setup: chain recovery reconstructs missing `Proxy` rows from proxy auth tokens still visible at the current CI wallet address, row adoption reattaches valid rows from historical deterministic CI wallets, and hygiene cleans any active rows before the new lifecycle begins. It then runs UTxO shaping and a funding preflight that fetches fresh `freeUtxos`. The hardcoded lifecycle budget is 536 ADA per eligible wallet: 505 ADA DRep registration, 10 ADA initial proxy funding, 1 ADA planned proxy spend, and a 20 ADA fee buffer. Because collateral is reserved outside selected spend inputs, the practical minimum post-shape layout is at least 536 ADA selectable at the multisig wallet address plus a separate ADA-only bot payment-address collateral UTxO. The self-split path needs enough total ADA to leave that 536 ADA selectable budget, create a 6 ADA collateral output, and cover a 2 ADA self-split fee buffer. Adding hierarchical means default PR smoke needs that budget available for one more wallet. Proxy DRep registration uses `CI_DREP_ANCHOR_URL` as the on-chain anchor URL and sends an inline route-chain `anchorJson`; it does not use `CI_DREP_ANCHOR_JSON`. + +The first full-lifecycle steps for each eligible wallet type are ordered as: + +1. `v1.proxy.full.recoverFromChain.` +2. `v1.proxy.full.adoptOrphans.` +3. `v1.proxy.full.hygiene.` +4. `v1.proxy.full.utxoShape.` +5. `v1.proxy.full.preflight.` + +Chain recovery is CI-only and evidence-based. It scans non-lovelace assets at the current bootstrap `walletAddress`, asks Blockfrost for each asset's mint transaction, tests the mint transaction inputs as candidate `paramUtxo` values with `deriveProxyScripts`, and only creates or reactivates a `Proxy` row when the derived `authTokenId` exactly matches the observed asset unit. This handles clean-database rebuilds where old proxy auth tokens and proxy DReps remain on-chain but the app has no `Proxy` rows. It cannot recover a proxy if the auth token is no longer discoverable at the current CI wallet address. + +When preflight passes, each eligible wallet lifecycle creates its own proxy, finalizes the confirmed setup, exercises proxy spend, proxy DRep register/deregister, optional proxy voting when active governance proposals exist, then runs safe cleanup and asserts the proxy no longer appears in `GET /api/v1/proxies`. Proxy actions always use bot payment-address collateral that is distinct from selected wallet spend inputs; DRep registration selects an auth-token input plus additional wallet inputs when needed to meet the registration budget. The proposer/collateral owner is signer index 0 (`CI_MNEMONIC_1`), and signer index 1 (`CI_MNEMONIC_2`) broadcasts for the default threshold-2 proxy actions. After each broadcasted proxy action, the route-chain waits for the selected wallet inputs to disappear from fresh `freeUtxos` before proposing the next action. Cleanup may require two submitted transactions: a sweep transaction that empties the proxy address while preserving an auth token, followed by a burn transaction and cleanup finalization. If the initial cleanup call already returns a burn transaction, the optional burn proposal is skipped after that transaction is signed. Because this scenario runs on every PR, the default CI legacy, hierarchical, and SDK wallets must stay funded; one-UTxO shape problems are repaired by the self-split step, while true budget failures still fail the route-chain rather than skipping proxy lifecycle coverage. + +Runtime expectation: `scenario.proxy-smoke` is the quick, non-mutating proxy subset. `scenario.proxy-full-lifecycle` is a real-chain scenario with multiple broadcasts per eligible wallet and can dominate default PR smoke duration during slow preprod/Blockfrost periods. The GitHub Actions job timeout is intentionally higher than the nominal happy path to leave room for confirmation polling. + +For each tested wallet type, the `nativeScript` step stores decoded script payloads in step artifacts (`artifacts.nativeScripts`) and the list of script entry types (`artifacts.scriptTypes`) inside `ci-route-chain-report.md`, so script structure is visible during CI triage. + +Signing is expected to be on, and broadcast is expected to be on, for normal CI route-chain runs. + +### Ring transfer + +Current transfer/sign chain in the route manifest runs a deterministic ring across multisig wallet addresses: + +- `legacy.walletAddress -> hierarchical.walletAddress` +- `hierarchical.walletAddress -> sdk.walletAddress` +- `sdk.walletAddress -> legacy.walletAddress` + +Each ring leg uses the same `CI_TRANSFER_LOVELACE` amount, so balances remain close after one cycle (differences are fee-driven). + +Real transfer construction is script-native: + +- route-chain spends UTxOs from the source multisig wallet script address +- destination is the next multisig wallet script address in the ring +- change returns to the source multisig wallet script address +- signer mnemonics are used for witness collection/signing, not as transfer funding inputs + +For each ring leg, signing runs two signer rounds: + +- signer index 1 (`CI_MNEMONIC_2`) signs with broadcast disabled +- signer index 2 (`CI_MNEMONIC_3`) signs with broadcast enabled + +Each leg is asserted as pending immediately after `addTransaction`, then asserted removed after signer 2 broadcast. + +### Create-wallet scenario (`scenario.create-wallet`) + +Runs after the early discovery and ADA route-health checks, before request-heavy default-bot scenarios. This keeps the app's rate-limit behavior intact while avoiding earlier smoke checks consuming the shared bot rate-limit budget before the positive wallet creation assertion. Requires `multisig:create` scope on the CI bot (provisioned by default). + +**Step 1** — calls `POST /api/v1/createWallet` with the CI signer addresses and the `CI_NUM_REQUIRED_SIGNERS` threshold. Asserts the response is 201 with a `walletId` and `address`. + +**Step 2** — calls `GET /api/v1/walletIds` for the bot and asserts the new `walletId` is present. This confirms the bot's cosigner access was set correctly during wallet creation. + +**Step 3 (cleanup, non-critical)** — deletes the test wallet directly via Prisma (`WalletBotAccess` rows first, then the `Wallet` row). Marked non-critical so a cleanup failure does not fail the scenario. If cleanup is skipped (e.g. step 1 failed), no orphan wallet is left behind. + +### DRep certificate scenarios (`scenario.drep-certificates`) + +Runs when both `legacy` and `sdk` wallets are in context. Requires `CI_DREP_ANCHOR_URL`. + +For each wallet type the scenario runs a pre-hygiene step followed by two sequential phases — register then retire — leaving the wallet in its pre-test DRep state: + +**Pre-hygiene step** — checks on-chain DRep state via `GET /api/v1/drepInfo`. If the DRep is already registered (e.g. from a previous incomplete run), it proposes a `retire` tx, signs with both signers, and waits for on-chain confirmation. If the broadcast is rejected with `DRepNotRegistered` or similar errors, the credential is treated as already clean (stale Blockfrost cache false-positive) and the step succeeds silently. + +**Main test phases:** + +1. Fetch free UTxOs from the wallet, call `POST /api/v1/botDRepCertificate` with `action: "register"`, `anchorUrl`, and `anchorJson` (the parsed JSON from `CI_DREP_ANCHOR_JSON`). The API computes the anchor data hash server-side from `anchorJson` — no outbound fetch anywhere. +2. Assert the transaction appears in pending. +3. Signer 1 (`CI_MNEMONIC_2`, index 1) adds a payment-key witness, no broadcast. +4. Signer 2 (`CI_MNEMONIC_3`, index 2) adds a payment-key witness and broadcasts. +5. Assert the transaction is cleared from pending. +6. Poll `freeUtxos?fresh=true` until the spent inputs are no longer unspent on-chain (confirms block inclusion before the next phase). Up to 30 retries × 8 s = 4 minutes. +7. Repeat steps 1–6 with `action: "retire"`. + +**Why payment-key witnesses are sufficient for DRep cert:** + +- **Legacy wallet:** the DRep credential script is the same as the payment script (no separate DRep keys), so the same payment vkeys satisfy both the spending inputs and the DRep certificate. +- **SDK wallet:** the CI bootstrap sets `signersDRepKeys = paymentKeyHashes`, so the DRep certificate script is also built from payment key hashes. Payment vkeys satisfy both scripts. + +### Stake certificate scenarios (`scenario.stake-certificates`) + +Runs when the `sdk` wallet is in context. Does not require `CI_DREP_ANCHOR_URL`. **`CI_STAKE_POOL_ID_HEX` is required** — it is passed as `poolId` in the `register_and_delegate` body. + +The scenario runs three phases: + +**Pre-hygiene step** — before the main test, checks on-chain state via `GET /api/v1/stakeAccountInfo`. If the stake credential is already registered (e.g. from a previous incomplete run), it proposes a `deregister` tx, signs with both signers, and waits for on-chain confirmation. If the broadcast is rejected with `StakeKeyNotRegisteredDELEG` or similar errors, the credential is treated as already clean (stale Blockfrost cache false-positive) and the step succeeds silently. + +**Main test: `register_and_delegate`** — uses `register_and_delegate` rather than bare `register` because production `stakingCertificates.ts` includes `.certificateScript()` on the register cert. In Conway era a bare register cert with a script witness causes `ExtraneousScriptWitnessesUTXOW`; `register_and_delegate` avoids this because the delegate cert legitimately requires the same staking script. Each phase follows 6 steps (propose → pending → sign1 → sign2+broadcast → cleared → on-chain confirmation poll). + +**Main test: `deregister`** — restores the wallet to its pre-test staking state. Same 6-step flow. + +Each signing step uses **`runStakeCertSigningFlow`** (`scenarios/flows/certificateSigningFlow.ts`) instead of the standard `runSigningFlow`, because the staking certificate script uses **stake key hashes** (role-2 keys) rather than payment key hashes: + +1. `MeshWallet.signTx(txCbor, true)` produces both a payment vkey witness and a stake vkey witness. +2. The flow extracts the payment vkey (matched by `resolvePaymentKeyHash(signerAddress)`) and the stake vkey (matched by `resolveStakeKeyHash(ctx.signerStakeAddresses[signerIndex])`). If the stake vkey cannot be found by key-hash search, the flow falls back to BIP32 derivation at path `m/1852'/1815'/0'/2/0` and signs the tx hash manually. +3. Both are submitted in a **single** `POST /api/v1/signTransaction` call via the optional `stakeKey` / `stakeSignature` body fields — this avoids hitting the "address already signed" guard that would block a second call from the same signer. + +`signTransaction` validates the stake witness by checking that its key hash is present in `wallet.signersStakeKeys` (resolved to key hashes). The stake witness is merged into the transaction CBOR alongside the payment witness before the broadcast threshold check runs. + +## Environment and secrets + +Primary variables (in workflow/compose): + +- `CI_JWT_SECRET` +- `CI_MNEMONIC_1`, `CI_MNEMONIC_2`, `CI_MNEMONIC_3` +- `CI_BLOCKFROST_PREPROD_API_KEY` +- `CI_NETWORK_ID` +- `CI_WALLET_TYPES` +- `CI_NUM_REQUIRED_SIGNERS` (default `2`): minimum signature threshold written into each created wallet's native script. Passed as `requiredSigners` during bootstrap. Also used by the `nativeScript` step to assert that the decoded `atLeast` script's `required` count matches, and by `scenario.create-wallet` as the `numRequiredSigners` parameter. +- `CI_SIGN_WALLET_TYPE` (default `legacy`): which wallet type is used when `runSigningFlow` resolves a wallet for signing in ring-transfer steps. Overridden per leg in transfer scenarios. +- `SIGN_BROADCAST` +- `CI_ROUTE_SCENARIOS` (optional scenario id filter) +- `CI_TRANSFER_LOVELACE` (optional transfer amount) +- `CI_DREP_ANCHOR_URL` (required by the default run for `scenario.drep-certificates` and `scenario.proxy-full-lifecycle`): the URL string stored in the on-chain anchor — passed as-is to the API, never fetched. +- `CI_DREP_ANCHOR_JSON` (required by the default run for `scenario.drep-certificates`): the raw JSON content of the CIP-119 DRep metadata document. Parsed and sent as `anchorJson`; the API computes the anchor data hash server-side — no outbound fetch anywhere. Both vars are forwarded into the `ci-runner` container via `docker-compose.ci.yml`. +- `CI_STAKE_POOL_ID_HEX` (**required** for `scenario.stake-certificates`): hex stake pool id stored in bootstrap context and used as `poolId` in the `register_and_delegate` certificate body. +- `CI_HTTP_RETRIES` (default `6`), `CI_HTTP_RETRY_DELAY_MS` (default `1000`), `CI_HTTP_MAX_RETRY_DELAY_MS` (default `30000`): route-chain API retry controls for transient responses (`429`, `418`, and selected `5xx`). Defaults are long enough to ride out the app's 60-second in-process rate-limit window without changing app behavior. + +Validation notes: + +- Route-chain transfer scenarios are preprod-only; `CI_NETWORK_ID` must be `0`. +- Signer/bot/wallet addresses used in context must all be testnet-form (`addr_test` / `stake_test`). +- `CI_WALLET_TYPES` must contain only `legacy`, `hierarchical`, `sdk`; invalid values fail fast. +- The default full route-chain (including ring transfer scenario) requires all three wallet types (`legacy`, `hierarchical`, `sdk`) to be present. +- `CI_ROUTE_SCENARIOS` values must exist in `scenarios/manifest.ts`; unknown ids fail fast. +- `CI_MNEMONIC_1`, `CI_MNEMONIC_2`, and `CI_MNEMONIC_3` must derive signer addresses from bootstrap context for multi-signer route-chain signing. Signer indexes are zero-based relative to `wallet.signerAddresses`. +- `CI_STAKE_POOL_ID_HEX` must be set when running `scenario.stake-certificates`; the scenario throws at proposal time if `ctx.stakePoolIdHex` is absent. +- Proxy full lifecycle runs by default for legacy, hierarchical, and SDK wallets when present. Before new proxy setup, route-chain first recovers any chain-discoverable proxy rows, adopts historical rows for the same deterministic wallet script, and runs hygiene so stale proxy DReps/auth tokens are cleaned centrally. Those CI wallets must each have enough selectable multisig-wallet ADA for initial proxy funding, the planned proxy spend, DRep registration, and fee headroom, plus an ADA-only collateral UTxO at `bot.paymentAddress`. If total ADA is sufficient but the UTxO shape is not, route-chain self-splits it before proxy preflight by creating a 6 ADA collateral output at `bot.paymentAddress`. The proxy collateral is selected from `bot.paymentAddress`, which is signer index 0 in the bootstrap wallet context. +- Source multisig wallet script addresses must be funded on preprod for each ring leg (`legacy -> hierarchical -> sdk -> legacy`). +- `CI_JWT_SECRET` must remain the same between bootstrap and route-chain, because bot auth secrets are deterministically derived from it. +- CI bot keys are provisioned with scopes: `multisig:create`, `multisig:read`, `multisig:sign`, `governance:read`, `ballot:write`. + +## Bootstrap context schema + +`cli/bootstrap.ts` writes **`schemaVersion`: `3`** only; route-chain rejects any other version. There are no persisted runtime secrets. + +- `wallets[]`: `{ type, walletId, walletAddress, signerAddresses }` (no seeded `transactionId`) +- `bots[]`: `{ id, paymentAddress, botKeyId, botId }` +- `defaultBotId`: primary bot used for discovery/freeUtxos assertions +- `signerStakeAddresses[]`: stake (`stake_test` / `stake1`) addresses aligned with `signerAddresses` (derived from each signer’s payment address). +- `sdkStakeAddress` (optional): multisig reward address for the CI SDK wallet (same derivation as `MultisigWallet.getStakeAddress()`); omitted if `CI_WALLET_TYPES` did not include `sdk`. +- `stakePoolIdHex` (optional): copied from `CI_STAKE_POOL_ID_HEX` when set. + +### Native scripts and wallet types + +Cardano “native scripts” here are `sig` / `all` / `any` / `atLeast` trees ([`MultisigWallet`](src/utils/multisigSDK.ts)). + +- **Staking (SDK multisig):** UTxOs are witnessed with the **payment** script; stake registration / delegation / deregistration certificates use **`certificateScript`** with the **staking** script (`buildScript(2)` / role `2` keys). Bootstrap always attaches role-2 stake keys for the SDK wallet. Because the staking script uses **stake key hashes** (distinct from payment key hashes), `signTransaction` accepts an optional `stakeKey` / `stakeSignature` pair validated against `wallet.signersStakeKeys`. +- **DRep registration / voting:** **Legacy** wallets use a **single** script (payment-only) for both spending and DRep identity. **SDK** wallets with DRep keys use the **payment** script for inputs and a **DRep** script (`buildScript(3)`) for DRep certificates. In the CI bootstrap `signersDRepKeys` is set to the payment key hashes, so standard payment-key witnesses satisfy the DRep certificate script without any additional witness type. + +Security guarantees: + +- The context file does not store bot JWT tokens. +- The context file does not store bot secrets. +- Route steps authenticate bots on demand at runtime. +- `docker-compose.ci.yml` removes the context file after route-chain execution. +- Failure log upload applies token/secret/mnemonic/private-key redaction filters. + +Limitation: + +- If application code logs sensitive values directly, redaction can miss uncommon formats. +- Treat uploaded logs as diagnostic artifacts, not as guaranteed zero-leak outputs. + +Logging policy (required for contributors): + +- It is acceptable to log non-sensitive diagnostics: wallet IDs, transaction hashes, key hashes, and testnet addresses. +- Never log raw secrets: mnemonics, private keys/signing keys, bot auth secrets, bearer tokens, or API keys. +- Redaction is best-effort safety net; route steps and helpers must avoid printing sensitive raw values in the first place. + +Safe-to-print checklist for new route/scenario code: + +- Safe: `walletId`, `transactionId`/tx hash, `paymentAddress`/`stakeAddress` (testnet), `keyHash`, scenario ids/status. +- Forbidden: any `CI_MNEMONIC_*` value, any `xprv*`/`ed25519*_sk*` material, `Authorization` headers, `secret`/`token` payload fields. + +## Report format + +`ci-route-chain-report.md` is a Markdown file structured for human triage. It contains: + +1. **Run header** — overall status, timestamp, duration, network, wallet types. +2. **Wallet balances table** — UTxO count and ADA balance per wallet type at run end. Native asset counts noted when present. +3. **Scenario summary table** — pass/fail, step pass rate, and duration per scenario. +4. **Step detail sections** — one subsection per scenario with a step table (step ID, duration, result message). Failed steps include their error and artifacts as code blocks. Passing step artifacts are intentionally omitted from Markdown, so use the step message and rerun targeted scenarios when detailed recovery diagnostics are needed. + +Balance source: direct on-chain UTxO lookup per wallet address from bootstrap context (includes UTxOs referenced by pending transactions). Lovelace values shown as ADA (2 d.p.). If balance collection fails, a warning line replaces the table. + +## Proxy Full Lifecycle UTxO Shaping + +`scenario.proxy-full-lifecycle` needs a wallet script UTxO for proxy setup/spend and a separate key-address collateral UTxO at `bot.paymentAddress` for each eligible wallet type (`legacy`, `hierarchical`, `sdk`). When a funded wallet has enough ADA but lacks the required wallet/key UTxO shape, the route-chain now performs an idempotent self-split before the proxy preflight: + +- If fresh `freeUtxos` plus fresh `bot.paymentAddress` UTxOs already satisfy the lifecycle budget and key collateral shape, the shaping step is a no-op. +- If wallet ADA is sufficient but the shape is not, the step submits a real preprod self-split through `/api/v1/addTransaction`, creating a 6 ADA collateral output at `bot.paymentAddress` and returning the rest as change to the wallet script address. The split requires the 536 ADA lifecycle budget plus the 6 ADA collateral output and a 2 ADA self-split fee buffer. +- The self-split is signed by signer 1 and signer 2 using the existing `CI_MNEMONIC_2` / `CI_MNEMONIC_3` route-chain signing path, then waits for the original inputs to disappear from fresh `freeUtxos`. +- Server-built proxy transactions are persisted with no initial signed addresses. Because key-address collateral lives at `bot.paymentAddress`, proxy setup and action transactions first add signer index 0 (`CI_MNEMONIC_1`) as a real collateral witness, then signer index 1 (`CI_MNEMONIC_2`) broadcasts for the default threshold-2 wallet. +- Manual funding is still required when the wallet does not have enough total ADA for the proxy lifecycle budget plus the 6 ADA collateral output and fee buffer. + +Because the self-split is an on-chain transaction, it can add one confirmation wait per wallet type, but only when the current UTxO shape needs repair. + +## How to contribute + +### Add a new route step + +1. Copy `scenarios/steps/template-route-step.ts` into a new step module under `scenarios/steps/`. +2. Set a stable `id` and route-specific `description`. +3. Implement deterministic inputs from context/env. +4. Call route(s) via `requestJson`. +5. Add strict assertions and concise artifacts for failure triage. +6. Register the step in `scenarios/manifest.ts`. + +### Add a new scenario + +1. Build a scenario factory in `scenarios/manifest.ts`. +2. Keep ordering intentional (upstream dependencies first). +3. Mark step severity correctly: + - `critical`: stop scenario/chain on failure. + - `non-critical`: continue and report. +4. Ensure artifacts are small but diagnostic. + +### Keep things maintainable + +- Do not overload bootstrap with route-specific behavior. +- Prefer reusable helpers in `framework/` or `scenarios/flows/`. +- Keep step ids stable (helps CI history and triage). +- Avoid hidden randomness in assertions; use deterministic checks. +- For governance scenarios, derive proposal lists via `framework/governance.ts` so payload shape and proposal selection remain deterministic across step reruns. + +## Local execution (PowerShell, CI-like) + +From repo root: + +- `C:\Users\andru\Documents\GitHub\multisig` + +Set required CI variables in your current shell: + +```powershell +$env:CI_JWT_SECRET="..." +$env:CI_MNEMONIC_1="..." +$env:CI_MNEMONIC_2="..." +$env:CI_MNEMONIC_3="..." +$env:CI_BLOCKFROST_PREPROD_API_KEY="..." +$env:CI_NETWORK_ID="0" +$env:CI_WALLET_TYPES="legacy,hierarchical,sdk" +$env:CI_TRANSFER_LOVELACE="2000000" +$env:SIGN_BROADCAST="true" +$env:CI_DREP_ANCHOR_URL="https://..." # required for the default full flow; stored as on-chain anchor URL, never fetched +$env:CI_STAKE_POOL_ID_HEX="..." # required for the default full flow (scenario.stake-certificates) +``` + +`CI_DREP_ANCHOR_JSON` contains the full CIP-119 JSON document and must be set separately using a PowerShell here-string so the double quotes are preserved: + +```powershell +$env:CI_DREP_ANCHOR_JSON = @' +{ + "@context": { + "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + "CIP119": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/README.md#", + ... + }, + "hashAlgorithm": "blake2b-256", + "body": { ... } +} +'@ +``` + +In GitHub Actions, store the full JSON as a repository secret — the runner injects it verbatim, no quoting required. + +Optional (recommended for full flow): + +```powershell +Remove-Item Env:CI_ROUTE_SCENARIOS -ErrorAction SilentlyContinue +$env:CI_ROUTE_SCENARIOS="" +``` + +Start a clean CI-like stack: + +If you changed local code or Dockerfiles, rebuild `app` and `ci-runner`; otherwise you can skip the `build` command for faster reruns. + +```powershell +docker compose -f docker-compose.ci.yml down -v +docker compose -f docker-compose.ci.yml build app ci-runner +docker compose -f docker-compose.ci.yml up -d postgres app +``` + +Bootstrap wallets and write host-mounted artifacts: + +```powershell +docker compose -f docker-compose.ci.yml run --rm ` + -e CI_CONTEXT_PATH=/artifacts/ci-wallet-context.json ` + ci-runner npx --yes tsx scripts/ci/cli/bootstrap.ts +``` + +Optional: confirm wallets are funded on-chain before running route-chain (uses `CI_CONTEXT_PATH` and `CI_BLOCKFROST_PREPROD_API_KEY`; same total-balance semantics as `walletBalanceSummary` in the route-chain report). Flags: `--json` (machine-readable summary only), `--strict` (exit with status 1 if balance collection fails). + +```powershell +docker compose -f docker-compose.ci.yml run --rm ` + -e CI_CONTEXT_PATH=/artifacts/ci-wallet-context.json ` + ci-runner npx --yes tsx scripts/ci/cli/wallet-status.ts +``` + +Run route-chain smoke scenarios: + +```powershell +docker compose -f docker-compose.ci.yml run --rm ` + -e CI_CONTEXT_PATH=/artifacts/ci-wallet-context.json ` + -e CI_ROUTE_CHAIN_REPORT_PATH=/artifacts/ci-route-chain-report.md ` + ci-runner npx --yes tsx scripts/ci/cli/route-chain.ts + +``` + +View generated report on host: + +```powershell +Get-Content ".\ci-artifacts\ci-route-chain-report.md" +``` + +## Local execution (Linux/Bash, CI-like) + +From repo root: + +- `/path/to/multisig` + +Set required CI variables in your current shell: + +```bash +export CI_JWT_SECRET="..." +export CI_MNEMONIC_1="..." +export CI_MNEMONIC_2="..." +export CI_MNEMONIC_3="..." +export CI_BLOCKFROST_PREPROD_API_KEY="..." +export CI_NETWORK_ID="0" +export CI_WALLET_TYPES="legacy,hierarchical,sdk" +export CI_TRANSFER_LOVELACE="2000000" +export SIGN_BROADCAST="true" +export CI_DREP_ANCHOR_URL="https://..." # required for the default full flow; stored as on-chain anchor URL, never fetched +export CI_STAKE_POOL_ID_HEX="..." # required for the default full flow (scenario.stake-certificates) +``` + +`CI_DREP_ANCHOR_JSON` contains the full CIP-119 JSON document and must be set separately using a heredoc so the double quotes are preserved: + +```bash +export CI_DREP_ANCHOR_JSON=$(cat <<'EOF' +{ + "@context": { + "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + "CIP119": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/README.md#", + ... + }, + "hashAlgorithm": "blake2b-256", + "body": { ... } +} +EOF +) +``` + +In GitHub Actions, store the full JSON as a repository secret — the runner injects it verbatim, no quoting required. + +Optional (recommended for full flow): + +```bash +unset CI_ROUTE_SCENARIOS +export CI_ROUTE_SCENARIOS="" +``` + +Start a clean CI-like stack: + +If you changed local code or Dockerfiles, rebuild `app` and `ci-runner`; otherwise you can skip the `build` command for faster reruns. + +```bash +docker compose -f docker-compose.ci.yml down -v +docker compose -f docker-compose.ci.yml build app ci-runner +docker compose -f docker-compose.ci.yml up -d postgres app +``` + +Bootstrap wallets and write host-mounted artifacts: + +```bash +docker compose -f docker-compose.ci.yml run --rm \ + -e CI_CONTEXT_PATH=/artifacts/ci-wallet-context.json \ + ci-runner npx --yes tsx scripts/ci/cli/bootstrap.ts +``` + +Optional: confirm wallets are funded on-chain before running route-chain (uses `CI_CONTEXT_PATH` and `CI_BLOCKFROST_PREPROD_API_KEY`; same total-balance semantics as `walletBalanceSummary` in the route-chain report). Flags: `--json` (machine-readable summary only), `--strict` (exit with status 1 if balance collection fails). + +```bash +docker compose -f docker-compose.ci.yml run --rm \ + -e CI_CONTEXT_PATH=/artifacts/ci-wallet-context.json \ + ci-runner npx --yes tsx scripts/ci/cli/wallet-status.ts +``` + +Run route-chain smoke scenarios: + +```bash +docker compose -f docker-compose.ci.yml run --rm \ + -e CI_CONTEXT_PATH=/artifacts/ci-wallet-context.json \ + -e CI_ROUTE_CHAIN_REPORT_PATH=/artifacts/ci-route-chain-report.md \ + ci-runner npx --yes tsx scripts/ci/cli/route-chain.ts +``` + +View generated report on host: + +```bash +cat ./ci-artifacts/ci-route-chain-report.md +``` diff --git a/scripts/ci/cli/bootstrap.ts b/scripts/ci/cli/bootstrap.ts new file mode 100644 index 00000000..0138922b --- /dev/null +++ b/scripts/ci/cli/bootstrap.ts @@ -0,0 +1,326 @@ +import { BotWalletRole, PrismaClient } from "@prisma/client"; +import { stringifyRedacted } from "../framework/redact"; +import { requireEnv, parseWalletTypesEnv } from "../framework/env"; +import { parseMnemonic } from "../framework/mnemonic"; +import { deriveCiBotSecret } from "../framework/botAuth"; +import { hashBotSecret } from "../framework/botProvision"; +import { + deserializeAddress, + resolvePaymentKeyHash, + resolveStakeKeyHash, + serializeRewardAddress, +} from "@meshsdk/core"; +import { MultisigWallet, type MultisigKey } from "../../../src/utils/multisigSDK"; + +const prisma = new PrismaClient(); + +type CIWalletType = "legacy" | "hierarchical" | "sdk"; + +type PaymentNativeScript = + | { type: "sig"; keyHash: string } + | { type: "all"; scripts: PaymentNativeScript[] } + | { type: "any"; scripts: PaymentNativeScript[] } + | { type: "atLeast"; required: number; scripts: PaymentNativeScript[] }; + +type CIBotBootstrap = { + id: string; + paymentAddress: string; + botKeyId: string; + botId: string; +}; + +function stakeAddressFromPaymentAddress(paymentAddress: string): string { + const stakeHash = deserializeAddress(paymentAddress).stakeCredentialHash; + if (!stakeHash) { + throw new Error("Expected stake credential on payment address for CI signer"); + } + const network = paymentAddress.includes("test") ? 0 : 1; + const stake = serializeRewardAddress(stakeHash, false, network); + if (!stake) { + throw new Error("Could not serialize stake address from payment address"); + } + return stake; +} + +function buildSdkMultisigStakeAddress(args: { + signersAddresses: string[]; + signerStakeAddresses: string[]; + signerDescriptions: string[]; + paymentKeyHashes: string[]; + numRequiredSigners: number; + networkId: 0 | 1; +}): string { + const keys: MultisigKey[] = []; + for (let i = 0; i < args.signersAddresses.length; i++) { + const addr = args.signersAddresses[i]; + if (!addr) continue; + keys.push({ + keyHash: resolvePaymentKeyHash(addr), + role: 0, + name: args.signerDescriptions[i] ?? "", + }); + } + for (let i = 0; i < args.signerStakeAddresses.length; i++) { + const sk = args.signerStakeAddresses[i]; + if (!sk) continue; + keys.push({ + keyHash: resolveStakeKeyHash(sk), + role: 2, + name: args.signerDescriptions[i] ?? "", + }); + } + for (let i = 0; i < args.paymentKeyHashes.length; i++) { + const drep = args.paymentKeyHashes[i]; + if (!drep) continue; + keys.push({ keyHash: drep, role: 3, name: args.signerDescriptions[i] ?? "" }); + } + const wallet = new MultisigWallet( + "ci-sdk-preview", + keys, + "", + args.numRequiredSigners, + args.networkId, + undefined, + "atLeast", + ); + if (!wallet.stakingEnabled()) { + throw new Error("CI SDK preview MultisigWallet: staking not enabled (check signer key roles)"); + } + const stakeAddr = wallet.getStakeAddress(); + if (!stakeAddr) { + throw new Error("CI SDK preview MultisigWallet: could not derive multisig stake address"); + } + return stakeAddr; +} + +async function deriveAddress(words: string[], networkId: 0 | 1): Promise { + const { MeshWallet } = await import("@meshsdk/core"); + const wallet = new MeshWallet({ + networkId, + key: { type: "mnemonic", words }, + }); + await wallet.init(); + return wallet.getChangeAddress(); +} + +async function main() { + const apiBaseUrl = (process.env.API_BASE_URL ?? "http://app:3000").trim().replace(/\/$/, ""); + const jwtSecret = requireEnv("CI_JWT_SECRET"); + const mnemonic1 = requireEnv("CI_MNEMONIC_1"); + const mnemonic2 = requireEnv("CI_MNEMONIC_2"); + const mnemonic3 = requireEnv("CI_MNEMONIC_3"); + const walletTypes = parseWalletTypesEnv( + process.env.CI_WALLET_TYPES ?? "legacy,hierarchical,sdk", + ); + const parsedNetworkId = Number(process.env.CI_NETWORK_ID ?? "0"); + const networkId: 0 | 1 = parsedNetworkId === 1 ? 1 : 0; + const requiredSigners = Math.max( + 1, + Number.isFinite(Number(process.env.CI_NUM_REQUIRED_SIGNERS ?? "2")) + ? Number(process.env.CI_NUM_REQUIRED_SIGNERS ?? "2") + : 2, + ); + const contextPath = process.env.CI_CONTEXT_PATH ?? "/tmp/ci-wallet-context.json"; + const stakePoolIdHex = + typeof process.env.CI_STAKE_POOL_ID_HEX === "string" && process.env.CI_STAKE_POOL_ID_HEX.trim() + ? process.env.CI_STAKE_POOL_ID_HEX.trim() + : undefined; + + const signerAddresses = await Promise.all([ + deriveAddress(parseMnemonic(mnemonic1), networkId), + deriveAddress(parseMnemonic(mnemonic2), networkId), + deriveAddress(parseMnemonic(mnemonic3), networkId), + ]); + + const signerStakeAddresses = signerAddresses.map((addr) => stakeAddressFromPaymentAddress(addr)); + + const signerBots: CIBotBootstrap[] = []; + const botAuthByAddress: Record = {}; + for (let i = 0; i < signerAddresses.length; i++) { + const paymentAddress = signerAddresses[i]; + if (!paymentAddress) { + throw new Error(`Missing signer address at index ${i}`); + } + const botSecret = deriveCiBotSecret(paymentAddress, jwtSecret); + const botKey = await prisma.botKey.create({ + data: { + ownerAddress: `ci-owner-${Date.now()}-${i}`, + name: `ci-bot-signer-${i}-${Date.now()}`, + keyHash: hashBotSecret(botSecret, jwtSecret), + scope: JSON.stringify([ + "multisig:create", + "multisig:read", + "multisig:sign", + "governance:read", + "ballot:write", + ]), + }, + }); + + const botAuthResponse = await fetch(`${apiBaseUrl}/api/v1/botAuth`, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + botKeyId: botKey.id, + secret: botSecret, + paymentAddress, + }), + }); + const botAuthBody = await botAuthResponse.json(); + if (!botAuthResponse.ok || !botAuthBody?.token || !botAuthBody?.botId) { + throw new Error( + `botAuth failed for signer index ${i} (${botAuthResponse.status}): ${stringifyRedacted(botAuthBody)}`, + ); + } + + signerBots.push({ + id: `signer${i}`, + paymentAddress, + botKeyId: botKey.id, + botId: botAuthBody.botId as string, + }); + botAuthByAddress[paymentAddress] = botAuthBody.token as string; + } + const primaryBot = signerBots[0]; + if (!primaryBot) { + throw new Error("No signer bots were provisioned"); + } + + const paymentKeyHashes = signerAddresses.map((addr) => resolvePaymentKeyHash(addr)); + + const signerDescriptions = ["CI Signer 1", "CI Signer 2", "CI Signer 3"]; + const numRequired = Math.min(requiredSigners, signerAddresses.length); + + const createdWallets: Array<{ + type: CIWalletType; + walletId: string; + walletAddress: string; + signerAddresses: string[]; + }> = []; + + let sdkStakeAddress: string | undefined; + + for (const walletType of walletTypes) { + const basePayload: Record = { + name: `CI ${walletType} Wallet ${Date.now()}`, + description: `CI ${walletType} wallet smoke test`, + signersAddresses: signerAddresses, + signersDescriptions: signerDescriptions, + numRequiredSigners: numRequired, + scriptType: "atLeast", + network: networkId, + }; + + if (walletType === "hierarchical") { + basePayload.scriptType = "all"; + basePayload.paymentNativeScript = { + type: "all", + scripts: [ + { + type: "atLeast", + required: Math.min(requiredSigners, paymentKeyHashes.length), + scripts: paymentKeyHashes.map((keyHash) => ({ type: "sig", keyHash })), + }, + ], + } satisfies PaymentNativeScript; + } + + if (walletType === "sdk") { + basePayload.signersDRepKeys = paymentKeyHashes; + basePayload.signersStakeKeys = signerStakeAddresses; + } + + const createWalletResponse = await fetch(`${apiBaseUrl}/api/v1/createWallet`, { + method: "POST", + headers: { + "content-type": "application/json", + authorization: `Bearer ${botAuthByAddress[primaryBot.paymentAddress]}`, + }, + body: JSON.stringify(basePayload), + }); + const createWalletBody = await createWalletResponse.json(); + if (!createWalletResponse.ok || !createWalletBody?.walletId) { + throw new Error( + `createWallet (${walletType}) failed (${createWalletResponse.status}): ${stringifyRedacted(createWalletBody)}`, + ); + } + + if (walletType === "sdk") { + sdkStakeAddress = buildSdkMultisigStakeAddress({ + signersAddresses: signerAddresses, + signerStakeAddresses, + signerDescriptions, + paymentKeyHashes, + numRequiredSigners: numRequired, + networkId, + }); + } + + for (const bot of signerBots.slice(1)) { + await prisma.walletBotAccess.upsert({ + where: { + walletId_botId: { + walletId: createWalletBody.walletId as string, + botId: bot.botId, + }, + }, + update: { + role: BotWalletRole.cosigner, + }, + create: { + walletId: createWalletBody.walletId as string, + botId: bot.botId, + role: BotWalletRole.cosigner, + }, + }); + } + + createdWallets.push({ + type: walletType, + walletId: createWalletBody.walletId as string, + walletAddress: createWalletBody.address as string, + signerAddresses, + }); + } + + await import("fs/promises").then((fs) => + fs.writeFile( + contextPath, + JSON.stringify( + { + schemaVersion: 3, + createdAt: new Date().toISOString(), + apiBaseUrl, + networkId, + walletTypes, + wallets: createdWallets, + bots: signerBots, + defaultBotId: primaryBot.id, + walletId: createdWallets[0]?.walletId, + walletAddress: createdWallets[0]?.walletAddress, + signerAddresses, + signerStakeAddresses, + sdkStakeAddress, + ...(stakePoolIdHex ? { stakePoolIdHex } : {}), + }, + null, + 2, + ), + "utf8", + ), + ); + + console.log( + `Created wallets: ${createdWallets.map((w) => `${w.type}:${w.walletId}`).join(", ")}`, + ); + console.log(`Saved CI context (schema 3) to ${contextPath}`); +} + +main() + .catch((error) => { + console.error("bootstrap failed:", error); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/scripts/ci/cli/inspect-context.ts b/scripts/ci/cli/inspect-context.ts new file mode 100644 index 00000000..9eeadad7 --- /dev/null +++ b/scripts/ci/cli/inspect-context.ts @@ -0,0 +1,48 @@ +import { loadBootstrapContext } from "../framework/context"; +import { getBotForAddress, getDefaultBot } from "../framework/botContext"; +import { requireEnv } from "../framework/env"; + +function maskMiddle(value: string): string { + if (value.length <= 12) { + return `${value.slice(0, 4)}...${value.slice(-2)}`; + } + return `${value.slice(0, 8)}...${value.slice(-8)}`; +} + +async function main() { + const contextPath = requireEnv("CI_CONTEXT_PATH", "/tmp/ci-wallet-context.json"); + const ctx = await loadBootstrapContext(contextPath); + const defaultBot = getDefaultBot(ctx); + + console.log(`Context file: ${contextPath}`); + console.log(`Schema version: ${ctx.schemaVersion}`); + console.log(`API base URL: ${ctx.apiBaseUrl}`); + console.log(`Network ID: ${ctx.networkId}`); + console.log(`Wallets: ${ctx.wallets.length}`); + console.log(`Bots: ${ctx.bots.length}`); + console.log(`Default bot: ${defaultBot.id} (${maskMiddle(defaultBot.paymentAddress)})`); + console.log( + `Signer stake addresses: ${ctx.signerStakeAddresses.map((a) => maskMiddle(a)).join(", ")}`, + ); + if (ctx.sdkStakeAddress) { + console.log(`SDK multisig reward address: ${maskMiddle(ctx.sdkStakeAddress)}`); + } + if (ctx.stakePoolIdHex) { + console.log(`Stake pool id (hex): ${maskMiddle(ctx.stakePoolIdHex)}`); + } + console.log(""); + + console.log("Signer to bot mapping:"); + for (const [walletIndex, wallet] of ctx.wallets.entries()) { + console.log(`- [${walletIndex}] ${wallet.type} wallet ${wallet.walletId}`); + wallet.signerAddresses.forEach((address, signerIndex) => { + const bot = getBotForAddress(ctx, address); + console.log(` signer[${signerIndex}] ${maskMiddle(address)} -> ${bot.id}`); + }); + } +} + +main().catch((error) => { + console.error("inspect-context failed:", error); + process.exit(1); +}); diff --git a/scripts/ci/cli/route-chain.ts b/scripts/ci/cli/route-chain.ts new file mode 100644 index 00000000..8179f979 --- /dev/null +++ b/scripts/ci/cli/route-chain.ts @@ -0,0 +1,58 @@ +import { loadBootstrapContext } from "../framework/context"; +import { runScenarios } from "../framework/runner"; +import { writeMarkdownReport } from "../framework/markdown"; +import { getScenarioManifest, ROUTE_SCENARIO_IDS } from "../scenarios/manifest"; +import { requireEnv, parseCommaList } from "../framework/env"; +import { assertPreprodContext } from "../framework/preprod"; + +async function main() { + const contextPath = requireEnv("CI_CONTEXT_PATH", "/tmp/ci-wallet-context.json"); + const reportPath = requireEnv("CI_ROUTE_CHAIN_REPORT_PATH", "/tmp/ci-route-chain-report.md"); + const context = await loadBootstrapContext(contextPath); + assertPreprodContext(context); + const requestedScenarioIds = parseCommaList(process.env.CI_ROUTE_SCENARIOS); + const allScenarioIds = new Set(ROUTE_SCENARIO_IDS); + const unknownScenarioIds = requestedScenarioIds.filter((id) => !allScenarioIds.has(id)); + if (unknownScenarioIds.length) { + throw new Error( + `Unknown scenario id(s) in CI_ROUTE_SCENARIOS: ${unknownScenarioIds.join(", ")}. Available: ${Array.from(allScenarioIds).join(", ")}`, + ); + } + const scenarios = getScenarioManifest(context, requestedScenarioIds); + + if (!scenarios.length) { + throw new Error( + requestedScenarioIds.length + ? `No route scenarios matched CI_ROUTE_SCENARIOS='${requestedScenarioIds.join(",")}'` + : "No route scenarios enabled in manifest", + ); + } + + const report = await runScenarios({ + scenarios, + ctx: context, + continueOnNonCriticalFailure: true, + }); + await writeMarkdownReport(report, reportPath); + + for (const scenario of report.scenarios) { + console.log(`[${scenario.status.toUpperCase()}] ${scenario.id}`); + for (const step of scenario.steps) { + if (step.status === "passed") { + console.log(` + ${step.id} (${step.durationMs}ms) - ${step.message}`); + } else { + console.log(` x ${step.id} (${step.durationMs}ms) - ${step.error ?? step.message}`); + } + } + } + console.log(`Route-chain report written to ${reportPath} (markdown)`); + + if (report.status !== "passed") { + throw new Error("Route-chain scenario run failed"); + } +} + +main().catch((error) => { + console.error("route-chain failed:", error); + process.exit(1); +}); diff --git a/scripts/ci/cli/wallet-status.ts b/scripts/ci/cli/wallet-status.ts new file mode 100644 index 00000000..e416a829 --- /dev/null +++ b/scripts/ci/cli/wallet-status.ts @@ -0,0 +1,78 @@ +import { loadBootstrapContext } from "../framework/context"; +import { requireEnv } from "../framework/env"; +import { assertPreprodContext } from "../framework/preprod"; +import { collectWalletBalanceSummary } from "../framework/walletBalances"; +import type { CIWalletBalanceEntry } from "../framework/types"; + +function parseArgs(argv: string[]): { json: boolean; strict: boolean } { + let json = false; + let strict = false; + for (const arg of argv) { + if (arg === "--json") { + json = true; + } else if (arg === "--strict") { + strict = true; + } + } + return { json, strict }; +} + +function lovelaceToAdaDisplay(lovelace: string): string { + const v = BigInt(lovelace); + const whole = v / 1_000_000n; + const frac = v % 1_000_000n; + if (frac === 0n) { + return whole.toString(); + } + const fracStr = frac.toString().padStart(6, "0").replace(/0+$/, ""); + return `${whole}.${fracStr}`; +} + +function printHumanTable( + wallets: { walletId: string; type: string }[], + getEntry: (walletId: string) => CIWalletBalanceEntry | undefined, +): void { + console.log("CI wallet balances (multisig script addresses, total on-chain UTxO sums)"); + console.log(""); + for (const w of wallets) { + const e = getEntry(w.walletId); + if (!e) { + console.log(`${w.type}\t${w.walletId}\t(no balance entry)`); + continue; + } + const ada = lovelaceToAdaDisplay(e.lovelace); + console.log(`${e.walletType}\t${e.walletId}`); + console.log(` address: ${e.walletAddress}`); + console.log(` utxos: ${e.utxoCount}\tlovelace: ${e.lovelace}\t(~${ada} ADA)`); + console.log(""); + } +} + +async function main() { + const { json, strict } = parseArgs(process.argv.slice(2)); + const contextPath = requireEnv("CI_CONTEXT_PATH", "/tmp/ci-wallet-context.json"); + const ctx = await loadBootstrapContext(contextPath); + assertPreprodContext(ctx); + + const summary = await collectWalletBalanceSummary(ctx); + + if (json) { + console.log(JSON.stringify(summary, null, 2)); + } else { + printHumanTable(ctx.wallets, (id) => summary.byWalletId[id]); + if (summary.error) { + console.error(`Wallet balance collection reported an error: ${summary.error}`); + } else { + console.log(`Captured at: ${summary.capturedAt} (networkId=${summary.networkId})`); + } + } + + if (summary.error && strict) { + process.exit(1); + } +} + +main().catch((error) => { + console.error("wallet-status failed:", error); + process.exit(1); +}); diff --git a/scripts/ci/framework/botAuth.ts b/scripts/ci/framework/botAuth.ts new file mode 100644 index 00000000..d872126f --- /dev/null +++ b/scripts/ci/framework/botAuth.ts @@ -0,0 +1,94 @@ +import { createHmac } from "crypto"; +import type { CIBootstrapContext, CIBotContext } from "./types"; +import { requestJson } from "./http"; + +type CachedBotToken = { + token: string; + expiresAtMs: number; +}; + +const botTokenCache = new Map(); +const BOT_AUTH_RETRY_DELAYS_MS = [250, 500, 1000] as const; + +export function requireCiJwtSecret(): string { + const value = process.env.CI_JWT_SECRET; + if (!value || !value.trim()) { + throw new Error("Missing required environment variable: CI_JWT_SECRET"); + } + return value.trim(); +} + +// Deterministic secret lets us re-auth bots without persisting secrets to disk. +export function deriveCiBotSecret(paymentAddress: string, jwtSecret: string): string { + return createHmac("sha256", jwtSecret) + .update(`ci-bot-secret:${paymentAddress}`, "utf8") + .digest("hex"); +} + +function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function decodeJwtExpiryMs(token: string): number | null { + const payload = token.split(".")[1]; + if (!payload) return null; + try { + const decoded = JSON.parse(Buffer.from(payload, "base64url").toString("utf8")) as { exp?: unknown }; + if (typeof decoded.exp !== "number" || !Number.isFinite(decoded.exp)) return null; + return decoded.exp * 1000; + } catch { + return null; + } +} + +function getBotCacheKey(bot: CIBotContext): string { + return `${bot.id}:${bot.paymentAddress}`; +} + +export async function authenticateBot(args: { + ctx: CIBootstrapContext; + bot: CIBotContext; +}): Promise { + const cacheKey = getBotCacheKey(args.bot); + const now = Date.now(); + const cacheHit = botTokenCache.get(cacheKey); + if (cacheHit && cacheHit.expiresAtMs - now > 10_000) { + return cacheHit.token; + } + + const secret = deriveCiBotSecret(args.bot.paymentAddress, requireCiJwtSecret()); + let auth: { status: number; data: { token?: string; error?: string } } | null = null; + for (let attempt = 0; attempt <= BOT_AUTH_RETRY_DELAYS_MS.length; attempt++) { + auth = await requestJson<{ token?: string; error?: string }>({ + url: `${args.ctx.apiBaseUrl}/api/v1/botAuth`, + method: "POST", + body: { + botKeyId: args.bot.botKeyId, + secret, + paymentAddress: args.bot.paymentAddress, + }, + }); + if (auth.status !== 429) { + break; + } + if (attempt < BOT_AUTH_RETRY_DELAYS_MS.length) { + const retryDelayMs = BOT_AUTH_RETRY_DELAYS_MS[attempt]; + if (retryDelayMs !== undefined) { + await sleep(retryDelayMs); + } + } + } + + if (!auth || auth.status !== 200 || !auth.data?.token) { + const failedStatus = auth?.status ?? "no-response"; + throw new Error(`botAuth failed (${failedStatus})`); + } + + const expiresAtMs = decodeJwtExpiryMs(auth.data.token) ?? Date.now() + 55 * 60 * 1000; + botTokenCache.set(cacheKey, { + token: auth.data.token, + expiresAtMs, + }); + + return auth.data.token; +} diff --git a/scripts/ci/framework/botContext.ts b/scripts/ci/framework/botContext.ts new file mode 100644 index 00000000..902c9d1c --- /dev/null +++ b/scripts/ci/framework/botContext.ts @@ -0,0 +1,46 @@ +import type { CIBootstrapContext, CIBotContext, CIWalletContext } from "./types"; + +export function getDefaultBot(ctx: CIBootstrapContext): CIBotContext { + if (ctx.defaultBotId) { + const matched = ctx.bots.find((bot) => bot.id === ctx.defaultBotId); + if (matched) { + return matched; + } + } + + const fallback = ctx.bots[0]; + if (!fallback) { + throw new Error("Context has no bot credentials"); + } + return fallback; +} + +export function getBotForAddress( + ctx: CIBootstrapContext, + paymentAddress: string, +): CIBotContext { + const address = paymentAddress.trim(); + const matched = ctx.bots.find((bot) => bot.paymentAddress === address); + if (matched) { + return matched; + } + throw new Error(`No bot context found for paymentAddress ${address}`); +} + +export function getBotForSignerIndex(args: { + ctx: CIBootstrapContext; + wallet: CIWalletContext; + signerIndex: number; +}): { bot: CIBotContext; signerAddress: string } { + const signerAddress = args.wallet.signerAddresses[args.signerIndex]; + if (!signerAddress) { + throw new Error( + `Context is missing signerAddresses[${args.signerIndex}] for wallet ${args.wallet.walletId}`, + ); + } + + return { + bot: getBotForAddress(args.ctx, signerAddress), + signerAddress, + }; +} diff --git a/scripts/ci/framework/botProvision.ts b/scripts/ci/framework/botProvision.ts new file mode 100644 index 00000000..d7e1a042 --- /dev/null +++ b/scripts/ci/framework/botProvision.ts @@ -0,0 +1,5 @@ +import { createHmac } from "crypto"; + +export function hashBotSecret(secret: string, jwtSecret: string): string { + return createHmac("sha256", jwtSecret).update(secret, "utf8").digest("hex"); +} diff --git a/scripts/ci/framework/context.ts b/scripts/ci/framework/context.ts new file mode 100644 index 00000000..e975f37a --- /dev/null +++ b/scripts/ci/framework/context.ts @@ -0,0 +1,133 @@ +import { readFile } from "fs/promises"; +import type { CIBootstrapContext, CIBotContext, CIWalletType } from "./types"; + +function assertString(name: string, value: unknown): string { + if (typeof value !== "string" || !value.trim()) { + throw new Error(`Invalid context: ${name} must be a non-empty string`); + } + return value.trim(); +} + +function optionalString(value: unknown): string | undefined { + return typeof value === "string" && value.trim() ? value.trim() : undefined; +} + +function assertStringArray(name: string, value: unknown): string[] { + if (!Array.isArray(value) || value.length === 0) { + throw new Error(`Invalid context: ${name} must be a non-empty array`); + } + const normalized = value.map((item, idx) => { + if (typeof item !== "string" || !item.trim()) { + throw new Error(`Invalid context: ${name}[${idx}] must be a non-empty string`); + } + return item.trim(); + }); + return normalized; +} + +function normalizeWalletType(value: unknown): CIWalletType { + const v = typeof value === "string" ? value.trim().toLowerCase() : ""; + if (v === "legacy" || v === "hierarchical" || v === "sdk") return v; + throw new Error(`Invalid context: unsupported wallet type '${String(value)}'`); +} + +function normalizeBots(input: Record): { + bots: CIBotContext[]; + defaultBotId?: string; +} { + const botsRaw = input.bots; + if (!Array.isArray(botsRaw) || botsRaw.length === 0) { + throw new Error("Invalid context: bots must be a non-empty array"); + } + const bots = botsRaw.map((bot, idx) => { + if (!bot || typeof bot !== "object") { + throw new Error(`Invalid context: bots[${idx}] must be an object`); + } + const b = bot as Record; + return { + id: assertString(`bots[${idx}].id`, b.id), + paymentAddress: assertString(`bots[${idx}].paymentAddress`, b.paymentAddress), + botKeyId: assertString(`bots[${idx}].botKeyId`, b.botKeyId), + botId: typeof b.botId === "string" && b.botId.trim() ? b.botId.trim() : undefined, + } satisfies CIBotContext; + }); + + const defaultBotIdRaw = typeof input.defaultBotId === "string" ? input.defaultBotId.trim() : ""; + const defaultBotId = defaultBotIdRaw || bots[0]?.id; + return { bots, defaultBotId }; +} + +export function validateBootstrapContext(raw: unknown): CIBootstrapContext { + if (!raw || typeof raw !== "object") { + throw new Error("Invalid context: expected JSON object"); + } + + const input = raw as Record; + if (Number(input.schemaVersion) !== 3) { + throw new Error( + `Invalid context: unsupported schemaVersion '${String(input.schemaVersion)}' (expected 3)`, + ); + } + + const walletsRaw = input.wallets; + if (!Array.isArray(walletsRaw) || walletsRaw.length === 0) { + throw new Error("Invalid context: wallets must be a non-empty array"); + } + + const wallets = walletsRaw.map((wallet, idx) => { + if (!wallet || typeof wallet !== "object") { + throw new Error(`Invalid context: wallets[${idx}] must be an object`); + } + const w = wallet as Record; + return { + type: normalizeWalletType(w.type), + walletId: assertString(`wallets[${idx}].walletId`, w.walletId), + walletAddress: assertString(`wallets[${idx}].walletAddress`, w.walletAddress), + transactionId: optionalString(w.transactionId), + signerAddresses: assertStringArray(`wallets[${idx}].signerAddresses`, w.signerAddresses), + }; + }); + + const walletTypesRaw = Array.isArray(input.walletTypes) ? input.walletTypes : wallets.map((w) => w.type); + const walletTypes = walletTypesRaw.map((v) => normalizeWalletType(v)); + const signerAddresses = assertStringArray("signerAddresses", input.signerAddresses); + const signerStakeAddresses = assertStringArray("signerStakeAddresses", input.signerStakeAddresses); + if (signerStakeAddresses.length !== signerAddresses.length) { + throw new Error("Invalid context: signerStakeAddresses length must match signerAddresses"); + } + + const sdkStakeAddress = optionalString(input.sdkStakeAddress); + const stakePoolIdHex = optionalString(input.stakePoolIdHex); + + const normalizedBots = normalizeBots(input); + const defaultBot = + normalizedBots.bots.find((bot) => bot.id === normalizedBots.defaultBotId) ?? + normalizedBots.bots[0]; + if (!defaultBot) { + throw new Error("Invalid context: unable to resolve default bot"); + } + + return { + schemaVersion: 3, + createdAt: assertString("createdAt", input.createdAt ?? new Date().toISOString()), + apiBaseUrl: assertString("apiBaseUrl", input.apiBaseUrl), + networkId: Number(input.networkId) === 1 ? 1 : 0, + walletTypes, + wallets, + bots: normalizedBots.bots, + defaultBotId: normalizedBots.defaultBotId, + walletId: typeof input.walletId === "string" ? input.walletId : wallets[0]?.walletId, + walletAddress: + typeof input.walletAddress === "string" ? input.walletAddress : wallets[0]?.walletAddress, + signerAddresses, + signerStakeAddresses, + transactionId: optionalString(input.transactionId) ?? wallets[0]?.transactionId, + ...(sdkStakeAddress !== undefined ? { sdkStakeAddress } : {}), + ...(stakePoolIdHex !== undefined ? { stakePoolIdHex } : {}), + }; +} + +export async function loadBootstrapContext(contextPath: string): Promise { + const raw = await readFile(contextPath, "utf8"); + return validateBootstrapContext(JSON.parse(raw)); +} diff --git a/scripts/ci/framework/datumSign.ts b/scripts/ci/framework/datumSign.ts new file mode 100644 index 00000000..b84e6973 --- /dev/null +++ b/scripts/ci/framework/datumSign.ts @@ -0,0 +1,24 @@ +import type { CIBootstrapContext } from "./types"; +import { deriveSignerFromMnemonic } from "./walletAuth"; + +export async function signDatumWithMnemonic(args: { + ctx: CIBootstrapContext; + mnemonic: string; + datum: string; +}): Promise<{ + signerAddress: string; + key: string; + signature: string; +}> { + const signer = await deriveSignerFromMnemonic({ + ctx: args.ctx, + mnemonic: args.mnemonic, + }); + const signature = await signer.signData(args.datum); + return { + signerAddress: signer.signerAddress, + key: signature.key, + signature: signature.signature, + }; +} + diff --git a/scripts/ci/framework/env.ts b/scripts/ci/framework/env.ts new file mode 100644 index 00000000..042900d1 --- /dev/null +++ b/scripts/ci/framework/env.ts @@ -0,0 +1,40 @@ +import type { CIWalletType } from "./types"; + +export function requireEnv(name: string, fallback?: string): string { + const value = process.env[name] ?? fallback; + if (!value || !value.trim()) { + throw new Error(`Missing required environment variable: ${name}`); + } + return value.trim(); +} + +export function boolFromEnv(value: string | undefined, fallback: boolean): boolean { + if (value === undefined) return fallback; + return value.trim().toLowerCase() === "true"; +} + +/** Parse comma-separated non-empty tokens (e.g. CI_ROUTE_SCENARIOS). */ +export function parseCommaList(raw: string | undefined): string[] { + return (raw ?? "") + .split(",") + .map((s) => s.trim()) + .filter(Boolean); +} + +export function parseWalletTypesEnv(raw: string): CIWalletType[] { + const allowed = new Set(["legacy", "hierarchical", "sdk"]); + const requested = raw + .split(",") + .map((s) => s.trim().toLowerCase()) + .filter(Boolean); + if (!requested.length) { + throw new Error("CI_WALLET_TYPES must include at least one wallet type"); + } + const invalid = requested.filter((value) => !allowed.has(value)); + if (invalid.length) { + throw new Error( + `CI_WALLET_TYPES contains unsupported value(s): ${invalid.join(", ")}. Allowed: legacy,hierarchical,sdk`, + ); + } + return requested as CIWalletType[]; +} diff --git a/scripts/ci/framework/governance.ts b/scripts/ci/framework/governance.ts new file mode 100644 index 00000000..ba40569f --- /dev/null +++ b/scripts/ci/framework/governance.ts @@ -0,0 +1,69 @@ +export type ActiveProposal = { + proposalId: string; + title: string; +}; + +type GovernanceResponse = { + proposals?: Array<{ + proposalId?: unknown; + title?: unknown; + }>; +}; + +export function getDeterministicActiveProposals( + data: GovernanceResponse | unknown, + maxItems = 2, +): ActiveProposal[] { + const proposalsRaw = (data as GovernanceResponse | undefined)?.proposals; + if (!Array.isArray(proposalsRaw)) { + return []; + } + const proposals = proposalsRaw + .map((proposal) => { + const proposalId = + typeof proposal?.proposalId === "string" ? proposal.proposalId.trim() : ""; + if (!proposalId) return null; + const title = + typeof proposal?.title === "string" && proposal.title.trim() + ? proposal.title.trim() + : proposalId; + return { + proposalId, + title, + }; + }) + .filter((proposal): proposal is ActiveProposal => Boolean(proposal)) + .sort((a, b) => a.proposalId.localeCompare(b.proposalId)) + .slice(0, Math.max(1, maxItems)); + + return proposals; +} + +export function buildBallotUpsertPayload(args: { + walletId: string; + ballotName: string; + proposals: ActiveProposal[]; + secondPass?: boolean; +}): { + walletId: string; + ballotName: string; + proposals: Array<{ + proposalId: string; + proposalTitle: string; + choice: "Yes" | "No"; + rationaleComment: string; + }>; +} { + const isSecondPass = Boolean(args.secondPass); + return { + walletId: args.walletId, + ballotName: args.ballotName, + proposals: args.proposals.map((proposal, index) => ({ + proposalId: proposal.proposalId, + proposalTitle: proposal.title, + choice: (isSecondPass ? (index % 2 === 0 ? "No" : "Yes") : index % 2 === 0 ? "Yes" : "No"), + rationaleComment: `ci-route-chain ${isSecondPass ? "update" : "seed"} ${proposal.proposalId}`, + })), + }; +} + diff --git a/scripts/ci/framework/http.ts b/scripts/ci/framework/http.ts new file mode 100644 index 00000000..96524914 --- /dev/null +++ b/scripts/ci/framework/http.ts @@ -0,0 +1,136 @@ +type JsonRecord = Record; + +const DEFAULT_RETRY_STATUSES = new Set([408, 418, 429, 500, 502, 503, 504]); +const DEFAULT_RETRIES = 6; +const DEFAULT_RETRY_DELAY_MS = 1000; +const DEFAULT_MAX_RETRY_DELAY_MS = 30000; + +function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function parseNonNegativeInt(value: string | undefined, fallback: number): number { + if (!value?.trim()) return fallback; + const parsed = Number(value); + if (!Number.isFinite(parsed) || parsed < 0) return fallback; + return Math.floor(parsed); +} + +function getRetryAfterMs(header: string | null): number | null { + if (!header) return null; + const seconds = Number(header); + if (Number.isFinite(seconds) && seconds >= 0) { + return seconds * 1000; + } + const dateMs = Date.parse(header); + if (Number.isFinite(dateMs)) { + return Math.max(0, dateMs - Date.now()); + } + return null; +} + +function getRetryDelayMs(args: { + attempt: number; + retryDelayMs: number; + maxRetryDelayMs: number; + retryAfterMs?: number | null; +}): number { + if (typeof args.retryAfterMs === "number") { + return Math.min(args.retryAfterMs, args.maxRetryDelayMs); + } + const exponentialDelay = args.retryDelayMs * 2 ** Math.max(0, args.attempt - 1); + return Math.min(exponentialDelay, args.maxRetryDelayMs); +} + +function findBigIntPath(value: unknown, path = "body"): string | null { + if (typeof value === "bigint") return path; + if (Array.isArray(value)) { + for (let index = 0; index < value.length; index += 1) { + const childPath = findBigIntPath(value[index], `${path}[${index}]`); + if (childPath) return childPath; + } + return null; + } + if (typeof value === "object" && value !== null) { + for (const [key, child] of Object.entries(value)) { + const childPath = findBigIntPath(child, `${path}.${key}`); + if (childPath) return childPath; + } + } + return null; +} + +export async function requestJson(args: { + url: string; + method?: "GET" | "POST"; + token?: string; + body?: JsonRecord; + timeoutMs?: number; + retries?: number; + retryDelayMs?: number; + maxRetryDelayMs?: number; + retryStatuses?: number[]; +}): Promise<{ status: number; data: T }> { + const { + url, + method = "GET", + token, + body, + timeoutMs = 30000, + retries = parseNonNegativeInt(process.env.CI_HTTP_RETRIES, DEFAULT_RETRIES), + retryDelayMs = parseNonNegativeInt(process.env.CI_HTTP_RETRY_DELAY_MS, DEFAULT_RETRY_DELAY_MS), + maxRetryDelayMs = parseNonNegativeInt(process.env.CI_HTTP_MAX_RETRY_DELAY_MS, DEFAULT_MAX_RETRY_DELAY_MS), + retryStatuses, + } = args; + const retryableStatuses = retryStatuses ? new Set(retryStatuses) : DEFAULT_RETRY_STATUSES; + const bigIntPath = body ? findBigIntPath(body) : null; + if (bigIntPath) { + throw new Error( + `requestJson body contains non-JSON BigInt at ${bigIntPath}; convert diagnostics to strings before sending the request`, + ); + } + + let attempt = 0; + let lastError: unknown = null; + + while (attempt <= retries) { + attempt += 1; + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeoutMs); + + try { + const response = await fetch(url, { + method, + headers: { + ...(body ? { "content-type": "application/json" } : {}), + ...(token ? { authorization: `Bearer ${token}` } : {}), + }, + body: body ? JSON.stringify(body) : undefined, + signal: controller.signal, + }); + + const data = (await response.json()) as T; + clearTimeout(timer); + if (attempt <= retries && retryableStatuses.has(response.status)) { + await sleep( + getRetryDelayMs({ + attempt, + retryDelayMs, + maxRetryDelayMs, + retryAfterMs: getRetryAfterMs(response.headers.get("retry-after")), + }), + ); + continue; + } + return { status: response.status, data }; + } catch (error) { + clearTimeout(timer); + lastError = error; + if (attempt <= retries) { + await sleep(getRetryDelayMs({ attempt, retryDelayMs, maxRetryDelayMs })); + } + } + } + + throw new Error(`HTTP request failed after ${retries + 1} attempt(s): ${String(lastError)}`); +} diff --git a/scripts/ci/framework/markdown.ts b/scripts/ci/framework/markdown.ts new file mode 100644 index 00000000..a13880fb --- /dev/null +++ b/scripts/ci/framework/markdown.ts @@ -0,0 +1,101 @@ +import { mkdir, writeFile } from "fs/promises"; +import { dirname } from "path"; +import type { RunReport, ScenarioReport, StepReport } from "./types"; + +function lovelaceToAda(lovelace: string): string { + return (Number(BigInt(lovelace)) / 1_000_000).toFixed(2); +} + +function fmtMs(ms: number): string { + if (ms < 1000) return `${ms}ms`; + return `${(ms / 1000).toFixed(1)}s`; +} + +function escapeCell(s: string): string { + // Escape both `\` and `|` in a single pass with a character class so the + // replacement can't be mis-ordered or partially applied — CodeQL's + // js/incomplete-sanitization rule flagged the previous chained version. + // Backslash is added in the replacement, so we capture and prefix in + // one regex (no second pass that could double-escape). + return s.replace(/[\\|]/g, "\\$&").replace(/[\r\n]+/g, " "); +} + +function renderSteps(steps: StepReport[]): string { + const rows: string[] = []; + rows.push("| Step | ms | Message |"); + rows.push("|------|----|---------|"); + + const errorBlocks: string[] = []; + + for (const step of steps) { + const icon = step.status === "passed" ? "✅" : "❌"; + const msg = escapeCell(step.status === "failed" ? (step.error ?? step.message) : step.message); + rows.push(`| ${icon} ${step.id} | ${step.durationMs} | ${msg} |`); + + if (step.status === "failed" && step.artifacts && Object.keys(step.artifacts).length > 0) { + errorBlocks.push(`**\`${step.id}\` artifacts:**`); + errorBlocks.push("```json"); + errorBlocks.push(JSON.stringify(step.artifacts, null, 2)); + errorBlocks.push("```"); + } + } + + if (errorBlocks.length > 0) { + rows.push("", ...errorBlocks); + } + + return rows.join("\n"); +} + +function renderScenario(scenario: ScenarioReport): string { + const icon = scenario.status === "passed" ? "✅" : "❌"; + return [`### ${icon} ${scenario.id} — ${fmtMs(scenario.durationMs)}`, "", renderSteps(scenario.steps)].join("\n"); +} + +export async function writeMarkdownReport(report: RunReport, outputPath: string): Promise { + const lines: string[] = []; + const icon = report.status === "passed" ? "✅" : "❌"; + + lines.push(`# CI Route-Chain: ${report.status.toUpperCase()} ${icon}`, ""); + + const network = report.contextSummary.networkId === 0 ? "preprod" : "mainnet"; + lines.push( + `**Run:** ${report.createdAt} · **Duration:** ${fmtMs(report.durationMs)} · **Network:** ${network} · **Wallets:** ${report.contextSummary.walletTypes.join(", ")}`, + "", + ); + + // Wallet balances + lines.push("## Wallet Balances", ""); + if (report.walletBalanceSummary.error) { + lines.push(`> Balance collection failed: ${report.walletBalanceSummary.error}`); + } else { + lines.push("| Type | UTxOs | ADA |", "|------|-------|-----|"); + for (const [type, entry] of Object.entries(report.walletBalanceSummary.byWalletType)) { + if (!entry) continue; + const ada = lovelaceToAda(entry.lovelace); + const nativeCount = Object.keys(entry.assets).filter((k) => k !== "lovelace").length; + const assetNote = nativeCount > 0 ? ` +${nativeCount} assets` : ""; + lines.push(`| ${type} | ${entry.utxoCount} | ${ada}${assetNote} |`); + } + } + lines.push(""); + + // Scenario summary + lines.push("## Scenario Summary", ""); + lines.push("| Scenario | Status | Steps | Duration |", "|----------|--------|-------|----------|"); + for (const scenario of report.scenarios) { + const sIcon = scenario.status === "passed" ? "✅" : "❌"; + const passed = scenario.steps.filter((s) => s.status === "passed").length; + lines.push(`| ${scenario.id} | ${sIcon} | ${passed}/${scenario.steps.length} | ${fmtMs(scenario.durationMs)} |`); + } + lines.push(""); + + // Step details + lines.push("## Steps", ""); + for (const scenario of report.scenarios) { + lines.push(renderScenario(scenario), ""); + } + + await mkdir(dirname(outputPath), { recursive: true }); + await writeFile(outputPath, lines.join("\n"), "utf8"); +} diff --git a/scripts/ci/framework/mnemonic.ts b/scripts/ci/framework/mnemonic.ts new file mode 100644 index 00000000..f63581d2 --- /dev/null +++ b/scripts/ci/framework/mnemonic.ts @@ -0,0 +1,6 @@ +export function parseMnemonic(value: string): string[] { + return value + .trim() + .split(/\s+/) + .filter(Boolean); +} diff --git a/scripts/ci/framework/preprod.ts b/scripts/ci/framework/preprod.ts new file mode 100644 index 00000000..21740bd8 --- /dev/null +++ b/scripts/ci/framework/preprod.ts @@ -0,0 +1,33 @@ +import type { CIBootstrapContext } from "./types"; + +export function isTestnetAddress(address: string): boolean { + return address.startsWith("addr_test") || address.startsWith("stake_test"); +} + +export function assertPreprodContext(context: CIBootstrapContext): void { + const configuredNetworkId = Number(process.env.CI_NETWORK_ID ?? "0") === 1 ? 1 : 0; + if (configuredNetworkId !== 0) { + throw new Error( + `CI route-chain is configured for preprod only. CI_NETWORK_ID must be 0, got ${configuredNetworkId}`, + ); + } + if (context.networkId !== 0) { + throw new Error( + `Bootstrap context is not preprod. Expected context.networkId=0, got ${context.networkId}`, + ); + } + + const addresses = [ + ...context.signerAddresses, + ...context.bots.map((bot) => bot.paymentAddress), + ...context.wallets.map((wallet) => wallet.walletAddress), + ...context.wallets.flatMap((wallet) => wallet.signerAddresses), + ].map((address) => address.trim()); + + const nonTestnet = Array.from(new Set(addresses.filter((address) => !isTestnetAddress(address)))); + if (nonTestnet.length) { + throw new Error( + `Preprod invariant failed: found non-testnet address(es): ${nonTestnet.slice(0, 5).join(", ")}`, + ); + } +} diff --git a/scripts/ci/framework/redact.ts b/scripts/ci/framework/redact.ts new file mode 100644 index 00000000..9f69156a --- /dev/null +++ b/scripts/ci/framework/redact.ts @@ -0,0 +1,51 @@ +function shouldRedactKey(key: string): boolean { + const k = key.toLowerCase(); + const sensitiveKeyParts = [ + "token", + "secret", + "authorization", + "api_key", + "apikey", + "mnemonic", + "privatekey", + "private_key", + "signingkey", + "signing_key", + "seed", + "xprv", + "ed25519e_sk", + ]; + + if (sensitiveKeyParts.some((part) => k.includes(part))) { + return true; + } + + return ( + (k.includes("private") && k.includes("key")) || + (k.includes("signing") && k.includes("key")) + ); +} + +export function redactForLogs(value: unknown): unknown { + if (Array.isArray(value)) { + return value.map((item) => redactForLogs(item)); + } + if (!value || typeof value !== "object") { + return value; + } + + const obj = value as Record; + const out: Record = {}; + for (const [key, fieldValue] of Object.entries(obj)) { + out[key] = shouldRedactKey(key) ? "[REDACTED]" : redactForLogs(fieldValue); + } + return out; +} + +export function stringifyRedacted(value: unknown): string { + try { + return JSON.stringify(redactForLogs(value)); + } catch { + return String(value); + } +} diff --git a/scripts/ci/framework/runner.ts b/scripts/ci/framework/runner.ts new file mode 100644 index 00000000..7e665c0a --- /dev/null +++ b/scripts/ci/framework/runner.ts @@ -0,0 +1,98 @@ +import { mkdir, writeFile } from "fs/promises"; +import { dirname } from "path"; +import type { CIBootstrapContext, RunReport, Scenario, ScenarioReport, StepReport } from "./types"; +import { collectWalletBalanceSummary } from "./walletBalances"; + +function now(): number { + return Date.now(); +} + +export async function runScenarios(args: { + scenarios: Scenario[]; + ctx: CIBootstrapContext; + continueOnNonCriticalFailure?: boolean; +}): Promise { + const start = now(); + const { scenarios, ctx, continueOnNonCriticalFailure = true } = args; + const scenarioReports: ScenarioReport[] = []; + let overallFailed = false; + + for (const scenario of scenarios) { + const scenarioStart = now(); + const steps: StepReport[] = []; + let scenarioFailed = false; + + for (const step of scenario.steps) { + const stepStart = now(); + const severity = step.severity ?? "critical"; + try { + const result = await step.execute(ctx); + steps.push({ + id: step.id, + description: step.description, + status: "passed", + severity, + message: result.message, + artifacts: result.artifacts, + durationMs: now() - stepStart, + }); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + steps.push({ + id: step.id, + description: step.description, + status: "failed", + severity, + message: "Step failed", + durationMs: now() - stepStart, + error: errorMessage, + }); + scenarioFailed = true; + overallFailed = true; + if (severity === "critical") { + break; + } + if (!continueOnNonCriticalFailure) { + break; + } + } + } + + scenarioReports.push({ + id: scenario.id, + description: scenario.description, + status: scenarioFailed ? "failed" : "passed", + durationMs: now() - scenarioStart, + steps, + }); + + if (scenarioFailed) { + const hitCritical = steps.some((s) => s.status === "failed" && s.severity === "critical"); + if (hitCritical) { + break; + } + } + } + + const walletBalanceSummary = await collectWalletBalanceSummary(ctx); + + return { + createdAt: new Date().toISOString(), + scenarioIds: scenarios.map((s) => s.id), + status: overallFailed ? "failed" : "passed", + durationMs: now() - start, + contextSummary: { + apiBaseUrl: ctx.apiBaseUrl, + networkId: ctx.networkId, + walletCount: ctx.wallets.length, + walletTypes: ctx.walletTypes, + }, + walletBalanceSummary, + scenarios: scenarioReports, + }; +} + +export async function writeRunReport(report: RunReport, outputPath: string): Promise { + await mkdir(dirname(outputPath), { recursive: true }); + await writeFile(outputPath, JSON.stringify(report, null, 2), "utf8"); +} diff --git a/scripts/ci/framework/types.ts b/scripts/ci/framework/types.ts new file mode 100644 index 00000000..909ee4f7 --- /dev/null +++ b/scripts/ci/framework/types.ts @@ -0,0 +1,110 @@ +export type CIWalletType = "legacy" | "hierarchical" | "sdk"; + +export type CIWalletContext = { + type: CIWalletType; + walletId: string; + walletAddress: string; + transactionId?: string; + signerAddresses: string[]; +}; + +export type CIBotContext = { + id: string; + paymentAddress: string; + botKeyId: string; + botId?: string; +}; + +export type CIBootstrapContext = { + schemaVersion: 3; + createdAt: string; + apiBaseUrl: string; + networkId: 0 | 1; + walletTypes: CIWalletType[]; + wallets: CIWalletContext[]; + bots: CIBotContext[]; + defaultBotId?: string; + walletId?: string; + walletAddress?: string; + signerAddresses: string[]; + transactionId?: string; + /** Per-signer stake (reward) addresses aligned with signerAddresses. */ + signerStakeAddresses: string[]; + /** Multisig reward address for the SDK wallet (from MultisigWallet.getStakeAddress); present when an SDK wallet was bootstrapped. */ + sdkStakeAddress?: string; + /** Optional preprod stake pool id (hex) for future delegate scenarios. */ + stakePoolIdHex?: string; +}; + +export type StepSeverity = "critical" | "non-critical"; + +export type StepRunResult = { + message: string; + artifacts?: Record; +}; + +export type RouteStep = { + id: string; + description: string; + severity?: StepSeverity; + execute: (ctx: CIBootstrapContext) => Promise; +}; + +export type Scenario = { + id: string; + description: string; + steps: RouteStep[]; +}; + +export type StepReport = { + id: string; + description: string; + status: "passed" | "failed" | "skipped"; + severity: StepSeverity; + message: string; + durationMs: number; + artifacts?: Record; + error?: string; +}; + +export type ScenarioReport = { + id: string; + description: string; + status: "passed" | "failed"; + durationMs: number; + steps: StepReport[]; +}; + +export type CIWalletBalanceEntry = { + walletType: CIWalletType; + walletId: string; + walletAddress: string; + utxoCount: number; + lovelace: string; + assets: Record; + capturedAt: string; + networkId: 0 | 1; +}; + +export type CIWalletBalanceSummary = { + capturedAt: string; + networkId: 0 | 1; + byWalletType: Partial>; + byWalletId: Record; + error?: string; +}; + +export type RunReport = { + createdAt: string; + scenarioIds: string[]; + status: "passed" | "failed"; + durationMs: number; + contextSummary: { + apiBaseUrl: string; + networkId: 0 | 1; + walletCount: number; + walletTypes: CIWalletType[]; + }; + walletBalanceSummary: CIWalletBalanceSummary; + scenarios: ScenarioReport[]; +}; diff --git a/scripts/ci/framework/walletAuth.ts b/scripts/ci/framework/walletAuth.ts new file mode 100644 index 00000000..bbdee880 --- /dev/null +++ b/scripts/ci/framework/walletAuth.ts @@ -0,0 +1,73 @@ +import type { CIBootstrapContext } from "./types"; +import { requestJson } from "./http"; +import { stringifyRedacted } from "./redact"; +import { parseMnemonic } from "./mnemonic"; + +export async function deriveSignerFromMnemonic(args: { + ctx: CIBootstrapContext; + mnemonic: string; +}): Promise<{ + signerAddress: string; + signData: (payload: string) => Promise<{ key: string; signature: string }>; +}> { + const { MeshWallet } = await import("@meshsdk/core"); + const wallet = new MeshWallet({ + networkId: args.ctx.networkId, + key: { type: "mnemonic", words: parseMnemonic(args.mnemonic) }, + }); + await wallet.init(); + const signerAddress = await wallet.getChangeAddress(); + return { + signerAddress, + signData: async (payload: string) => { + const signature = await wallet.signData(payload, signerAddress); + return { + key: signature.key, + signature: signature.signature, + }; + }, + }; +} + +export async function authenticateSignerWithMnemonic(args: { + ctx: CIBootstrapContext; + mnemonic: string; +}): Promise<{ + token: string; + signerAddress: string; + nonce: string; +}> { + const signer = await deriveSignerFromMnemonic(args); + const nonceResponse = await requestJson<{ nonce?: string; error?: string }>({ + url: `${args.ctx.apiBaseUrl}/api/v1/getNonce?address=${encodeURIComponent(signer.signerAddress)}`, + method: "GET", + }); + if (nonceResponse.status !== 200 || typeof nonceResponse.data?.nonce !== "string") { + throw new Error( + `getNonce failed (${nonceResponse.status}): ${stringifyRedacted(nonceResponse.data)}`, + ); + } + + const signed = await signer.signData(nonceResponse.data.nonce); + const authResponse = await requestJson<{ token?: string; error?: string }>({ + url: `${args.ctx.apiBaseUrl}/api/v1/authSigner`, + method: "POST", + body: { + address: signer.signerAddress, + signature: signed.signature, + key: signed.key, + }, + }); + if (authResponse.status !== 200 || typeof authResponse.data?.token !== "string") { + throw new Error( + `authSigner failed (${authResponse.status}): ${stringifyRedacted(authResponse.data)}`, + ); + } + + return { + token: authResponse.data.token, + signerAddress: signer.signerAddress, + nonce: nonceResponse.data.nonce, + }; +} + diff --git a/scripts/ci/framework/walletBalances.ts b/scripts/ci/framework/walletBalances.ts new file mode 100644 index 00000000..92435603 --- /dev/null +++ b/scripts/ci/framework/walletBalances.ts @@ -0,0 +1,102 @@ +import type { UTxO } from "@meshsdk/core"; +import type { + CIBootstrapContext, + CIWalletBalanceEntry, + CIWalletBalanceSummary, + CIWalletType, +} from "./types"; + +type BigIntMap = Map; + +function getBlockfrostApiKey(networkId: 0 | 1): string { + if (networkId === 0) { + const preprod = process.env.CI_BLOCKFROST_PREPROD_API_KEY?.trim(); + if (!preprod) { + throw new Error("CI_BLOCKFROST_PREPROD_API_KEY is required for wallet balance summary"); + } + return preprod; + } + + const mainnet = process.env.CI_BLOCKFROST_MAINNET_API_KEY?.trim(); + if (!mainnet) { + throw new Error("CI_BLOCKFROST_MAINNET_API_KEY is required for wallet balance summary"); + } + return mainnet; +} + +function addAssetQuantity(map: BigIntMap, unit: string, quantityRaw: string): void { + const quantity = BigInt(quantityRaw); + map.set(unit, (map.get(unit) ?? 0n) + quantity); +} + +function sumUtxoAssets(utxos: UTxO[]): BigIntMap { + const totals: BigIntMap = new Map(); + for (const utxo of utxos) { + for (const asset of utxo.output.amount ?? []) { + if (!asset?.unit || asset.quantity === undefined || asset.quantity === null) { + continue; + } + addAssetQuantity(totals, asset.unit, String(asset.quantity)); + } + } + return totals; +} + +function toAssetRecord(map: BigIntMap): Record { + return Object.fromEntries( + Array.from(map.entries()).map(([unit, quantity]) => [unit, quantity.toString()]), + ); +} + +function emptySummary(networkId: 0 | 1, error?: string): CIWalletBalanceSummary { + return { + capturedAt: new Date().toISOString(), + networkId, + byWalletType: {}, + byWalletId: {}, + ...(error ? { error } : {}), + }; +} + +export async function collectWalletBalanceSummary( + ctx: CIBootstrapContext, +): Promise { + try { + const apiKey = getBlockfrostApiKey(ctx.networkId); + const { BlockfrostProvider } = await import("@meshsdk/core"); + const provider = new BlockfrostProvider(apiKey); + const capturedAt = new Date().toISOString(); + + const byWalletType: Partial> = {}; + const byWalletId: CIWalletBalanceSummary["byWalletId"] = {}; + + for (const wallet of ctx.wallets) { + const utxos = await provider.fetchAddressUTxOs(wallet.walletAddress); + const totals = sumUtxoAssets(utxos); + const assets = toAssetRecord(totals); + const entry: CIWalletBalanceEntry = { + walletType: wallet.type, + walletId: wallet.walletId, + walletAddress: wallet.walletAddress, + utxoCount: utxos.length, + lovelace: (totals.get("lovelace") ?? 0n).toString(), + assets, + capturedAt, + networkId: ctx.networkId, + }; + + byWalletType[wallet.type] = entry; + byWalletId[wallet.walletId] = entry; + } + + return { + capturedAt, + networkId: ctx.networkId, + byWalletType, + byWalletId, + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + return emptySummary(ctx.networkId, message); + } +} diff --git a/scripts/ci/framework/walletType.ts b/scripts/ci/framework/walletType.ts new file mode 100644 index 00000000..7fcc3f5d --- /dev/null +++ b/scripts/ci/framework/walletType.ts @@ -0,0 +1,8 @@ +import type { CIWalletType } from "./types"; + +/** Normalize wallet type from env/CLI strings (legacy default). */ +export function normalizeWalletTypeFromLabel(value: string): CIWalletType { + const v = value.trim().toLowerCase(); + if (v === "hierarchical" || v === "sdk") return v; + return "legacy"; +} diff --git a/scripts/ci/scenarios/flows/certificateSigningFlow.ts b/scripts/ci/scenarios/flows/certificateSigningFlow.ts new file mode 100644 index 00000000..b6722c66 --- /dev/null +++ b/scripts/ci/scenarios/flows/certificateSigningFlow.ts @@ -0,0 +1,232 @@ +import type { CIBootstrapContext, CIWalletType } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getBotForSignerIndex } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; +import { parseMnemonic } from "../../framework/mnemonic"; +import { + SIGN_TRANSACTION_REQUEST_OPTIONS, + selectPendingTransactionForSigning, + type PendingTransactionForSigning, +} from "./signingFlow"; + +/** + * Signs a pending certificate transaction using BOTH the signer's payment key + * (required for the spending native script) and, when available, their stake key + * (required for the staking certificate native script). + * + * Both witnesses are submitted in a single signTransaction call so that the + * address-already-signed guard is not hit on a second call. + * + * This is needed for botStakeCertificate transactions where the certificate + * script is built from role-2 (stake) key hashes that differ from the payment + * key hashes used by the spending script. + */ +export async function runStakeCertSigningFlow(args: { + ctx: CIBootstrapContext; + mnemonic: string; + signerIndex?: number; + signBroadcast?: boolean; + preferredTransactionId?: string; + requireBroadcastSuccess?: boolean; +}): Promise<{ + walletType: CIWalletType; + walletId: string; + transactionId: string; + signerAddress: string; + status: number; + submitted?: boolean; + submissionError?: string; + stakeWitnessIncluded: boolean; +}> { + const { ctx, mnemonic } = args; + const signerIndex = args.signerIndex ?? 1; + const shouldBroadcast = args.signBroadcast ?? true; + const requireBroadcastSuccess = args.requireBroadcastSuccess ?? true; + + // Staking cert scenarios always target the SDK wallet. + const targetWalletType: CIWalletType = "sdk"; + const selectedWallet = ctx.wallets.find((w) => w.type === targetWalletType); + if (!selectedWallet) { + throw new Error(`Unable to find wallet context for type ${targetWalletType}`); + } + + const { bot: signerBot, signerAddress: signAddress } = getBotForSignerIndex({ + ctx, + wallet: selectedWallet, + signerIndex, + }); + + const [{ MeshWallet, resolvePaymentKeyHash, resolveStakeKeyHash }, { csl, calculateTxHash }] = await Promise.all([ + import("@meshsdk/core"), + import("@meshsdk/core-csl"), + ]); + + const signerWallet = new MeshWallet({ + networkId: ctx.networkId, + key: { type: "mnemonic", words: parseMnemonic(mnemonic) }, + }); + await signerWallet.init(); + const signerAddress = await signerWallet.getChangeAddress(); + if (signerAddress !== signAddress) { + throw new Error( + `Mnemonic does not derive signer address index ${signerIndex} from context`, + ); + } + + const signerToken = await authenticateBot({ ctx, bot: signerBot }); + + const pendingResponse = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(selectedWallet.walletId)}&address=${encodeURIComponent(signerAddress)}`, + method: "GET", + token: signerToken, + }); + if (pendingResponse.status !== 200 || !Array.isArray(pendingResponse.data)) { + throw new Error( + `pendingTransactions lookup failed (${pendingResponse.status}): ${stringifyRedacted(pendingResponse.data)}`, + ); + } + if (!pendingResponse.data.length) { + throw new Error("No pending transactions to sign for sdk wallet"); + } + + const tx = selectPendingTransactionForSigning(pendingResponse.data, args.preferredTransactionId); + + const signedPayloadHex = await signerWallet.signTx(tx.txCbor, true); + + // Parse the full vkey witness set from the signed payload. + let vkeys: ReturnType | null = null; + try { + const signedTx = csl.Transaction.from_hex(signedPayloadHex); + vkeys = signedTx.witness_set().vkeys() ?? csl.Vkeywitnesses.new(); + } catch { + const witnessSet = csl.TransactionWitnessSet.from_hex(signedPayloadHex); + vkeys = witnessSet.vkeys() ?? csl.Vkeywitnesses.new(); + } + if (!vkeys || vkeys.len() === 0) { + throw new Error("No vkey witnesses found in signed payload"); + } + + // ── Extract payment key witness ────────────────────────────────────────── + const paymentKeyHash = resolvePaymentKeyHash(signerAddress).toLowerCase(); + let paymentVkey: typeof vkeys extends { get: (i: number) => infer V } ? V : never; + let foundPayment = false; + for (let i = 0; i < vkeys.len(); i++) { + const candidate = vkeys.get(i); + const kh = Buffer.from(candidate.vkey().public_key().hash().to_bytes()).toString("hex").toLowerCase(); + if (kh === paymentKeyHash) { + paymentVkey = candidate; + foundPayment = true; + break; + } + } + if (!foundPayment) { + // Fall back to first witness if payment key not found by hash match. + paymentVkey = vkeys.get(0); + } + + const keyHex = paymentVkey!.vkey().public_key().to_hex().toLowerCase(); + const signatureHex = paymentVkey!.signature().to_hex().toLowerCase(); + + // ── Extract stake key witness ──────────────────────────────────────────── + // MeshWallet.signTx produces only payment key witnesses for native script + // spending inputs. Staking certificate native scripts require role-2 (stake) + // key witnesses, derived via BIP32 path m/1852'/1815'/0'/2/0 and signed + // against the transaction hash — the same path used by bootstrap.ts. + const signerStakeAddr = ctx.signerStakeAddresses[signerIndex]; + let stakeKeyHex: string | undefined; + let stakeSignatureHex: string | undefined; + + if (signerStakeAddr) { + try { + const expectedStakeHash = resolveStakeKeyHash(signerStakeAddr).toLowerCase(); + + // Primary: check if the regular signing already included the stake witness + // (MeshWallet may sign with all required keys in some versions). + for (let i = 0; i < vkeys.len(); i++) { + const candidate = vkeys.get(i); + const kh = Buffer.from(candidate.vkey().public_key().hash().to_bytes()).toString("hex").toLowerCase(); + if (kh === expectedStakeHash) { + stakeKeyHex = candidate.vkey().public_key().to_hex().toLowerCase(); + stakeSignatureHex = candidate.signature().to_hex().toLowerCase(); + break; + } + } + + // Fallback: derive stake key directly from mnemonic via BIP32 and sign + // the tx hash manually. This is reliable regardless of wallet version. + if (!stakeKeyHex) { + const { mnemonicToEntropy } = await import("bip39"); + const entropy = mnemonicToEntropy(parseMnemonic(mnemonic).join(" ")); + const rootKey = csl.Bip32PrivateKey.from_bip39_entropy( + Buffer.from(entropy, "hex"), + Buffer.from(""), + ); + const stakeRawKey = rootKey + .derive(2147483648 + 1852) + .derive(2147483648 + 1815) + .derive(2147483648 + 0) + .derive(2) + .derive(0) + .to_raw_key(); + const stakePubKey = stakeRawKey.to_public(); + const derivedHash = Buffer.from(stakePubKey.hash().to_bytes()).toString("hex").toLowerCase(); + if (derivedHash === expectedStakeHash) { + const txHashBytes = Buffer.from(calculateTxHash(tx.txCbor), "hex"); + stakeKeyHex = stakePubKey.to_hex().toLowerCase(); + stakeSignatureHex = Buffer.from(stakeRawKey.sign(txHashBytes).to_bytes()).toString("hex").toLowerCase(); + } + } + } catch { + // Cannot produce stake witness — broadcast may fail without it + } + } + + const stakeWitnessIncluded = !!(stakeKeyHex && stakeSignatureHex); + + // ── Submit to signTransaction ──────────────────────────────────────────── + const signBody: Record = { + walletId: selectedWallet.walletId, + transactionId: tx.id, + address: signerAddress, + signature: signatureHex, + key: keyHex, + broadcast: shouldBroadcast, + }; + if (stakeWitnessIncluded) { + signBody.stakeKey = stakeKeyHex; + signBody.stakeSignature = stakeSignatureHex; + } + + const signResponse = await requestJson< + { submitted?: boolean; txHash?: string; error?: string; submissionError?: string } + >({ + url: `${ctx.apiBaseUrl}/api/v1/signTransaction`, + method: "POST", + token: signerToken, + ...SIGN_TRANSACTION_REQUEST_OPTIONS, + body: signBody, + }); + + if (signResponse.status !== 200 && signResponse.status !== 502) { + throw new Error( + `signTransaction failed (${signResponse.status}): ${stringifyRedacted(signResponse.data)}`, + ); + } + if (requireBroadcastSuccess && signResponse.status === 502) { + throw new Error( + `signTransaction broadcast failed (${signResponse.status}): ${stringifyRedacted(signResponse.data)}`, + ); + } + + return { + walletType: selectedWallet.type, + walletId: selectedWallet.walletId, + transactionId: tx.id, + signerAddress, + status: signResponse.status, + submitted: signResponse.data?.submitted, + submissionError: signResponse.data?.submissionError, + stakeWitnessIncluded, + }; +} diff --git a/scripts/ci/scenarios/flows/signingFlow.ts b/scripts/ci/scenarios/flows/signingFlow.ts new file mode 100644 index 00000000..f52e5630 --- /dev/null +++ b/scripts/ci/scenarios/flows/signingFlow.ts @@ -0,0 +1,180 @@ +import type { CIBootstrapContext, CIWalletType } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getBotForSignerIndex } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; +import { parseMnemonic } from "../../framework/mnemonic"; +import { normalizeWalletTypeFromLabel } from "../../framework/walletType"; + +export type PendingTransactionForSigning = { id: string; txCbor?: string }; + +// signTransaction mutates the pending tx before broadcast. Retrying a 502 can +// turn the useful submission error into a duplicate-signature 409. +export const SIGN_TRANSACTION_REQUEST_OPTIONS = { + retries: 0, +} as const; + +export function selectPendingTransactionForSigning( + pendingTransactions: PendingTransactionForSigning[], + preferredTransactionId?: string, +): PendingTransactionForSigning & { txCbor: string } { + if (preferredTransactionId) { + const tx = pendingTransactions.find((p) => p.id === preferredTransactionId); + if (!tx) { + throw new Error(`Preferred pending transaction ${preferredTransactionId} was not found`); + } + if (!tx.txCbor) { + throw new Error(`Preferred pending transaction ${preferredTransactionId} does not include txCbor`); + } + return { ...tx, txCbor: tx.txCbor }; + } + + const tx = pendingTransactions.find((p) => typeof p.txCbor === "string" && p.txCbor.length > 0); + if (!tx) { + throw new Error("Pending transactions exist but none include txCbor"); + } + const txCbor = tx.txCbor; + if (!txCbor) { + throw new Error("Pending transactions exist but none include txCbor"); + } + return { ...tx, txCbor }; +} + +export async function runSigningFlow(args: { + ctx: CIBootstrapContext; + mnemonic: string; + signWalletType?: string; + signerIndex?: number; + signerLabel?: string; + signBroadcast?: boolean; + preferredTransactionId?: string; + requireBroadcastSuccess?: boolean; +}): Promise<{ + walletType: CIWalletType; + walletId: string; + transactionId: string; + signerAddress: string; + status: number; + submitted?: boolean; + txHash?: string; +}> { + const { ctx, mnemonic } = args; + const targetWalletType = normalizeWalletTypeFromLabel(args.signWalletType ?? "legacy"); + const signerIndex = args.signerIndex ?? 1; + const signerLabel = args.signerLabel ?? `signer${signerIndex}`; + const shouldBroadcast = args.signBroadcast ?? true; + const requireBroadcastSuccess = args.requireBroadcastSuccess ?? true; + + const selectedWallet = ctx.wallets.find((w) => w.type === targetWalletType); + if (!selectedWallet) { + throw new Error(`Unable to find wallet context for type ${targetWalletType}`); + } + + const { bot: signerBot, signerAddress: signAddress } = getBotForSignerIndex({ + ctx, + wallet: selectedWallet, + signerIndex, + }); + + const [{ MeshWallet, resolvePaymentKeyHash }, { csl }] = await Promise.all([ + import("@meshsdk/core"), + import("@meshsdk/core-csl"), + ]); + const signerWallet = new MeshWallet({ + networkId: ctx.networkId, + key: { type: "mnemonic", words: parseMnemonic(mnemonic) }, + }); + await signerWallet.init(); + const signerAddress = await signerWallet.getChangeAddress(); + if (signerAddress !== signAddress) { + throw new Error( + `${signerLabel} mnemonic does not derive signer address index ${signerIndex} from context`, + ); + } + + const signerToken = await authenticateBot({ ctx, bot: signerBot }); + + const pendingResponse = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(selectedWallet.walletId)}&address=${encodeURIComponent(signerAddress)}`, + method: "GET", + token: signerToken, + }); + if (pendingResponse.status !== 200 || !Array.isArray(pendingResponse.data)) { + throw new Error( + `pendingTransactions lookup failed (${pendingResponse.status}): ${stringifyRedacted(pendingResponse.data)}`, + ); + } + if (!pendingResponse.data.length) { + throw new Error(`No pending transactions to sign for wallet type ${targetWalletType}`); + } + + const tx = selectPendingTransactionForSigning(pendingResponse.data, args.preferredTransactionId); + + const signedPayloadHex = await signerWallet.signTx(tx.txCbor, true); + + let vkeys: any = null; + try { + const signedTx = csl.Transaction.from_hex(signedPayloadHex); + vkeys = signedTx.witness_set().vkeys(); + } catch { + const witnessSet = csl.TransactionWitnessSet.from_hex(signedPayloadHex); + vkeys = witnessSet.vkeys(); + } + + if (!vkeys || vkeys.len() === 0) { + throw new Error("No vkey witness found in signed payload"); + } + + const addressKeyHash = resolvePaymentKeyHash(signerAddress).toLowerCase(); + let selected = vkeys.get(0); + for (let i = 0; i < vkeys.len(); i++) { + const candidate = vkeys.get(i); + const keyHash = Buffer.from(candidate.vkey().public_key().hash().to_bytes()) + .toString("hex") + .toLowerCase(); + if (keyHash === addressKeyHash) { + selected = candidate; + break; + } + } + + const keyHex = selected.vkey().public_key().to_hex().toLowerCase(); + const signatureHex = selected.signature().to_hex().toLowerCase(); + const signResponse = await requestJson< + { submitted?: boolean; txHash?: string; error?: string; submissionError?: string } + >({ + url: `${ctx.apiBaseUrl}/api/v1/signTransaction`, + method: "POST", + token: signerToken, + ...SIGN_TRANSACTION_REQUEST_OPTIONS, + body: { + walletId: selectedWallet.walletId, + transactionId: tx.id, + address: signerAddress, + signature: signatureHex, + key: keyHex, + broadcast: shouldBroadcast, + }, + }); + + if (signResponse.status !== 200 && signResponse.status !== 502) { + throw new Error( + `signTransaction failed (${signResponse.status}): ${stringifyRedacted(signResponse.data)}`, + ); + } + if (requireBroadcastSuccess && signResponse.status === 502) { + throw new Error( + `signTransaction broadcast failed (${signResponse.status}): ${stringifyRedacted(signResponse.data)}`, + ); + } + + return { + walletType: selectedWallet.type, + walletId: selectedWallet.walletId, + transactionId: tx.id, + signerAddress, + status: signResponse.status, + submitted: signResponse.data?.submitted, + txHash: signResponse.data?.txHash, + }; +} diff --git a/scripts/ci/scenarios/flows/transferFlow.ts b/scripts/ci/scenarios/flows/transferFlow.ts new file mode 100644 index 00000000..5790dff8 --- /dev/null +++ b/scripts/ci/scenarios/flows/transferFlow.ts @@ -0,0 +1,239 @@ +import type { CIBootstrapContext, CIWalletType } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; +import { parseMnemonic } from "../../framework/mnemonic"; +import { normalizeWalletTypeFromLabel } from "../../framework/walletType"; +import { isTestnetAddress } from "../../framework/preprod"; +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); + +type TransferSeedResult = { + fromWalletType: CIWalletType; + toWalletType: CIWalletType; + fromWalletId: string; + toWalletId: string; + transferFromAddress: string; + transferToAddress: string; + transferAmountLovelace: string; + transactionId: string; +}; + +type UTxOAmount = { + unit: string; + quantity: string; +}; + +type ScriptUtxo = { + input: { + txHash: string; + outputIndex: number; + }; + output: { + address: string; + amount: UTxOAmount[]; + }; +}; + +function parseLovelace(amounts: UTxOAmount[]): bigint { + const lovelace = amounts.find((asset) => asset.unit === "lovelace")?.quantity ?? "0"; + try { + return BigInt(lovelace); + } catch { + return 0n; + } +} + +async function loadScriptCbor(walletId: string): Promise { + const wallet = await prisma.wallet.findUnique({ + where: { id: walletId }, + select: { scriptCbor: true }, + }); + const scriptCbor = wallet?.scriptCbor?.trim(); + if (!scriptCbor) { + throw new Error(`Wallet ${walletId} is missing scriptCbor; cannot build multisig input transaction`); + } + return scriptCbor; +} + +export async function seedRealTransferTransaction(args: { + ctx: CIBootstrapContext; + fromMnemonic: string; + fromWalletType: string; + toWalletType: string; + transferLovelace?: string; +}): Promise { + const { ctx } = args; + const defaultBot = getDefaultBot(ctx); + const defaultBotToken = await authenticateBot({ ctx, bot: defaultBot }); + const fromWalletType = normalizeWalletTypeFromLabel(args.fromWalletType); + const toWalletType = normalizeWalletTypeFromLabel(args.toWalletType); + const fromWallet = ctx.wallets.find((w) => w.type === fromWalletType); + if (!fromWallet) { + throw new Error(`Unable to find source wallet context for type ${fromWalletType}`); + } + const toWallet = ctx.wallets.find((w) => w.type === toWalletType); + if (!toWallet) { + throw new Error(`Unable to find destination wallet context for type ${toWalletType}`); + } + + if (fromWallet.walletId === toWallet.walletId) { + throw new Error(`Source and destination wallets must differ for transfer leg ${fromWalletType}`); + } + + const transferToAddress = toWallet.walletAddress; + if (!transferToAddress) { + throw new Error(`Destination wallet ${toWallet.walletId} is missing walletAddress`); + } + const transferFromAddress = fromWallet.walletAddress; + if (!transferFromAddress) { + throw new Error(`Source wallet ${fromWallet.walletId} is missing walletAddress`); + } + + const transferAmountLovelace = (() => { + const raw = (args.transferLovelace ?? process.env.CI_TRANSFER_LOVELACE ?? "2000000").trim(); + const n = Number(raw); + if (!Number.isFinite(n) || n < 1_000_000) { + throw new Error("CI_TRANSFER_LOVELACE must be a number >= 1000000"); + } + return String(Math.trunc(n)); + })(); + + const apiKey = process.env.CI_BLOCKFROST_PREPROD_API_KEY?.trim(); + if (!apiKey) { + throw new Error("CI_BLOCKFROST_PREPROD_API_KEY is required for real transfer scenario"); + } + if (ctx.networkId !== 0) { + throw new Error( + `CI route-chain transfer scenario is preprod-only. Expected networkId=0, received networkId=${ctx.networkId}`, + ); + } + + for (const address of [ + transferFromAddress, + transferToAddress, + ...fromWallet.signerAddresses, + ...toWallet.signerAddresses, + ]) { + if (!isTestnetAddress(address)) { + throw new Error(`Preprod invariant failed: non-testnet address detected: ${address}`); + } + } + + const { MeshWallet, MeshTxBuilder, BlockfrostProvider } = await import("@meshsdk/core"); + const provider = new BlockfrostProvider(apiKey); + const signerWallet = new MeshWallet({ + networkId: ctx.networkId, + key: { type: "mnemonic", words: parseMnemonic(args.fromMnemonic) }, + }); + await signerWallet.init(); + const signerAddress = await signerWallet.getChangeAddress(); + const expectedFromAddress = fromWallet.signerAddresses?.[1]; + if (!expectedFromAddress || signerAddress !== expectedFromAddress) { + throw new Error( + `Transfer mnemonic does not match expected signerAddresses[1] for source wallet ${fromWalletType}`, + ); + } + if (!isTestnetAddress(signerAddress)) { + throw new Error(`Preprod invariant failed: transfer signer is not a testnet address (${signerAddress})`); + } + + const sourceWalletScriptCbor = await loadScriptCbor(fromWallet.walletId); + const freeUtxosResponse = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/freeUtxos?walletId=${encodeURIComponent(fromWallet.walletId)}&address=${encodeURIComponent(defaultBot.paymentAddress)}`, + method: "GET", + token: defaultBotToken, + }); + if (freeUtxosResponse.status !== 200 || !Array.isArray(freeUtxosResponse.data)) { + throw new Error( + `freeUtxos transfer preflight failed (${freeUtxosResponse.status}): ${stringifyRedacted(freeUtxosResponse.data)}`, + ); + } + if (freeUtxosResponse.data.length === 0) { + throw new Error( + `No free UTxOs available for source wallet ${fromWalletType} (${fromWallet.walletId}) at ${transferFromAddress}`, + ); + } + + const availableLovelace = freeUtxosResponse.data.reduce((sum, utxo) => { + return sum + parseLovelace(utxo.output.amount); + }, 0n); + const transferAmount = BigInt(transferAmountLovelace); + const feeBuffer = 1_000_000n; + const minimumRequired = transferAmount + feeBuffer; + if (availableLovelace < minimumRequired) { + throw new Error( + `Insufficient multisig wallet balance for transfer: available=${availableLovelace.toString()} lovelace, required>=${minimumRequired.toString()} (amount=${transferAmountLovelace}, feeBuffer=${feeBuffer.toString()})`, + ); + } + + const txBuilder = new MeshTxBuilder({ + fetcher: provider, + evaluator: provider, + verbose: true, + }); + txBuilder.setNetwork("preprod"); + for (const utxo of freeUtxosResponse.data) { + txBuilder + .txIn( + utxo.input.txHash, + utxo.input.outputIndex, + utxo.output.amount, + utxo.output.address, + ) + .txInScript(sourceWalletScriptCbor); + } + txBuilder.txOut(transferToAddress, [ + { + unit: "lovelace", + quantity: transferAmountLovelace, + }, + ]); + txBuilder.changeAddress(transferFromAddress); + const unsignedTxHex = await txBuilder.complete(); + if (!unsignedTxHex || typeof unsignedTxHex !== "string") { + throw new Error("Failed to build unsigned transfer transaction"); + } + + const addResponse = await requestJson<{ id?: string; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/addTransaction`, + method: "POST", + token: defaultBotToken, + body: { + walletId: fromWallet.walletId, + address: defaultBot.paymentAddress, + txCbor: unsignedTxHex, + txJson: JSON.stringify({ + source: "ci-route-chain", + kind: "real-transfer", + fromWalletType, + toWalletType, + from: transferFromAddress, + to: transferToAddress, + fundingSource: "source-multisig-utxos", + amountLovelace: transferAmountLovelace, + sourceUtxoCount: freeUtxosResponse.data.length, + availableLovelace: availableLovelace.toString(), + }), + description: `CI real transfer route-chain tx (${fromWalletType} -> ${toWalletType})`, + }, + }); + if (addResponse.status !== 201 || !addResponse.data?.id) { + throw new Error( + `addTransaction real-transfer failed (${addResponse.status}): ${stringifyRedacted(addResponse.data)}`, + ); + } + + return { + fromWalletType, + toWalletType, + fromWalletId: fromWallet.walletId, + toWalletId: toWallet.walletId, + transferFromAddress, + transferToAddress, + transferAmountLovelace, + transactionId: addResponse.data.id, + }; +} diff --git a/scripts/ci/scenarios/flows/utxoShapeFlow.ts b/scripts/ci/scenarios/flows/utxoShapeFlow.ts new file mode 100644 index 00000000..d2dc9035 --- /dev/null +++ b/scripts/ci/scenarios/flows/utxoShapeFlow.ts @@ -0,0 +1,309 @@ +import { PrismaClient } from "@prisma/client"; +import type { CIBootstrapContext, CIWalletType } from "../../framework/types"; +import { authenticateBot } from "../../framework/botAuth"; +import { getDefaultBot } from "../../framework/botContext"; +import { boolFromEnv } from "../../framework/env"; +import { requestJson } from "../../framework/http"; +import { parseMnemonic } from "../../framework/mnemonic"; +import { isTestnetAddress } from "../../framework/preprod"; +import { stringifyRedacted } from "../../framework/redact"; +import { + analyzeProxyFullLifecycleUtxoShape, + assertProxyFullLifecyclePreflight, + formatAda, + key, + PROXY_LIFECYCLE_COLLATERAL_SPLIT_LOVELACE, + type ScriptUtxo, + type UtxoRef, + toRef, +} from "../proxyLifecyclePreflight"; +import { runSigningFlow } from "./signingFlow"; +import { getWalletByType } from "../steps/helpers"; + +const prisma = new PrismaClient(); + +type UtxoShapeResult = { + walletType: CIWalletType; + walletId: string; + status: "already-shaped" | "split"; + transactionId?: string; + spentUtxoRefs?: UtxoRef[]; + attempts?: number; + totalLovelace: string; + requiredTotalLovelace: string; + drepSelectableLovelace: string; + keyCollateralCandidates: number; +}; + +async function loadScriptCbor(walletId: string): Promise { + const wallet = await prisma.wallet.findUnique({ + where: { id: walletId }, + select: { scriptCbor: true }, + }); + const scriptCbor = wallet?.scriptCbor?.trim(); + if (!scriptCbor) { + throw new Error(`Wallet ${walletId} is missing scriptCbor; cannot build proxy lifecycle self-split`); + } + return scriptCbor; +} + +async function fetchFreshFreeUtxos(args: { + ctx: CIBootstrapContext; + walletId: string; + token: string; + address: string; +}): Promise { + const response = await requestJson({ + url: `${args.ctx.apiBaseUrl}/api/v1/freeUtxos?walletId=${encodeURIComponent(args.walletId)}&address=${encodeURIComponent(args.address)}&fresh=true`, + method: "GET", + token: args.token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error(`freeUtxos UTxO-shape lookup failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + return response.data; +} + +async function fetchKeyAddressUtxos(args: { + ctx: CIBootstrapContext; + address: string; +}): Promise { + const apiKey = process.env.CI_BLOCKFROST_PREPROD_API_KEY?.trim(); + if (!apiKey) { + throw new Error("CI_BLOCKFROST_PREPROD_API_KEY is required to fetch proxy lifecycle key-address collateral"); + } + if (args.ctx.networkId !== 0) { + throw new Error(`Proxy lifecycle key collateral lookup is preprod-only. Expected networkId=0, received networkId=${args.ctx.networkId}`); + } + + const { BlockfrostProvider } = await import("@meshsdk/core"); + const provider = new BlockfrostProvider(apiKey); + const utxos = await provider.fetchAddressUTxOs(args.address); + return utxos.map((utxo) => ({ + input: utxo.input, + output: utxo.output, + })); +} + +async function pollUntilUtxosConsumed(args: { + ctx: CIBootstrapContext; + walletId: string; + token: string; + address: string; + spentUtxoRefs: UtxoRef[]; + maxRetries?: number; + retryDelayMs?: number; +}): Promise<{ attempts: number }> { + const maxRetries = args.maxRetries ?? 30; + const retryDelayMs = args.retryDelayMs ?? 8000; + const spent = new Set(args.spentUtxoRefs.map(key)); + for (let attempt = 0; attempt < maxRetries; attempt++) { + if (attempt > 0) { + await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); + } + const utxos = await fetchFreshFreeUtxos(args); + if (!utxos.some((utxo) => spent.has(key(toRef(utxo))))) { + return { attempts: attempt + 1 }; + } + } + throw new Error("Timed out waiting for proxy lifecycle self-split inputs to be confirmed"); +} + +function requireProxyShapeEnvironment(ctx: CIBootstrapContext, walletAddress: string, collateralAddress: string): void { + const apiKey = process.env.CI_BLOCKFROST_PREPROD_API_KEY?.trim(); + if (!apiKey) { + throw new Error("CI_BLOCKFROST_PREPROD_API_KEY is required for proxy lifecycle UTxO shaping"); + } + if (ctx.networkId !== 0) { + throw new Error(`Proxy lifecycle UTxO shaping is preprod-only. Expected networkId=0, received networkId=${ctx.networkId}`); + } + if (!isTestnetAddress(walletAddress)) { + throw new Error(`Preprod invariant failed: proxy lifecycle wallet address is not testnet (${walletAddress})`); + } + if (!isTestnetAddress(collateralAddress)) { + throw new Error(`Preprod invariant failed: proxy lifecycle collateral address is not testnet (${collateralAddress})`); + } + for (const envName of ["CI_MNEMONIC_2", "CI_MNEMONIC_3"] as const) { + if (!process.env[envName]?.trim()) { + throw new Error(`${envName} is required for proxy lifecycle UTxO shaping`); + } + parseMnemonic(process.env[envName]!); + } +} + +async function buildSelfSplitTransaction(args: { + walletId: string; + walletAddress: string; + collateralAddress: string; + utxos: ScriptUtxo[]; +}): Promise { + const apiKey = process.env.CI_BLOCKFROST_PREPROD_API_KEY?.trim(); + if (!apiKey) { + throw new Error("CI_BLOCKFROST_PREPROD_API_KEY is required for proxy lifecycle UTxO shaping"); + } + const scriptCbor = await loadScriptCbor(args.walletId); + const { MeshTxBuilder, BlockfrostProvider } = await import("@meshsdk/core"); + const provider = new BlockfrostProvider(apiKey); + const txBuilder = new MeshTxBuilder({ + fetcher: provider, + evaluator: provider, + verbose: true, + }); + txBuilder.setNetwork("preprod"); + for (const utxo of args.utxos) { + txBuilder + .txIn( + utxo.input.txHash, + utxo.input.outputIndex, + utxo.output.amount, + utxo.output.address, + ) + .txInScript(scriptCbor); + } + txBuilder.txOut(args.collateralAddress, [ + { + unit: "lovelace", + quantity: PROXY_LIFECYCLE_COLLATERAL_SPLIT_LOVELACE.toString(), + }, + ]); + txBuilder.changeAddress(args.walletAddress); + const unsignedTxHex = await txBuilder.complete(); + if (!unsignedTxHex || typeof unsignedTxHex !== "string") { + throw new Error("Failed to build unsigned proxy lifecycle self-split transaction"); + } + return unsignedTxHex; +} + +export async function ensureProxyLifecycleUtxoShape(args: { + ctx: CIBootstrapContext; + walletType: CIWalletType; +}): Promise { + const wallet = getWalletByType(args.ctx, args.walletType); + if (!wallet) throw new Error(`Missing ${args.walletType} wallet`); + if (!wallet.walletAddress) { + throw new Error(`Wallet ${wallet.walletId} is missing walletAddress; cannot shape proxy lifecycle UTxOs`); + } + + const bot = getDefaultBot(args.ctx); + const token = await authenticateBot({ ctx: args.ctx, bot }); + const [utxos, collateralUtxos] = await Promise.all([ + fetchFreshFreeUtxos({ + ctx: args.ctx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + }), + fetchKeyAddressUtxos({ ctx: args.ctx, address: bot.paymentAddress }), + ]); + const analysis = analyzeProxyFullLifecycleUtxoShape({ + walletUtxos: utxos, + collateralUtxos, + }); + if (analysis.status === "pass") { + return { + walletType: args.walletType, + walletId: wallet.walletId, + status: "already-shaped", + totalLovelace: analysis.totalLovelace.toString(), + requiredTotalLovelace: analysis.requiredTotalLovelace.toString(), + drepSelectableLovelace: analysis.drepSelectableLovelace.toString(), + keyCollateralCandidates: analysis.keyCollateralCandidates, + }; + } + if (analysis.status !== "needs-split") { + if (analysis.status === "insufficient-shape") { + throw new Error( + `Proxy lifecycle self-split cannot leave ${formatAda(PROXY_LIFECYCLE_COLLATERAL_SPLIT_LOVELACE)} collateral plus enough selectable ADA. ${analysis.diagnostics}. Add at least ${formatAda(analysis.selfSplitRequiredLovelace - analysis.totalLovelace)} plus any desired safety margin before running proxy full lifecycle.`, + ); + } + assertProxyFullLifecyclePreflight({ walletUtxos: utxos, collateralUtxos }); + } + + requireProxyShapeEnvironment(args.ctx, wallet.walletAddress, bot.paymentAddress); + const unsignedTxHex = await buildSelfSplitTransaction({ + walletId: wallet.walletId, + walletAddress: wallet.walletAddress, + collateralAddress: bot.paymentAddress, + utxos, + }); + const addResponse = await requestJson<{ id?: string; error?: string }>({ + url: `${args.ctx.apiBaseUrl}/api/v1/addTransaction`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + txCbor: unsignedTxHex, + txJson: JSON.stringify({ + source: "ci-route-chain", + kind: "proxy-lifecycle-utxo-shape", + walletType: args.walletType, + outputCollateralLovelace: PROXY_LIFECYCLE_COLLATERAL_SPLIT_LOVELACE.toString(), + outputCollateralAddress: bot.paymentAddress, + sourceUtxoCount: utxos.length, + totalLovelace: analysis.totalLovelace.toString(), + }), + description: `CI proxy lifecycle UTxO self-split (${args.walletType})`, + }, + }); + if (addResponse.status !== 201 || !addResponse.data?.id) { + throw new Error(`addTransaction proxy UTxO self-split failed (${addResponse.status}): ${stringifyRedacted(addResponse.data)}`); + } + + const transactionId = addResponse.data.id; + await runSigningFlow({ + ctx: args.ctx, + mnemonic: process.env.CI_MNEMONIC_2!, + signWalletType: args.walletType, + signerIndex: 1, + signerLabel: "signer1", + signBroadcast: false, + preferredTransactionId: transactionId, + requireBroadcastSuccess: false, + }); + await runSigningFlow({ + ctx: args.ctx, + mnemonic: process.env.CI_MNEMONIC_3!, + signWalletType: args.walletType, + signerIndex: 2, + signerLabel: "signer2", + signBroadcast: boolFromEnv(process.env.SIGN_BROADCAST, true), + preferredTransactionId: transactionId, + requireBroadcastSuccess: true, + }); + + const spentUtxoRefs = utxos.map(toRef); + const confirmation = await pollUntilUtxosConsumed({ + ctx: args.ctx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + spentUtxoRefs, + }); + const [shapedUtxos, shapedCollateralUtxos] = await Promise.all([ + fetchFreshFreeUtxos({ + ctx: args.ctx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + }), + fetchKeyAddressUtxos({ ctx: args.ctx, address: bot.paymentAddress }), + ]); + const shaped = assertProxyFullLifecyclePreflight({ + walletUtxos: shapedUtxos, + collateralUtxos: shapedCollateralUtxos, + }); + + return { + walletType: args.walletType, + walletId: wallet.walletId, + status: "split", + transactionId, + spentUtxoRefs, + attempts: confirmation.attempts, + totalLovelace: shaped.totalLovelace.toString(), + requiredTotalLovelace: shaped.requiredTotalLovelace.toString(), + drepSelectableLovelace: shaped.drepSelectableLovelace.toString(), + keyCollateralCandidates: shaped.keyCollateralCandidates, + }; +} diff --git a/scripts/ci/scenarios/manifest.ts b/scripts/ci/scenarios/manifest.ts new file mode 100644 index 00000000..21bfc7fc --- /dev/null +++ b/scripts/ci/scenarios/manifest.ts @@ -0,0 +1,99 @@ +import type { CIBootstrapContext, CIWalletType, Scenario } from "../framework/types"; +import { getRingWalletTypes } from "./steps/helpers"; +import { createScenarioPendingAndDiscovery, createScenarioAdaRouteHealth } from "./steps/discovery"; +import { createScenarioBotIdentity } from "./steps/botIdentity"; +import { createScenarioAuthPlane } from "./steps/authPlane"; +import { createScenarioSubmitDatum } from "./steps/datum"; +import { createScenarioGovernanceRoutes } from "./steps/governance"; +import { + createScenarioProxyFullLifecycle, + createScenarioProxySmoke, +} from "./steps/proxyBot"; +import { + createScenarioRealTransferAndSign, + createScenarioFinalAssertions, + type TransferLegRuntime, +} from "./steps/transferRing"; +import { + createScenarioDRepCertificates, + createScenarioStakeCertificates, +} from "./steps/certificates"; +import { createScenarioCreateWallet } from "./steps/walletLifecycle"; + +export const ROUTE_SCENARIO_IDS = [ + "scenario.wallet-discovery", + "scenario.ada-route-health", + "scenario.create-wallet", + "scenario.bot-identity", + "scenario.auth-plane", + "scenario.proxy-smoke", + "scenario.submit-datum", + "scenario.governance-routes", + "scenario.drep-certificates", + "scenario.stake-certificates", + "scenario.proxy-full-lifecycle", + "scenario.real-transfer-and-sign", + "scenario.final-assertions", +] as const; + +function createTransferRuntime(ctx: CIBootstrapContext): { transferLegs: TransferLegRuntime[] } { + const [legacy, hierarchical, sdk] = getRingWalletTypes(ctx); + return { + transferLegs: [ + { fromWalletType: legacy, toWalletType: hierarchical }, + { fromWalletType: hierarchical, toWalletType: sdk }, + { fromWalletType: sdk, toWalletType: legacy }, + ], + }; +} + +export function getScenarioManifest( + ctx: CIBootstrapContext, + requestedScenarioIds: string[] = [], +): Scenario[] { + const requested = new Set(requestedScenarioIds); + const shouldInclude = (id: (typeof ROUTE_SCENARIO_IDS)[number]) => + requested.size === 0 || requested.has(id); + + const hasLegacy = ctx.wallets.some((w) => w.type === "legacy"); + const hasSdk = ctx.wallets.some((w) => w.type === "sdk"); + let transferRuntime: { transferLegs: TransferLegRuntime[] } | undefined; + const getTransferRuntime = () => { + transferRuntime ??= createTransferRuntime(ctx); + return transferRuntime; + }; + + const scenarios: Scenario[] = []; + + if (shouldInclude("scenario.wallet-discovery")) scenarios.push(createScenarioPendingAndDiscovery(ctx)); + if (shouldInclude("scenario.ada-route-health")) scenarios.push(createScenarioAdaRouteHealth(ctx)); + if (shouldInclude("scenario.create-wallet")) scenarios.push(createScenarioCreateWallet(ctx)); + if (shouldInclude("scenario.bot-identity")) scenarios.push(createScenarioBotIdentity()); + if (shouldInclude("scenario.auth-plane")) scenarios.push(createScenarioAuthPlane(ctx)); + if (shouldInclude("scenario.proxy-smoke")) scenarios.push(createScenarioProxySmoke(ctx)); + if (shouldInclude("scenario.submit-datum")) scenarios.push(createScenarioSubmitDatum(ctx)); + if (shouldInclude("scenario.governance-routes")) scenarios.push(createScenarioGovernanceRoutes(ctx)); + + // Certificate scenarios run before the ring transfer so they use confirmed, + // unspent UTxOs. The ring transfer spends wallet UTxOs; running certs after + // it creates a race where the cert tx references UTxOs already in the mempool. + if (hasLegacy && hasSdk && shouldInclude("scenario.drep-certificates")) { + scenarios.push(createScenarioDRepCertificates()); + } + if (hasSdk && shouldInclude("scenario.stake-certificates")) { + scenarios.push(createScenarioStakeCertificates()); + } + + if (shouldInclude("scenario.proxy-full-lifecycle")) { + scenarios.push(createScenarioProxyFullLifecycle(ctx)); + } + + if (shouldInclude("scenario.real-transfer-and-sign")) { + scenarios.push(createScenarioRealTransferAndSign(getTransferRuntime())); + } + if (shouldInclude("scenario.final-assertions")) { + scenarios.push(createScenarioFinalAssertions(getTransferRuntime())); + } + + return scenarios; +} diff --git a/scripts/ci/scenarios/proxyChainRecovery.ts b/scripts/ci/scenarios/proxyChainRecovery.ts new file mode 100644 index 00000000..2b40b624 --- /dev/null +++ b/scripts/ci/scenarios/proxyChainRecovery.ts @@ -0,0 +1,369 @@ +import { PrismaClient, type Proxy as DbProxy } from "@prisma/client"; +import { BlockfrostProvider, type UTxO } from "@meshsdk/core"; +import { deriveProxyScripts } from "../../../src/lib/server/proxyTxBuilders"; +import type { UtxoRef } from "../../../src/lib/server/proxyUtxos"; +import type { CIBootstrapContext, CIWalletType } from "../framework/types"; +import { getWalletByType } from "./steps/helpers"; + +type ProxyRecoveryRow = Pick< + DbProxy, + "id" | "walletId" | "proxyAddress" | "authTokenId" | "paramUtxo" | "isActive" +>; + +type ProxyRecoveryCreateData = { + walletId: string; + proxyAddress: string; + authTokenId: string; + paramUtxo: string; + description: string; + isActive: true; +}; + +type ProxyRecoveryDb = { + wallet: { + findUnique: (args: { + where: { id: string }; + select: { id: true }; + }) => Promise<{ id: string } | null>; + }; + proxy: { + findFirst: (args: { + where: { authTokenId: string }; + select: Record; + }) => Promise; + create: (args: { + data: ProxyRecoveryCreateData; + select: Record; + }) => Promise; + update: (args: { + where: { id: string }; + data: { walletId: string; isActive: true }; + select: Record; + }) => Promise; + }; + $transaction?: (fn: (tx: ProxyRecoveryDb) => Promise) => Promise; +}; + +export type ProxyChainRecoveryProvider = { + fetchAddressUTxOs: (address: string) => Promise; + get: (path: string) => Promise; +}; + +type AssetHistoryEntry = { + tx_hash?: string; + action?: string; +}; + +type TxUtxoEntry = { + tx_hash?: string; + output_index?: number; +}; + +type TxUtxosResponse = { + inputs?: TxUtxoEntry[]; +}; + +export type ProxyChainRecoverySkipReason = + | "candidate-cap-exceeded" + | "asset-history-fetch-error" + | "no-mint-transaction" + | "tx-utxos-fetch-error" + | "no-derived-match" + | "already-current-active"; + +export type ProxyChainRecoveryResult = { + walletType: CIWalletType; + walletId: string; + walletAddress: string; + recovered: Array<{ + proxyId: string; + action: "created" | "reactivated" | "reattached"; + fromWalletId: string | null; + authTokenId: string; + proxyAddress: string; + paramUtxo: UtxoRef; + mintTxHash: string; + dRepId: string; + proxyUtxoCount?: number; + }>; + skipped: Array<{ + assetUnit: string; + reason: ProxyChainRecoverySkipReason; + detail?: string; + }>; +}; + +const DEFAULT_MAX_CANDIDATES = 25; +const ASSET_HISTORY_PAGE_SIZE = 100; + +const proxySelect: Record = { + id: true, + walletId: true, + proxyAddress: true, + authTokenId: true, + paramUtxo: true, + isActive: true, +}; + +let defaultDb: PrismaClient | undefined; + +function getDefaultDb(): PrismaClient { + defaultDb ??= new PrismaClient(); + return defaultDb; +} + +function createDefaultProvider(networkId: 0 | 1): ProxyChainRecoveryProvider { + const apiKey = + networkId === 0 + ? process.env.CI_BLOCKFROST_PREPROD_API_KEY?.trim() || + process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY_PREPROD?.trim() + : process.env.CI_BLOCKFROST_MAINNET_API_KEY?.trim() || + process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY_MAINNET?.trim(); + if (!apiKey) { + throw new Error(`Missing Blockfrost API key for proxy chain recovery on network ${networkId}`); + } + return new BlockfrostProvider(apiKey) as unknown as ProxyChainRecoveryProvider; +} + +async function runInTransaction( + db: ProxyRecoveryDb, + fn: (tx: ProxyRecoveryDb) => Promise, +): Promise { + if (typeof db.$transaction === "function") { + return db.$transaction(fn); + } + return fn(db); +} + +function positiveQuantity(quantity: string | undefined): boolean { + try { + return BigInt(quantity ?? "0") > 0n; + } catch { + return false; + } +} + +function collectAssetUnits(utxos: UTxO[]): string[] { + const units = new Set(); + for (const utxo of utxos) { + for (const asset of utxo.output.amount) { + if (asset.unit !== "lovelace" && positiveQuantity(asset.quantity)) { + units.add(asset.unit); + } + } + } + return [...units].sort(); +} + +function normalizeAssetHistory(value: unknown): AssetHistoryEntry[] { + return Array.isArray(value) ? (value as AssetHistoryEntry[]) : []; +} + +function normalizeTxUtxos(value: unknown): TxUtxosResponse { + return typeof value === "object" && value !== null ? (value as TxUtxosResponse) : {}; +} + +function findMintTxHash(history: AssetHistoryEntry[]): string | null { + const mint = history.find( + (entry) => entry.action === "minted" && typeof entry.tx_hash === "string" && entry.tx_hash, + ); + return mint?.tx_hash ?? null; +} + +function inputToRef(input: TxUtxoEntry): UtxoRef | null { + const txHash = typeof input.tx_hash === "string" ? input.tx_hash.trim() : ""; + const outputIndex = + typeof input.output_index === "number" && Number.isInteger(input.output_index) + ? input.output_index + : -1; + if (!txHash || outputIndex < 0) return null; + return { txHash, outputIndex }; +} + +async function inspectAssetCandidate(args: { + assetUnit: string; + provider: ProxyChainRecoveryProvider; + network: 0 | 1; +}): Promise< + | { + matched: true; + authTokenId: string; + proxyAddress: string; + paramUtxo: UtxoRef; + mintTxHash: string; + dRepId: string; + proxyUtxoCount?: number; + } + | { matched: false; reason: ProxyChainRecoverySkipReason; detail?: string } +> { + let history: AssetHistoryEntry[]; + try { + history = normalizeAssetHistory( + await args.provider.get( + `/assets/${encodeURIComponent(args.assetUnit)}/history?order=asc&count=${ASSET_HISTORY_PAGE_SIZE}`, + ), + ); + } catch (error) { + return { + matched: false, + reason: "asset-history-fetch-error", + detail: error instanceof Error ? error.message : String(error), + }; + } + + const mintTxHash = findMintTxHash(history); + if (!mintTxHash) { + return { matched: false, reason: "no-mint-transaction" }; + } + + let txUtxos: TxUtxosResponse; + try { + txUtxos = normalizeTxUtxos( + await args.provider.get(`/txs/${encodeURIComponent(mintTxHash)}/utxos`), + ); + } catch (error) { + return { + matched: false, + reason: "tx-utxos-fetch-error", + detail: error instanceof Error ? error.message : String(error), + }; + } + + const inputs = Array.isArray(txUtxos.inputs) ? txUtxos.inputs : []; + for (const input of inputs) { + const paramUtxo = inputToRef(input); + if (!paramUtxo) continue; + + const scripts = deriveProxyScripts({ paramUtxo, network: args.network }); + if (scripts.authTokenId !== args.assetUnit) continue; + + let proxyUtxoCount: number | undefined; + try { + proxyUtxoCount = (await args.provider.fetchAddressUTxOs(scripts.proxyAddress)).length; + } catch { + proxyUtxoCount = undefined; + } + + return { + matched: true, + authTokenId: scripts.authTokenId, + proxyAddress: scripts.proxyAddress, + paramUtxo, + mintTxHash, + dRepId: scripts.dRepId, + proxyUtxoCount, + }; + } + + return { matched: false, reason: "no-derived-match" }; +} + +export async function recoverProxyRowsFromChainForWalletType(args: { + ctx: CIBootstrapContext; + walletType: CIWalletType; + db?: ProxyRecoveryDb; + provider?: ProxyChainRecoveryProvider; + maxCandidates?: number; +}): Promise { + const wallet = getWalletByType(args.ctx, args.walletType); + if (!wallet) throw new Error(`Missing ${args.walletType} wallet`); + + const db = args.db ?? (getDefaultDb() as unknown as ProxyRecoveryDb); + const provider = args.provider ?? createDefaultProvider(args.ctx.networkId); + const currentWallet = await db.wallet.findUnique({ + where: { id: wallet.walletId }, + select: { id: true }, + }); + if (!currentWallet) { + throw new Error(`Current ${args.walletType} wallet row ${wallet.walletId} was not found`); + } + + const walletUtxos = await provider.fetchAddressUTxOs(wallet.walletAddress); + const assetUnits = collectAssetUnits(walletUtxos); + const maxCandidates = args.maxCandidates ?? DEFAULT_MAX_CANDIDATES; + const candidates = assetUnits.slice(0, maxCandidates); + const skipped: ProxyChainRecoveryResult["skipped"] = assetUnits + .slice(maxCandidates) + .map((assetUnit) => ({ + assetUnit, + reason: "candidate-cap-exceeded", + detail: `candidate limit ${maxCandidates} reached`, + })); + + const matches: Array<{ + assetUnit: string; + authTokenId: string; + proxyAddress: string; + paramUtxo: UtxoRef; + mintTxHash: string; + dRepId: string; + proxyUtxoCount?: number; + }> = []; + + for (const assetUnit of candidates) { + const inspected = await inspectAssetCandidate({ + assetUnit, + provider, + network: args.ctx.networkId, + }); + if (!inspected.matched) { + skipped.push({ assetUnit, reason: inspected.reason, detail: inspected.detail }); + continue; + } + matches.push({ assetUnit, ...inspected }); + } + + const recovered: ProxyChainRecoveryResult["recovered"] = []; + await runInTransaction(db, async (tx) => { + for (const match of matches) { + const existing = await tx.proxy.findFirst({ + where: { authTokenId: match.authTokenId }, + select: proxySelect, + }); + + if (existing?.walletId === wallet.walletId && existing.isActive) { + skipped.push({ assetUnit: match.assetUnit, reason: "already-current-active" }); + continue; + } + + const previousWalletId = existing?.walletId ?? null; + const row = existing + ? await tx.proxy.update({ + where: { id: existing.id }, + data: { walletId: wallet.walletId, isActive: true }, + select: proxySelect, + }) + : await tx.proxy.create({ + data: { + walletId: wallet.walletId, + proxyAddress: match.proxyAddress, + authTokenId: match.authTokenId, + paramUtxo: JSON.stringify(match.paramUtxo), + description: "Recovered CI proxy from chain", + isActive: true, + }, + select: proxySelect, + }); + + recovered.push({ + proxyId: row.id, + action: existing ? (previousWalletId === wallet.walletId ? "reactivated" : "reattached") : "created", + fromWalletId: previousWalletId, + authTokenId: match.authTokenId, + proxyAddress: match.proxyAddress, + paramUtxo: match.paramUtxo, + mintTxHash: match.mintTxHash, + dRepId: match.dRepId, + proxyUtxoCount: match.proxyUtxoCount, + }); + } + }); + + return { + walletType: args.walletType, + walletId: wallet.walletId, + walletAddress: wallet.walletAddress, + recovered, + skipped, + }; +} diff --git a/scripts/ci/scenarios/proxyLifecyclePreflight.ts b/scripts/ci/scenarios/proxyLifecyclePreflight.ts new file mode 100644 index 00000000..c996c337 --- /dev/null +++ b/scripts/ci/scenarios/proxyLifecyclePreflight.ts @@ -0,0 +1,181 @@ +export type UtxoRef = { txHash: string; outputIndex: number }; + +export type ScriptUtxo = { + input: UtxoRef; + output: { address: string; amount: { unit: string; quantity: string }[] }; +}; + +export type ProxyLifecycleUtxoShapeStatus = + | "pass" + | "needs-split" + | "insufficient-total" + | "insufficient-selectable" + | "insufficient-shape"; + +export const DREP_REGISTER_REQUIRED_LOVELACE = 505_000_000n; +export const LIFECYCLE_PROXY_LOVELACE = 10_000_000n; +export const FULL_LIFECYCLE_FEE_BUFFER_LOVELACE = 20_000_000n; +export const SETUP_UTXO_REQUIRED_LOVELACE = 20_000_000n; +export const COLLATERAL_REQUIRED_LOVELACE = 5_000_000n; +export const PROXY_SPEND_LOVELACE = 1_000_000n; +export const PROXY_LIFECYCLE_COLLATERAL_SPLIT_LOVELACE = 6_000_000n; +export const SELF_SPLIT_FEE_BUFFER_LOVELACE = 2_000_000n; +export const PROXY_FULL_LIFECYCLE_WALLET_TYPES = ["legacy", "hierarchical", "sdk"] as const; + +export function parseLovelace(utxo: ScriptUtxo): bigint { + return BigInt(utxo.output.amount.find((asset) => asset.unit === "lovelace")?.quantity ?? "0"); +} + +export function toRef(utxo: ScriptUtxo): UtxoRef { + return { txHash: utxo.input.txHash, outputIndex: utxo.input.outputIndex }; +} + +export function key(ref: UtxoRef): string { + return `${ref.txHash}:${ref.outputIndex}`; +} + +export function sameRef(left: UtxoRef, right: UtxoRef): boolean { + return key(left) === key(right); +} + +export function containsRef(refs: UtxoRef[], ref: UtxoRef): boolean { + return refs.some((existing) => sameRef(existing, ref)); +} + +export function formatAda(lovelace: bigint): string { + const ada = lovelace / 1_000_000n; + const remainder = lovelace % 1_000_000n; + if (remainder === 0n) return `${ada.toString()} ADA`; + return `${ada.toString()}.${remainder.toString().padStart(6, "0")} ADA`; +} + +export function getProxyFullLifecycleRequiredLovelace(): bigint { + return ( + DREP_REGISTER_REQUIRED_LOVELACE + + LIFECYCLE_PROXY_LOVELACE + + PROXY_SPEND_LOVELACE + + FULL_LIFECYCLE_FEE_BUFFER_LOVELACE + ); +} + +export type ProxyLifecycleUtxoShapeAnalysis = { + status: ProxyLifecycleUtxoShapeStatus; + totalLovelace: bigint; + largestUtxoLovelace: bigint; + setupCandidates: number; + keyCollateralCandidates: number; + drepSelectableLovelace: bigint; + drepRequiredLovelace: bigint; + requiredTotalLovelace: bigint; + selfSplitRequiredLovelace: bigint; + hasSetupCandidate: boolean; + hasKeyCollateral: boolean; + diagnostics: string; +}; + +export type ProxyLifecycleUtxoShapeInput = { + walletUtxos: ScriptUtxo[]; + collateralUtxos: ScriptUtxo[]; +}; + +export function analyzeProxyFullLifecycleUtxoShape(args: { + walletUtxos: ScriptUtxo[]; + collateralUtxos: ScriptUtxo[]; +}): ProxyLifecycleUtxoShapeAnalysis { + const lovelaces = args.walletUtxos.map(parseLovelace); + const totalLovelace = lovelaces.reduce((sum, value) => sum + value, 0n); + const largestUtxoLovelace = lovelaces.reduce( + (largest, value) => (value > largest ? value : largest), + 0n, + ); + const setupCandidates = lovelaces.filter((value) => value >= SETUP_UTXO_REQUIRED_LOVELACE).length; + const keyCollateralCandidates = args.collateralUtxos.filter( + (utxo) => + parseLovelace(utxo) >= COLLATERAL_REQUIRED_LOVELACE && + utxo.output.amount.every((asset) => asset.unit === "lovelace"), + ); + const hasSetupCandidate = setupCandidates > 0; + const hasKeyCollateral = keyCollateralCandidates.length > 0; + const drepRequiredLovelace = getProxyFullLifecycleRequiredLovelace(); + const drepSelectableLovelace = totalLovelace; + const requiredTotalLovelace = getProxyFullLifecycleRequiredLovelace(); + const selfSplitRequiredLovelace = + drepRequiredLovelace + PROXY_LIFECYCLE_COLLATERAL_SPLIT_LOVELACE + SELF_SPLIT_FEE_BUFFER_LOVELACE; + const diagnostics = + `total=${formatAda(totalLovelace)}, largestUtxO=${formatAda(largestUtxoLovelace)}, ` + + `setupCandidates=${setupCandidates}, keyCollateralCandidates=${keyCollateralCandidates.length}, ` + + `drepSelectable=${formatAda(drepSelectableLovelace)}, drepRequired=${formatAda(drepRequiredLovelace)}, ` + + `required=${formatAda(requiredTotalLovelace)} ` + + `(DRep register ${formatAda(DREP_REGISTER_REQUIRED_LOVELACE)} + ` + + `initial proxy ${formatAda(LIFECYCLE_PROXY_LOVELACE)} + ` + + `proxy spend ${formatAda(PROXY_SPEND_LOVELACE)} + ` + + `fee buffer ${formatAda(FULL_LIFECYCLE_FEE_BUFFER_LOVELACE)})`; + + let status: ProxyLifecycleUtxoShapeStatus = "pass"; + if (totalLovelace < requiredTotalLovelace) { + status = "insufficient-total"; + } else if (!hasSetupCandidate || !hasKeyCollateral) { + status = + totalLovelace >= selfSplitRequiredLovelace + ? "needs-split" + : "insufficient-shape"; + } else if (drepSelectableLovelace < drepRequiredLovelace) { + status = "insufficient-selectable"; + } + + return { + status, + totalLovelace, + largestUtxoLovelace, + setupCandidates, + keyCollateralCandidates: keyCollateralCandidates.length, + drepSelectableLovelace, + drepRequiredLovelace, + requiredTotalLovelace, + selfSplitRequiredLovelace, + hasSetupCandidate, + hasKeyCollateral, + diagnostics, + }; +} + +export function assertProxyFullLifecyclePreflight(args: { + walletUtxos: ScriptUtxo[]; + collateralUtxos: ScriptUtxo[]; +}): Omit< + ProxyLifecycleUtxoShapeAnalysis, + "status" | "diagnostics" | "selfSplitRequiredLovelace" | "hasSetupCandidate" | "hasKeyCollateral" +> { + const analysis = analyzeProxyFullLifecycleUtxoShape(args); + + if (analysis.keyCollateralCandidates === 0) { + throw new Error( + `Proxy full lifecycle preflight failed: no bot payment-address UTxO has at least ${formatAda(COLLATERAL_REQUIRED_LOVELACE)} for Plutus collateral. ${analysis.diagnostics}. Run proxy lifecycle UTxO shaping or fund the bot payment address before running proxy full lifecycle.`, + ); + } + if (analysis.setupCandidates === 0) { + throw new Error( + `Proxy full lifecycle preflight failed: no wallet UTxO has at least ${formatAda(SETUP_UTXO_REQUIRED_LOVELACE)} for proxy setup. ${analysis.diagnostics}. Fund or consolidate the CI wallet before running proxy full lifecycle.`, + ); + } + if (analysis.totalLovelace < analysis.requiredTotalLovelace) { + throw new Error( + `Proxy full lifecycle preflight failed: insufficient ADA for full lifecycle. ${analysis.diagnostics}. Add at least ${formatAda(analysis.requiredTotalLovelace - analysis.totalLovelace)} plus any desired safety margin before running proxy full lifecycle.`, + ); + } + if (analysis.drepSelectableLovelace < analysis.drepRequiredLovelace) { + throw new Error( + `Proxy full lifecycle preflight failed: DRep register cannot select enough ADA while reserving separate collateral and accounting for prior proxy setup/spend costs. ${analysis.diagnostics}. Add at least ${formatAda(analysis.drepRequiredLovelace - analysis.drepSelectableLovelace)} plus any desired safety margin, or consolidate spendable ADA outside the collateral UTxO.`, + ); + } + + return { + totalLovelace: analysis.totalLovelace, + largestUtxoLovelace: analysis.largestUtxoLovelace, + setupCandidates: analysis.setupCandidates, + keyCollateralCandidates: analysis.keyCollateralCandidates, + drepSelectableLovelace: analysis.drepSelectableLovelace, + drepRequiredLovelace: analysis.drepRequiredLovelace, + requiredTotalLovelace: analysis.requiredTotalLovelace, + }; +} diff --git a/scripts/ci/scenarios/proxyOrphanAdoption.ts b/scripts/ci/scenarios/proxyOrphanAdoption.ts new file mode 100644 index 00000000..9754a0a7 --- /dev/null +++ b/scripts/ci/scenarios/proxyOrphanAdoption.ts @@ -0,0 +1,307 @@ +import { PrismaClient, type Proxy as DbProxy, type Wallet as DbWallet } from "@prisma/client"; +import { BlockfrostProvider, type UTxO } from "@meshsdk/core"; +import { deriveProxyScripts } from "../../../src/lib/server/proxyTxBuilders"; +import { hasAsset, type UtxoRef } from "../../../src/lib/server/proxyUtxos"; +import { resolveWalletScriptAddressSafe } from "../../../src/lib/server/walletScriptAddress"; +import type { CIBootstrapContext, CIWalletType } from "../framework/types"; +import { getWalletByType } from "./steps/helpers"; + +type ProxyAdoptionWallet = Pick< + DbWallet, + | "id" + | "name" + | "signersAddresses" + | "signersStakeKeys" + | "signersDRepKeys" + | "signersDescriptions" + | "numRequiredSigners" + | "scriptCbor" + | "stakeCredentialHash" + | "type" + | "rawImportBodies" +>; + +type ProxyAdoptionRow = Pick< + DbProxy, + "id" | "walletId" | "proxyAddress" | "authTokenId" | "paramUtxo" | "isActive" +>; + +type ProxyAdoptionDb = { + wallet: { + findUnique: (args: { + where: { id: string }; + select: Record; + }) => Promise; + findMany: (args: { + select: Record; + }) => Promise; + }; + proxy: { + findMany: (args: { + where: { walletId: { in: string[] } }; + select: Record; + }) => Promise; + update: (args: { + where: { id: string }; + data: { walletId: string; isActive: true }; + select: { id: true; walletId: true; isActive: true }; + }) => Promise<{ id: string; walletId: string | null; isActive: boolean }>; + }; + $transaction?: (fn: (tx: ProxyAdoptionDb) => Promise) => Promise; +}; + +export type ProxyOrphanAdoptionProvider = { + fetchAddressUTxOs: (address: string) => Promise; +}; + +export type ProxyAdoptionSkipReason = + | "already-current-active" + | "invalid-param-utxo" + | "metadata-mismatch" + | "chain-empty" + | "chain-fetch-error"; + +export type ProxyAdoptionResult = { + walletType: CIWalletType; + walletId: string; + walletAddress: string; + historicalWalletIds: string[]; + adopted: Array<{ + proxyId: string; + fromWalletId: string | null; + authTokenId: string; + proxyAddress: string; + wasActive: boolean; + }>; + skipped: Array<{ + proxyId: string; + walletId: string | null; + reason: ProxyAdoptionSkipReason; + detail?: string; + }>; +}; + +const walletSelect: Record = { + id: true, + name: true, + signersAddresses: true, + signersStakeKeys: true, + signersDRepKeys: true, + signersDescriptions: true, + numRequiredSigners: true, + scriptCbor: true, + stakeCredentialHash: true, + type: true, + rawImportBodies: true, +}; + +const proxySelect: Record = { + id: true, + walletId: true, + proxyAddress: true, + authTokenId: true, + paramUtxo: true, + isActive: true, +}; + +let defaultDb: PrismaClient | undefined; + +function getDefaultDb(): PrismaClient { + defaultDb ??= new PrismaClient(); + return defaultDb; +} + +function createDefaultProvider(networkId: 0 | 1): ProxyOrphanAdoptionProvider { + const apiKey = + networkId === 0 + ? process.env.CI_BLOCKFROST_PREPROD_API_KEY?.trim() || + process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY_PREPROD?.trim() + : process.env.CI_BLOCKFROST_MAINNET_API_KEY?.trim() || + process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY_MAINNET?.trim(); + if (!apiKey) { + throw new Error(`Missing Blockfrost API key for proxy orphan adoption on network ${networkId}`); + } + return new BlockfrostProvider(apiKey); +} + +function parseParamUtxo(value: string): UtxoRef | null { + try { + const parsed = JSON.parse(value) as Partial; + const txHash = typeof parsed.txHash === "string" ? parsed.txHash.trim() : ""; + const outputIndex = + typeof parsed.outputIndex === "number" && Number.isInteger(parsed.outputIndex) + ? parsed.outputIndex + : -1; + if (!txHash || outputIndex < 0) return null; + return { txHash, outputIndex }; + } catch { + return null; + } +} + +async function runInTransaction( + db: ProxyAdoptionDb, + fn: (tx: ProxyAdoptionDb) => Promise, +): Promise { + if (typeof db.$transaction === "function") { + return db.$transaction(fn); + } + return fn(db); +} + +function resolveMatchingWalletIds(args: { + currentWallet: ProxyAdoptionWallet; + allWallets: ProxyAdoptionWallet[]; + fallbackAddress: string; +}): string[] { + const currentAddressResult = resolveWalletScriptAddressSafe( + args.currentWallet as DbWallet, + args.fallbackAddress, + ); + if ("error" in currentAddressResult) { + throw new Error(`Unable to resolve current wallet script address: ${currentAddressResult.error}`); + } + + return args.allWallets + .filter((wallet) => { + const resolved = resolveWalletScriptAddressSafe(wallet as DbWallet, args.fallbackAddress); + return "address" in resolved && resolved.address === currentAddressResult.address; + }) + .map((wallet) => wallet.id); +} + +function hasAuthToken(utxos: UTxO[], authTokenId: string): boolean { + return utxos.some((utxo) => hasAsset(utxo, authTokenId)); +} + +export async function adoptProxyOrphansForWalletType(args: { + ctx: CIBootstrapContext; + walletType: CIWalletType; + db?: ProxyAdoptionDb; + provider?: ProxyOrphanAdoptionProvider; +}): Promise { + const wallet = getWalletByType(args.ctx, args.walletType); + if (!wallet) throw new Error(`Missing ${args.walletType} wallet`); + + const db = args.db ?? (getDefaultDb() as unknown as ProxyAdoptionDb); + const provider = args.provider ?? createDefaultProvider(args.ctx.networkId); + const currentWallet = await db.wallet.findUnique({ + where: { id: wallet.walletId }, + select: walletSelect, + }); + if (!currentWallet) { + throw new Error(`Current ${args.walletType} wallet row ${wallet.walletId} was not found`); + } + + const allWallets = await db.wallet.findMany({ select: walletSelect }); + const matchingWalletIds = resolveMatchingWalletIds({ + currentWallet, + allWallets, + fallbackAddress: wallet.walletAddress, + }); + const historicalWalletIds = matchingWalletIds.filter((walletId) => walletId !== wallet.walletId); + if (matchingWalletIds.length === 0) { + return { + walletType: args.walletType, + walletId: wallet.walletId, + walletAddress: wallet.walletAddress, + historicalWalletIds: [], + adopted: [], + skipped: [], + }; + } + + const candidates = await db.proxy.findMany({ + where: { walletId: { in: matchingWalletIds } }, + select: proxySelect, + }); + + const walletUtxos = await provider.fetchAddressUTxOs(wallet.walletAddress); + const adopted: ProxyAdoptionResult["adopted"] = []; + const skipped: ProxyAdoptionResult["skipped"] = []; + const updates: ProxyAdoptionRow[] = []; + + for (const proxy of candidates) { + if (proxy.walletId === wallet.walletId && proxy.isActive) { + skipped.push({ + proxyId: proxy.id, + walletId: proxy.walletId, + reason: "already-current-active", + }); + continue; + } + + const paramUtxo = parseParamUtxo(proxy.paramUtxo); + if (!paramUtxo) { + skipped.push({ + proxyId: proxy.id, + walletId: proxy.walletId, + reason: "invalid-param-utxo", + }); + continue; + } + + const scripts = deriveProxyScripts({ paramUtxo, network: args.ctx.networkId }); + if (scripts.authTokenId !== proxy.authTokenId || scripts.proxyAddress !== proxy.proxyAddress) { + skipped.push({ + proxyId: proxy.id, + walletId: proxy.walletId, + reason: "metadata-mismatch", + }); + continue; + } + + let proxyUtxos: UTxO[]; + try { + proxyUtxos = await provider.fetchAddressUTxOs(proxy.proxyAddress); + } catch (error) { + skipped.push({ + proxyId: proxy.id, + walletId: proxy.walletId, + reason: "chain-fetch-error", + detail: error instanceof Error ? error.message : String(error), + }); + continue; + } + + if (!hasAuthToken(walletUtxos, proxy.authTokenId)) { + skipped.push({ + proxyId: proxy.id, + walletId: proxy.walletId, + reason: "chain-empty", + detail: proxyUtxos.length + ? "proxy address has UTxOs, but auth token is not at current wallet address" + : "no auth token at current wallet address and proxy address is empty", + }); + continue; + } + + updates.push(proxy); + } + + await runInTransaction(db, async (tx) => { + for (const proxy of updates) { + await tx.proxy.update({ + where: { id: proxy.id }, + data: { walletId: wallet.walletId, isActive: true }, + select: { id: true, walletId: true, isActive: true }, + }); + adopted.push({ + proxyId: proxy.id, + fromWalletId: proxy.walletId, + authTokenId: proxy.authTokenId, + proxyAddress: proxy.proxyAddress, + wasActive: proxy.isActive, + }); + } + }); + + return { + walletType: args.walletType, + walletId: wallet.walletId, + walletAddress: wallet.walletAddress, + historicalWalletIds, + adopted, + skipped, + }; +} diff --git a/scripts/ci/scenarios/steps/authPlane.ts b/scripts/ci/scenarios/steps/authPlane.ts new file mode 100644 index 00000000..509a2071 --- /dev/null +++ b/scripts/ci/scenarios/steps/authPlane.ts @@ -0,0 +1,233 @@ +import type { CIBootstrapContext, CIBotContext, Scenario } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; +import { authenticateSignerWithMnemonic } from "../../framework/walletAuth"; +import { getWalletByType } from "./helpers"; + +export function createScenarioAuthPlane(ctx: CIBootstrapContext): Scenario { + return { + id: "scenario.auth-plane", + description: "Wallet auth route checks and negative auth assertions", + steps: [ + { + id: "v1.authNegative.walletIds.addressMismatch", + description: "Assert /api/v1/walletIds rejects mismatched address", + severity: "critical", + execute: async (runCtx) => { + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const mismatchAddress = + runCtx.bots.find((candidate) => candidate.id !== bot.id)?.paymentAddress ?? + `${bot.paymentAddress}x`; + const response = await requestJson<{ error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/walletIds?address=${encodeURIComponent(mismatchAddress)}`, + method: "GET", + token, + }); + if (response.status !== 403) { + throw new Error( + `walletIds address mismatch expected 403, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + return { + message: "walletIds address mismatch correctly rejected with 403", + }; + }, + }, + ...ctx.walletTypes.map((walletType) => ({ + id: `v1.authNegative.addTransaction.addressMismatch.${walletType}`, + description: `Assert /api/v1/addTransaction rejects mismatched address (${walletType} walletId)`, + severity: "critical" as const, + execute: async (runCtx: CIBootstrapContext) => { + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const targetWallet = getWalletByType(runCtx, walletType); + if (!targetWallet) { + throw new Error(`Missing ${walletType} wallet for addTransaction negative check`); + } + const mismatchAddress = + runCtx.bots.find((candidate: CIBotContext) => candidate.id !== bot.id)?.paymentAddress ?? + `${bot.paymentAddress}x`; + const response = await requestJson<{ error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/addTransaction`, + method: "POST", + token, + body: { + walletId: targetWallet.walletId, + address: mismatchAddress, + txCbor: "00", + txJson: "{}", + description: "CI address mismatch negative check", + }, + }); + if (response.status !== 403) { + throw new Error( + `addTransaction address mismatch expected 403, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + return { + message: "addTransaction address mismatch correctly rejected with 403", + artifacts: { walletId: targetWallet.walletId }, + }; + }, + })), + ...ctx.walletTypes.map((walletType) => ({ + id: `v1.authNegative.pendingTransactions.missingToken.${walletType}`, + description: `Assert /api/v1/pendingTransactions rejects missing token (${walletType} wallet)`, + severity: "critical" as const, + execute: async (runCtx: CIBootstrapContext) => { + const wallet = getWalletByType(runCtx, walletType); + if (!wallet) { + throw new Error(`Missing ${walletType} wallet for pendingTransactions negative check`); + } + const signerAddress = wallet.signerAddresses[0]; + if (!signerAddress) { + throw new Error("Missing signer address for pendingTransactions negative check"); + } + const response = await requestJson<{ error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(signerAddress)}`, + method: "GET", + }); + if (response.status !== 401) { + throw new Error( + `pendingTransactions missing token expected 401, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + return { + message: "pendingTransactions missing token correctly rejected with 401", + artifacts: { walletId: wallet.walletId }, + }; + }, + })), + { + id: "v1.authNegative.drepInfo.missingToken", + description: "Assert /api/v1/drepInfo rejects missing token with 401", + severity: "critical", + execute: async (runCtx) => { + const wallet = runCtx.wallets[0]; + if (!wallet) { + throw new Error("drepInfo negative check: no wallet in context"); + } + const signerAddress = wallet.signerAddresses[0] ?? ""; + const response = await requestJson<{ error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/drepInfo?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(signerAddress)}`, + method: "GET", + }); + if (response.status !== 401) { + throw new Error( + `drepInfo missing token expected 401, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + return { + message: "drepInfo missing token correctly rejected with 401", + }; + }, + }, + { + id: "v1.authNegative.stakeAccountInfo.missingToken", + description: "Assert /api/v1/stakeAccountInfo rejects missing token with 401", + severity: "critical", + execute: async (runCtx) => { + const stakeAddress = runCtx.signerStakeAddresses[0] ?? runCtx.sdkStakeAddress ?? "stake_test1abc"; + const response = await requestJson<{ error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/stakeAccountInfo?stakeAddress=${encodeURIComponent(stakeAddress)}`, + method: "GET", + }); + if (response.status !== 401) { + throw new Error( + `stakeAccountInfo missing token expected 401, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + return { + message: "stakeAccountInfo missing token correctly rejected with 401", + }; + }, + }, + { + id: "v1.authNegative.createWallet.missingToken", + description: "Assert /api/v1/createWallet rejects missing token with 401", + severity: "critical", + execute: async (runCtx) => { + const response = await requestJson<{ error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/createWallet`, + method: "POST", + body: { name: "should-be-rejected", signersAddresses: [] }, + }); + if (response.status !== 401) { + throw new Error( + `createWallet missing token expected 401, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + return { + message: "createWallet missing token correctly rejected with 401", + }; + }, + }, + { + id: "v1.getNonce.authSigner.signer2", + description: "Authenticate signer via getNonce + authSigner", + severity: "critical", + execute: async (runCtx) => { + const mnemonic = process.env.CI_MNEMONIC_2; + if (!mnemonic?.trim()) { + throw new Error("CI_MNEMONIC_2 is required for authSigner scenario"); + } + const authResult = await authenticateSignerWithMnemonic({ + ctx: runCtx, + mnemonic, + }); + return { + message: "Signer wallet auth succeeded through getNonce/authSigner", + artifacts: { + signerAddress: authResult.signerAddress, + nonceLength: authResult.nonce.length, + }, + }; + }, + }, + { + id: "v1.signTransaction.badTransactionId", + description: "Assert /api/v1/signTransaction returns 404 for a non-existent transactionId", + severity: "non-critical", + execute: async (runCtx) => { + const mnemonic = process.env.CI_MNEMONIC_2; + if (!mnemonic?.trim()) { + return { + message: "CI_MNEMONIC_2 not set; skipping signTransaction bad-id validation check", + artifacts: { skipped: true }, + }; + } + const wallet = getWalletByType(runCtx, runCtx.walletTypes[0] ?? "legacy"); + if (!wallet) { + throw new Error("signTransaction bad-id: no wallet in context"); + } + const authResult = await authenticateSignerWithMnemonic({ ctx: runCtx, mnemonic }); + const response = await requestJson<{ error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/signTransaction`, + method: "POST", + token: authResult.token, + body: { + walletId: wallet.walletId, + transactionId: "00000000-0000-0000-0000-000000000000", + address: authResult.signerAddress, + signature: "aabbccdd", + key: "eeff0011", + broadcast: false, + }, + }); + if (response.status !== 404) { + throw new Error( + `signTransaction bad transactionId expected 404, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + return { + message: "signTransaction non-existent transactionId correctly returns 404", + artifacts: { walletId: wallet.walletId }, + }; + }, + }, + ], + }; +} diff --git a/scripts/ci/scenarios/steps/botIdentity.ts b/scripts/ci/scenarios/steps/botIdentity.ts new file mode 100644 index 00000000..1220ae7c --- /dev/null +++ b/scripts/ci/scenarios/steps/botIdentity.ts @@ -0,0 +1,82 @@ +import type { Scenario } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot, deriveCiBotSecret, requireCiJwtSecret } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; + +export function createScenarioBotIdentity(): Scenario { + return { + id: "scenario.bot-identity", + description: "Bot profile route checks", + steps: [ + { + id: "v1.botAuth.explicitRouteCheck", + description: "Verify /api/v1/botAuth response shape directly (bypasses token cache)", + severity: "critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const secret = deriveCiBotSecret(bot.paymentAddress, requireCiJwtSecret()); + const response = await requestJson<{ token?: string; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/botAuth`, + method: "POST", + body: { + botKeyId: bot.botKeyId, + secret, + paymentAddress: bot.paymentAddress, + }, + }); + if (response.status !== 200 || typeof response.data?.token !== "string") { + throw new Error( + `botAuth explicit check failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + const parts = response.data.token.split("."); + if (parts.length !== 3) { + throw new Error( + `botAuth: token is not a valid JWT — expected 3 dot-separated segments, got ${parts.length}`, + ); + } + return { + message: "botAuth explicit route check passed: response contains a well-formed JWT", + artifacts: { jwtSegmentCount: parts.length }, + }; + }, + }, + { + id: "v1.botMe.defaultBot", + description: "Verify default bot identity via /api/v1/botMe", + severity: "critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const response = await requestJson<{ + botId?: string; + paymentAddress?: string; + ownerAddress?: string; + error?: string; + }>({ + url: `${ctx.apiBaseUrl}/api/v1/botMe`, + method: "GET", + token, + }); + if (response.status !== 200) { + throw new Error(`botMe failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + if (response.data.botId !== bot.botId) { + throw new Error("botMe returned unexpected botId"); + } + if (response.data.paymentAddress !== bot.paymentAddress) { + throw new Error("botMe returned unexpected paymentAddress"); + } + return { + message: `botMe resolved bot ${response.data.botId}`, + artifacts: { + botId: response.data.botId, + paymentAddress: response.data.paymentAddress, + }, + }; + }, + }, + ], + }; +} diff --git a/scripts/ci/scenarios/steps/certificates.ts b/scripts/ci/scenarios/steps/certificates.ts new file mode 100644 index 00000000..b86f1d6a --- /dev/null +++ b/scripts/ci/scenarios/steps/certificates.ts @@ -0,0 +1,737 @@ +import type { CIBootstrapContext, CIWalletType, RouteStep, Scenario } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { runSigningFlow } from "../flows/signingFlow"; +import { runStakeCertSigningFlow } from "../flows/certificateSigningFlow"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; +import { boolFromEnv } from "../../framework/env"; + +type ScriptUtxo = { + input: { txHash: string; outputIndex: number }; + output: { address: string; amount: { unit: string; quantity: string }[] }; +}; + +async function fetchUtxoRefs(args: { + ctx: CIBootstrapContext; + walletId: string; + token: string; + botAddress: string; + fresh?: boolean; +}): Promise<{ txHash: string; outputIndex: number }[]> { + const { ctx, walletId, token, botAddress } = args; + const freshParam = args.fresh ? "&fresh=true" : ""; + const response = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/freeUtxos?walletId=${encodeURIComponent(walletId)}&address=${encodeURIComponent(botAddress)}${freshParam}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `freeUtxos preflight failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + if (response.data.length === 0) { + throw new Error("No free UTxOs available in wallet for certificate transaction"); + } + return response.data.map((u) => ({ txHash: u.input.txHash, outputIndex: u.input.outputIndex })); +} + +/** + * Polls freeUtxos?fresh=true until none of the given spent UTxO refs appear in + * the result. This confirms the cert tx has been included in a block and its + * inputs are no longer unspent on-chain. + * + * Preprod block time is ~20 s. We retry every 8 s for up to 4 minutes. + */ +async function pollUntilUtxosConsumed(args: { + ctx: CIBootstrapContext; + walletId: string; + token: string; + botAddress: string; + spentUtxoRefs: { txHash: string; outputIndex: number }[]; + maxRetries?: number; + retryDelayMs?: number; +}): Promise<{ attempts: number }> { + const { ctx, walletId, token, botAddress, spentUtxoRefs } = args; + const maxRetries = args.maxRetries ?? 30; + const retryDelayMs = args.retryDelayMs ?? 8000; + const spentKeys = new Set(spentUtxoRefs.map((r) => `${r.txHash}:${r.outputIndex}`)); + + for (let attempt = 0; attempt < maxRetries; attempt++) { + if (attempt > 0) { + await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); + } + const response = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/freeUtxos?walletId=${encodeURIComponent(walletId)}&address=${encodeURIComponent(botAddress)}&fresh=true`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + continue; + } + const hasOverlap = response.data.some((u) => + spentKeys.has(`${u.input.txHash}:${u.input.outputIndex}`), + ); + if (!hasOverlap) { + return { attempts: attempt + 1 }; + } + } + throw new Error( + `Timed out after ${maxRetries} attempts (${(maxRetries * (args.retryDelayMs ?? 8000)) / 1000}s) waiting for cert tx inputs to be confirmed on-chain`, + ); +} + +function createCertSigningStep(args: { + id: string; + description: string; + signerIndex: 1 | 2; + mnemonicEnvName: "CI_MNEMONIC_2" | "CI_MNEMONIC_3"; + walletType: CIWalletType; + signBroadcast: boolean; + requireBroadcastSuccess: boolean; + getTransactionId: () => string | undefined; + /** When true, use the stake-cert signing flow that submits both payment and stake key witnesses. */ + useStakeCertFlow?: boolean; +}): RouteStep { + return { + id: args.id, + description: args.description, + severity: "critical", + execute: async (ctx) => { + const mnemonic = process.env[args.mnemonicEnvName]; + if (!mnemonic?.trim()) { + throw new Error(`${args.mnemonicEnvName} is required for certificate signing`); + } + const txId = args.getTransactionId(); + if (!txId) { + throw new Error(`No transaction id available for signing step ${args.id}`); + } + const effectiveBroadcast = args.signBroadcast && boolFromEnv(process.env.SIGN_BROADCAST, true); + + if (args.useStakeCertFlow) { + const result = await runStakeCertSigningFlow({ + ctx, + mnemonic, + signerIndex: args.signerIndex, + signBroadcast: effectiveBroadcast, + preferredTransactionId: txId, + requireBroadcastSuccess: args.requireBroadcastSuccess, + }); + return { + message: `Stake cert sign (signer${args.signerIndex}) status=${result.status} submitted=${String(result.submitted)} stakeWitness=${String(result.stakeWitnessIncluded)}`, + artifacts: result as unknown as Record, + }; + } + + const result = await runSigningFlow({ + ctx, + mnemonic, + signWalletType: args.walletType, + signerIndex: args.signerIndex, + signerLabel: `signer${args.signerIndex}`, + signBroadcast: effectiveBroadcast, + preferredTransactionId: txId, + requireBroadcastSuccess: args.requireBroadcastSuccess, + }); + return { + message: `Certificate sign (${result.walletType}, signer${args.signerIndex}) status=${result.status} submitted=${String(result.submitted)}`, + artifacts: result as unknown as Record, + }; + }, + }; +} + +/** + * Builds the five steps for a single certificate action phase: + * 1. Propose tx via bot cert endpoint + * 2. Assert tx appears in pending + * 3. Signer 1 adds witness (no broadcast) + * 4. Signer 2 adds witness + broadcast + * 5. Assert tx cleared from pending (only when requireBroadcastSuccess=true) + * + * For staking cert (requireBroadcastSuccess=false): the staking certificate script + * uses stake key hashes (role-2), while signTransaction validates witnesses against + * the signer's payment key hash. Payment-key witnesses satisfy the spending script + * but cannot satisfy the separate stake-cert script, so broadcast will fail on-chain. + * Step 5 is omitted in that case. The test still validates that the API endpoint + * creates the pending transaction and that both signers can add witnesses. + */ +function createCertPhaseSteps(args: { + idPrefix: string; + walletType: CIWalletType; + certEndpoint: "botDRepCertificate" | "botStakeCertificate"; + action: string; + label: string; + runtime: { transactionId?: string; spentUtxoRefs?: { txHash: string; outputIndex: number }[] }; + requireBroadcastSuccess: boolean; + buildExtraBody?: (ctx: CIBootstrapContext) => Promise> | Record; + /** When true, each signing step uses the stake-cert flow (payment + stake witnesses). */ + useStakeCertFlow?: boolean; +}): RouteStep[] { + const { idPrefix, walletType, certEndpoint, action, label, runtime } = args; + + const steps: RouteStep[] = [ + // ── 1. Propose ─────────────────────────────────────────────────────────── + { + id: `${idPrefix}.propose`, + description: `Propose ${label}`, + severity: "critical", + execute: async (ctx) => { + const wallet = ctx.wallets.find((w) => w.type === walletType); + if (!wallet) { + throw new Error(`Wallet type "${walletType}" not found in CI context`); + } + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const utxoRefs = await fetchUtxoRefs({ + ctx, + walletId: wallet.walletId, + token, + botAddress: bot.paymentAddress, + fresh: true, + }); + + const extraBody = args.buildExtraBody ? await args.buildExtraBody(ctx) : {}; + const body: Record = { + walletId: wallet.walletId, + address: bot.paymentAddress, + action, + utxoRefs, + description: label, + ...extraBody, + }; + + const response = await requestJson<{ id?: string; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/${certEndpoint}`, + method: "POST", + token, + body, + }); + if (response.status !== 201 || !response.data?.id) { + throw new Error( + `${certEndpoint} (${action}) failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + runtime.transactionId = response.data.id; + runtime.spentUtxoRefs = utxoRefs; + return { + message: `${label} tx created (${runtime.transactionId})`, + artifacts: { walletId: wallet.walletId, transactionId: runtime.transactionId, action }, + }; + }, + }, + + // ── 2. Assert pending ───────────────────────────────────────────────────── + { + id: `${idPrefix}.pending`, + description: `Assert ${label} tx is pending`, + severity: "critical", + execute: async (ctx) => { + const txId = runtime.transactionId; + const wallet = ctx.wallets.find((w) => w.type === walletType); + if (!txId || !wallet) { + throw new Error(`Missing transaction id or wallet context for ${idPrefix}`); + } + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const response = await requestJson | { error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `pendingTransactions check failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + if (!response.data.some((tx) => tx.id === txId)) { + throw new Error(`Certificate tx ${txId} not found in pending transactions`); + } + return { + message: `${label} tx ${txId} is pending`, + artifacts: { transactionId: txId, pendingCount: response.data.length }, + }; + }, + }, + + // ── 3. Signer 1 witness (no broadcast) ─────────────────────────────────── + createCertSigningStep({ + id: `${idPrefix}.sign.signer1`, + description: `Signer 1 adds witness for ${label} (no broadcast)`, + signerIndex: 1, + mnemonicEnvName: "CI_MNEMONIC_2", + walletType, + signBroadcast: false, + requireBroadcastSuccess: false, + getTransactionId: () => runtime.transactionId, + useStakeCertFlow: args.useStakeCertFlow, + }), + + // ── 4. Signer 2 witness + broadcast ────────────────────────────────────── + createCertSigningStep({ + id: `${idPrefix}.sign.signer2`, + description: `Signer 2 signs and broadcasts ${label}`, + signerIndex: 2, + mnemonicEnvName: "CI_MNEMONIC_3", + walletType, + signBroadcast: true, + requireBroadcastSuccess: args.requireBroadcastSuccess, + getTransactionId: () => runtime.transactionId, + useStakeCertFlow: args.useStakeCertFlow, + }), + ]; + + // ── 5. Assert cleared (only when broadcast is required to succeed) ───────── + if (args.requireBroadcastSuccess) { + steps.push({ + id: `${idPrefix}.cleared`, + description: `Assert ${label} tx is cleared after broadcast`, + severity: "critical", + execute: async (ctx) => { + const txId = runtime.transactionId; + const wallet = ctx.wallets.find((w) => w.type === walletType); + if (!txId || !wallet) { + throw new Error(`Missing transaction id or wallet context for ${idPrefix}`); + } + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const response = await requestJson | { error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `pendingTransactions cleared check failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + if (response.data.some((tx) => tx.id === txId)) { + throw new Error(`Certificate tx ${txId} is still pending after sign+broadcast`); + } + return { + message: `${label} tx ${txId} cleared from pending`, + artifacts: { transactionId: txId, pendingCount: response.data.length }, + }; + }, + }); + + // ── 6. Wait for on-chain confirmation ───────────────────────────────────── + // The next cert phase needs confirmed UTxOs. Poll freeUtxos?fresh=true until + // the inputs spent by this tx are no longer visible (tx included in a block). + steps.push({ + id: `${idPrefix}.onchain`, + description: `Wait for ${label} tx inputs to be confirmed on-chain`, + severity: "critical", + execute: async (ctx) => { + const wallet = ctx.wallets.find((w) => w.type === walletType); + if (!wallet) { + throw new Error(`Wallet type "${walletType}" not found in CI context`); + } + const spentRefs = runtime.spentUtxoRefs ?? []; + if (spentRefs.length === 0) { + return { message: "No spent UTxO refs recorded; skipping on-chain confirmation wait", artifacts: {} }; + } + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const { attempts } = await pollUntilUtxosConsumed({ + ctx, + walletId: wallet.walletId, + token, + botAddress: bot.paymentAddress, + spentUtxoRefs: spentRefs, + }); + return { + message: `${label} inputs confirmed on-chain after ${attempts} poll attempt${attempts === 1 ? "" : "s"}`, + artifacts: { spentCount: spentRefs.length, attempts }, + }; + }, + }); + } + + return steps; +} + +/** + * Pre-hygiene step for a single wallet type: checks on-chain DRep state via + * GET /api/v1/drepInfo and deregisters if already registered, so the main + * register phase starts from a known clean state. + * + * Handles stale Blockfrost cache gracefully — if the broadcast is rejected + * with DRepNotRegistered or similar errors, the credential is confirmed clean + * and the step succeeds silently. + */ +function createDRepHygieneStep(walletType: CIWalletType): RouteStep { + return { + id: `v1.botDRepCertificate.${walletType}.hygiene`, + description: `Ensure ${walletType} DRep is deregistered before test`, + severity: "critical", + execute: async (ctx) => { + const wallet = ctx.wallets.find((w) => w.type === walletType); + if (!wallet) { + throw new Error(`Wallet type "${walletType}" not found in CI context`); + } + + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + + // Check on-chain DRep state. + const checkResp = await requestJson<{ active?: boolean; dRepId?: string; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/drepInfo?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (checkResp.status !== 200) { + throw new Error(`drepInfo failed (${checkResp.status}): ${stringifyRedacted(checkResp.data)}`); + } + if (!checkResp.data?.active) { + return { + message: `${walletType} DRep not registered on-chain; proceeding to main test`, + artifacts: { walletId: wallet.walletId, active: false, dRepId: checkResp.data?.dRepId }, + }; + } + + // DRep is registered — retire it. + const utxoRefs = await fetchUtxoRefs({ + ctx, + walletId: wallet.walletId, + token, + botAddress: bot.paymentAddress, + fresh: true, + }); + + const proposeResp = await requestJson<{ id?: string; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/botDRepCertificate`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + action: "retire", + utxoRefs, + description: "DRep retirement (hygiene)", + }, + }); + if (proposeResp.status !== 201 || !proposeResp.data?.id) { + throw new Error(`botDRepCertificate (hygiene retire) failed (${proposeResp.status}): ${stringifyRedacted(proposeResp.data)}`); + } + const txId = proposeResp.data.id; + + const mnemonic1 = process.env.CI_MNEMONIC_2; + const mnemonic2 = process.env.CI_MNEMONIC_3; + if (!mnemonic1?.trim()) throw new Error("CI_MNEMONIC_2 is required for hygiene signing"); + if (!mnemonic2?.trim()) throw new Error("CI_MNEMONIC_3 is required for hygiene signing"); + + // Signer 1 — no broadcast. + const sign1Result = await runSigningFlow({ + ctx, + mnemonic: mnemonic1, + signWalletType: walletType, + signerIndex: 1, + signerLabel: "signer1", + signBroadcast: false, + preferredTransactionId: txId, + requireBroadcastSuccess: false, + }); + console.log(`[drep-hygiene:${walletType}] signer1 sign: status=${sign1Result.status}`); + + // Signer 2 — broadcast. Catch stale-cache rejections: if Blockfrost reported the DRep + // as active but it is not actually registered on-chain, the node rejects the retire cert. + try { + const sign2Result = await runSigningFlow({ + ctx, + mnemonic: mnemonic2, + signWalletType: walletType, + signerIndex: 2, + signerLabel: "signer2", + signBroadcast: true, + preferredTransactionId: txId, + requireBroadcastSuccess: true, + }); + console.log(`[drep-hygiene:${walletType}] signer2 sign: status=${sign2Result.status} submitted=${String(sign2Result.submitted)}`); + } catch (err) { + const errMsg = String(err); + console.log(`[drep-hygiene:${walletType}] signer2 broadcast failed: ${errMsg.slice(0, 300)}`); + const isStaleCache = + errMsg.includes("DRepNotRegistered") || + errMsg.includes("DRepAlreadyRetired") || + errMsg.includes("VotingDRepsNotRegistered") || + errMsg.includes("ValueNotConservedUTxO") || + errMsg.includes("value is not balanced"); + if (isStaleCache) { + return { + message: `Hygiene DRep retire broadcast rejected — credential already deregistered (stale Blockfrost cache)`, + artifacts: { walletId: wallet.walletId, txId, staleCache: true }, + }; + } + throw err; + } + + // Broadcast succeeded — wait for on-chain confirmation before the register phase. + const { attempts } = await pollUntilUtxosConsumed({ + ctx, + walletId: wallet.walletId, + token, + botAddress: bot.paymentAddress, + spentUtxoRefs: utxoRefs, + }); + return { + message: `Hygiene DRep retire confirmed on-chain after ${attempts} poll attempt${attempts === 1 ? "" : "s"}`, + artifacts: { walletId: wallet.walletId, txId, attempts }, + }; + }, + }; +} + +/** + * DRep registration and retirement for legacy and SDK wallets. + * + * Legacy wallet: payment script doubles as the DRep credential script, so + * standard payment-key witnesses satisfy both spending inputs + * and the DRep certificate → full sign + broadcast. + * + * SDK wallet: the CI bootstrap sets signersDRepKeys = payment key hashes, + * so the DRep certificate script also uses payment key hashes. + * Standard payment-key witnesses satisfy both scripts + * → full sign + broadcast. + * + * Pre-hygiene deregisters if already registered, then register then retire, + * leaving the wallet in its pre-test DRep state. + * Requires CI_DREP_ANCHOR_URL to be set. + */ +export function createScenarioDRepCertificates(): Scenario { + const legacyReg: { transactionId?: string; spentUtxoRefs?: { txHash: string; outputIndex: number }[] } = {}; + const legacyRetire: { transactionId?: string; spentUtxoRefs?: { txHash: string; outputIndex: number }[] } = {}; + const sdkReg: { transactionId?: string; spentUtxoRefs?: { txHash: string; outputIndex: number }[] } = {}; + const sdkRetire: { transactionId?: string; spentUtxoRefs?: { txHash: string; outputIndex: number }[] } = {}; + + function buildDRepRegBody(): Record { + const anchorUrl = process.env.CI_DREP_ANCHOR_URL?.trim(); + if (!anchorUrl) { + throw new Error("CI_DREP_ANCHOR_URL is required for DRep registration"); + } + const anchorJsonRaw = process.env.CI_DREP_ANCHOR_JSON?.trim(); + if (!anchorJsonRaw) { + throw new Error("CI_DREP_ANCHOR_JSON is required for DRep registration"); + } + let anchorJson: object; + try { + anchorJson = JSON.parse(anchorJsonRaw) as object; + } catch { + throw new Error("CI_DREP_ANCHOR_JSON is not valid JSON"); + } + return { anchorUrl, anchorJson }; + } + + return { + id: "scenario.drep-certificates", + description: + "Register and retire DRep for legacy and SDK wallets, restoring pre-test state", + steps: [ + // Legacy: hygiene (deregister if already registered) + createDRepHygieneStep("legacy"), + // Legacy: register + ...createCertPhaseSteps({ + idPrefix: "v1.botDRepCertificate.legacy.register", + walletType: "legacy", + certEndpoint: "botDRepCertificate", + action: "register", + label: "DRep registration (legacy)", + runtime: legacyReg, + requireBroadcastSuccess: true, + buildExtraBody: () => buildDRepRegBody(), + }), + // Legacy: retire + ...createCertPhaseSteps({ + idPrefix: "v1.botDRepCertificate.legacy.retire", + walletType: "legacy", + certEndpoint: "botDRepCertificate", + action: "retire", + label: "DRep retirement (legacy)", + runtime: legacyRetire, + requireBroadcastSuccess: true, + }), + // SDK: hygiene (deregister if already registered) + createDRepHygieneStep("sdk"), + // SDK: register + ...createCertPhaseSteps({ + idPrefix: "v1.botDRepCertificate.sdk.register", + walletType: "sdk", + certEndpoint: "botDRepCertificate", + action: "register", + label: "DRep registration (sdk)", + runtime: sdkReg, + requireBroadcastSuccess: true, + buildExtraBody: () => buildDRepRegBody(), + }), + // SDK: retire + ...createCertPhaseSteps({ + idPrefix: "v1.botDRepCertificate.sdk.retire", + walletType: "sdk", + certEndpoint: "botDRepCertificate", + action: "retire", + label: "DRep retirement (sdk)", + runtime: sdkRetire, + requireBroadcastSuccess: true, + }), + ], + }; +} + +/** + * Stake register_and_delegate then deregister for the SDK wallet. + * + * Uses register_and_delegate rather than bare register because the production + * stakingCertificates.ts includes .certificateScript() on the register cert. + * In Conway era a bare register cert with a script witness causes + * ExtraneousScriptWitnessesUTXOW; register_and_delegate avoids this because + * the delegate cert legitimately requires the same staking script. + * + * Pre-hygiene: a single self-contained step checks on-chain state via + * stakeAccountInfo and deregisters if needed. It handles stale Blockfrost + * cache gracefully — if the broadcast is rejected with StakeKeyNotRegisteredDELEG, + * the credential is confirmed clean (the check was a false positive) and the + * step succeeds. Because freeUtxos.ts no longer blocks UTxOs for rejected txs, + * any failed deregister attempt does not block subsequent proposals. + * + * Requires ctx.stakePoolIdHex to be set (CI_STAKE_POOL_ID_HEX). + */ +export function createScenarioStakeCertificates(): Scenario { + const registerAndDelegateRuntime: { transactionId?: string; spentUtxoRefs?: { txHash: string; outputIndex: number }[] } = {}; + const deregisterRuntime: { transactionId?: string; spentUtxoRefs?: { txHash: string; outputIndex: number }[] } = {}; + + return { + id: "scenario.stake-certificates", + description: + "Register-and-delegate then deregister staking for SDK wallet, restoring pre-test state", + steps: [ + // ── Pre-hygiene: ensure credential is deregistered before test ───────── + // Single self-contained step — handles Blockfrost stale-cache gracefully. + { + id: "v1.botStakeCertificate.sdk.hygiene", + description: "Ensure SDK wallet stake credential is deregistered before test", + severity: "critical", + execute: async (ctx) => { + const stakeAddress = ctx.sdkStakeAddress; + if (!stakeAddress) { + return { + message: "sdkStakeAddress not in CI context; skipping hygiene", + artifacts: { skipped: true }, + }; + } + + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + + // Check on-chain state via the app's stakeAccountInfo proxy. + const checkResp = await requestJson<{ active?: boolean; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/stakeAccountInfo?stakeAddress=${encodeURIComponent(stakeAddress)}`, + method: "GET", + token, + }); + if (checkResp.status !== 200) { + throw new Error(`stakeAccountInfo failed (${checkResp.status}): ${stringifyRedacted(checkResp.data)}`); + } + if (!checkResp.data?.active) { + return { + message: "Stake credential not registered on-chain; proceeding to main test", + artifacts: { stakeAddress, active: false }, + }; + } + + // Credential is registered — deregister it. + const wallet = ctx.wallets.find((w) => w.type === "sdk"); + if (!wallet) throw new Error('SDK wallet not found in CI context'); + + const utxoRefs = await fetchUtxoRefs({ ctx, walletId: wallet.walletId, token, botAddress: bot.paymentAddress, fresh: true }); + + const proposeResp = await requestJson<{ id?: string; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/botStakeCertificate`, + method: "POST", + token, + body: { walletId: wallet.walletId, address: bot.paymentAddress, action: "deregister", utxoRefs, description: "Stake deregistration (hygiene)" }, + }); + if (proposeResp.status !== 201 || !proposeResp.data?.id) { + throw new Error(`botStakeCertificate (hygiene deregister) failed (${proposeResp.status}): ${stringifyRedacted(proposeResp.data)}`); + } + const txId = proposeResp.data.id; + + const mnemonic1 = process.env.CI_MNEMONIC_2; + const mnemonic2 = process.env.CI_MNEMONIC_3; + if (!mnemonic1?.trim()) throw new Error("CI_MNEMONIC_2 is required for hygiene signing"); + if (!mnemonic2?.trim()) throw new Error("CI_MNEMONIC_3 is required for hygiene signing"); + + // Signer 1 — no broadcast (same as main test's deregister phase). + const sign1Result = await runStakeCertSigningFlow({ ctx, mnemonic: mnemonic1, signerIndex: 1, signBroadcast: false, preferredTransactionId: txId, requireBroadcastSuccess: false }); + console.log(`[hygiene] signer1 sign: status=${sign1Result.status} stakeWitness=${String(sign1Result.stakeWitnessIncluded)}`); + + // Signer 2 — broadcast with requireBroadcastSuccess: true, matching the + // main test's deregister phase. Catch stale-cache errors (the credential + // was reported active by Blockfrost but is not actually registered on-chain: + // StakeKeyNotRegisteredDELEG + ValueNotConservedUTxO from the missing 2 ADA + // deposit refund) and treat them as "already clean". + try { + const sign2Result = await runStakeCertSigningFlow({ ctx, mnemonic: mnemonic2, signerIndex: 2, signBroadcast: true, preferredTransactionId: txId, requireBroadcastSuccess: true }); + console.log(`[hygiene] signer2 sign: status=${sign2Result.status} submitted=${String(sign2Result.submitted)} stakeWitness=${String(sign2Result.stakeWitnessIncluded)}`); + } catch (err) { + const errMsg = String(err); + console.log(`[hygiene] signer2 broadcast failed: ${errMsg.slice(0, 300)}`); + const isStaleCache = + errMsg.includes("StakeKeyNotRegisteredDELEG") || + errMsg.includes("StakeKeyAlreadyDeregistered") || + errMsg.includes("StakeKeyNotRegistered") || + errMsg.includes("ValueNotConservedUTxO") || + errMsg.includes("value is not balanced"); + if (isStaleCache) { + return { + message: "Hygiene deregister broadcast rejected — credential already deregistered (stale Blockfrost cache)", + artifacts: { stakeAddress, txId, staleCache: true }, + }; + } + throw err; + } + + // Broadcast succeeded — wait for on-chain confirmation. + const { attempts } = await pollUntilUtxosConsumed({ ctx, walletId: wallet.walletId, token, botAddress: bot.paymentAddress, spentUtxoRefs: utxoRefs }); + return { + message: `Hygiene deregister confirmed on-chain after ${attempts} poll attempt${attempts === 1 ? "" : "s"}`, + artifacts: { stakeAddress, txId, attempts }, + }; + }, + }, + + // ── Main test: register_and_delegate ───────────────────────────────── + // Uses register_and_delegate so the staking script witness required by + // the delegate cert prevents ExtraneousScriptWitnessesUTXOW on the + // register cert. Requires ctx.stakePoolIdHex (CI_STAKE_POOL_ID_HEX). + ...createCertPhaseSteps({ + idPrefix: "v1.botStakeCertificate.sdk.registerAndDelegate", + walletType: "sdk", + certEndpoint: "botStakeCertificate", + action: "register_and_delegate", + label: "Stake register-and-delegate (sdk)", + runtime: registerAndDelegateRuntime, + requireBroadcastSuccess: true, + useStakeCertFlow: true, + buildExtraBody: (ctx) => { + if (!ctx.stakePoolIdHex) { + throw new Error("ctx.stakePoolIdHex is required for register_and_delegate — set CI_STAKE_POOL_ID_HEX"); + } + return { poolId: ctx.stakePoolIdHex }; + }, + }), + + // ── Main test: deregister (restore pre-test state) ──────────────────── + ...createCertPhaseSteps({ + idPrefix: "v1.botStakeCertificate.sdk.deregister", + walletType: "sdk", + certEndpoint: "botStakeCertificate", + action: "deregister", + label: "Stake deregistration (sdk)", + runtime: deregisterRuntime, + requireBroadcastSuccess: true, + useStakeCertFlow: true, + }), + ], + }; +} diff --git a/scripts/ci/scenarios/steps/datum.ts b/scripts/ci/scenarios/steps/datum.ts new file mode 100644 index 00000000..9d6c2cc6 --- /dev/null +++ b/scripts/ci/scenarios/steps/datum.ts @@ -0,0 +1,74 @@ +import type { CIBootstrapContext, Scenario } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { stringifyRedacted } from "../../framework/redact"; +import { authenticateSignerWithMnemonic } from "../../framework/walletAuth"; +import { signDatumWithMnemonic } from "../../framework/datumSign"; +import { getWalletByType } from "./helpers"; + +export function createScenarioSubmitDatum(ctx: CIBootstrapContext): Scenario { + return { + id: "scenario.submit-datum", + description: "Datum submission route checks", + steps: ctx.walletTypes.map((walletType) => ({ + id: `v1.submitDatum.${walletType}.signer2`, + description: `Submit signed datum using signer auth token (${walletType} wallet)`, + severity: "critical" as const, + execute: async (runCtx: CIBootstrapContext) => { + const mnemonic = process.env.CI_MNEMONIC_2; + if (!mnemonic?.trim()) { + throw new Error("CI_MNEMONIC_2 is required for submitDatum scenario"); + } + const wallet = getWalletByType(runCtx, walletType); + if (!wallet) { + throw new Error(`Missing ${walletType} wallet for submitDatum scenario`); + } + const auth = await authenticateSignerWithMnemonic({ + ctx: runCtx, + mnemonic, + }); + const datum = JSON.stringify({ + source: "ci-route-chain", + kind: "submitDatum", + walletType: wallet.type, + walletId: wallet.walletId, + createdAt: new Date().toISOString(), + }); + const signedDatum = await signDatumWithMnemonic({ + ctx: runCtx, + mnemonic, + datum, + }); + if (signedDatum.signerAddress !== auth.signerAddress) { + throw new Error("Signer address mismatch between auth and datum signing"); + } + const response = await requestJson<{ id?: string; error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/submitDatum`, + method: "POST", + token: auth.token, + body: { + walletId: wallet.walletId, + signature: signedDatum.signature, + key: signedDatum.key, + address: auth.signerAddress, + datum, + callbackUrl: `${runCtx.apiBaseUrl}/api/v1/og`, + description: `CI submitDatum for ${wallet.type}`, + }, + }); + if (response.status !== 201 || !response.data?.id) { + throw new Error( + `submitDatum failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + return { + message: `submitDatum created signable ${response.data.id}`, + artifacts: { + signableId: response.data.id, + walletId: wallet.walletId, + signerAddress: auth.signerAddress, + }, + }; + }, + })), + }; +} diff --git a/scripts/ci/scenarios/steps/discovery.ts b/scripts/ci/scenarios/steps/discovery.ts new file mode 100644 index 00000000..74a9b4b8 --- /dev/null +++ b/scripts/ci/scenarios/steps/discovery.ts @@ -0,0 +1,250 @@ +import type { CIBootstrapContext, RouteStep, Scenario } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; +import { getWalletByType } from "./helpers"; + +function createWalletIdsStep(): RouteStep { + return { + id: "v1.walletIds.botAddress", + description: "Verify bot wallet discovery via /api/v1/walletIds", + severity: "critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const response = await requestJson | { error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/walletIds?address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error(`walletIds failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + + const ids = new Set( + response.data + .map((w) => (typeof w.walletId === "string" ? w.walletId : "")) + .filter(Boolean), + ); + const missing = ctx.wallets.map((w) => w.walletId).filter((id) => !ids.has(id)); + if (missing.length) { + throw new Error(`walletIds did not include expected wallets: ${missing.join(", ")}`); + } + + return { + message: `walletIds returned ${response.data.length} wallets and includes all bootstrap wallets`, + artifacts: { returnedWallets: response.data.length }, + }; + }, + }; +} + +function createPendingTransactionsZeroStep(walletType: string): RouteStep { + return { + id: `v1.pendingTransactions.zero.${walletType}`, + description: `Assert no pending transactions at bootstrap for ${walletType} wallet`, + severity: "non-critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const wallet = getWalletByType(ctx, walletType); + if (!wallet) { + throw new Error(`Missing wallet type in context: ${walletType}`); + } + const response = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `pendingTransactions zero-check failed for ${walletType} (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + if (response.data.length !== 0) { + throw new Error( + `pendingTransactions zero-check: expected 0 pending txs for ${walletType} at bootstrap, found ${response.data.length}. A previous CI run may have left stale state.`, + ); + } + return { + message: `pendingTransactions confirmed empty for ${walletType} at bootstrap`, + artifacts: { walletId: wallet.walletId, pendingCount: 0 }, + }; + }, + }; +} + +function createProxiesListStep(walletType: string): RouteStep { + return { + id: `v1.proxies.list.${walletType}`, + description: `List confirmed proxies for ${walletType} wallet`, + severity: "non-critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const wallet = getWalletByType(ctx, walletType); + if (!wallet) { + throw new Error(`Missing wallet type in context: ${walletType}`); + } + + const response = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/proxies?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `proxies list failed for ${walletType} (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + + return { + message: `proxies returned ${response.data.length} confirmed proxies for ${walletType}`, + artifacts: { walletId: wallet.walletId, proxyCount: response.data.length }, + }; + }, + }; +} + +function createLookupMultisigWalletStep(ctx: CIBootstrapContext): RouteStep { + return { + id: "v1.lookupMultisigWallet.signerKeyHash", + description: "Smoke-test public /api/v1/lookupMultisigWallet with a signer key hash", + severity: "non-critical", + execute: async (runCtx) => { + const signerAddress = runCtx.signerAddresses[0]; + if (!signerAddress) { + throw new Error("lookupMultisigWallet: no signer addresses in bootstrap context"); + } + const { resolvePaymentKeyHash } = await import("@meshsdk/core"); + const keyHash = resolvePaymentKeyHash(signerAddress); + const response = await requestJson({ + url: `${runCtx.apiBaseUrl}/api/v1/lookupMultisigWallet?pubKeyHashes=${encodeURIComponent(keyHash)}&network=${runCtx.networkId}`, + method: "GET", + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `lookupMultisigWallet failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + return { + message: `lookupMultisigWallet returned ${response.data.length} on-chain metadata entries for signer key hash`, + artifacts: { keyHash, matchCount: response.data.length }, + }; + }, + }; +} + +function createFreeUtxosStep(walletType: string): RouteStep { + return { + id: `v1.freeUtxos.${walletType}`, + description: `Probe free UTxOs route for ${walletType} wallet`, + severity: "non-critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const wallet = getWalletByType(ctx, walletType); + if (!wallet) { + throw new Error(`Missing wallet type in context: ${walletType}`); + } + const response = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/freeUtxos?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `freeUtxos failed for ${walletType} (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + return { + message: `freeUtxos returned ${response.data.length} entries for ${walletType}`, + artifacts: { walletId: wallet.walletId, utxoCount: response.data.length }, + }; + }, + }; +} + +function createNativeScriptStep(walletType: string): RouteStep { + return { + id: `v1.nativeScript.${walletType}`, + description: `Fetch and validate native scripts for ${walletType} wallet`, + severity: "non-critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const wallet = getWalletByType(ctx, walletType); + if (!wallet) { + throw new Error(`Missing wallet type in context: ${walletType}`); + } + const response = await requestJson | { error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/nativeScript?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `nativeScript failed for ${walletType} (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + if (response.data.length === 0) { + throw new Error(`nativeScript returned no scripts for ${walletType}`); + } + + // Assert a payment script entry is present + const paymentEntry = response.data.find((entry) => entry.type === "payment"); + if (!paymentEntry) { + throw new Error( + `nativeScript: no "payment" type entry for ${walletType}; got types: ${response.data.map((e) => e.type).join(", ")}`, + ); + } + + // If the decoded payment script is an atLeast type, validate the required count + const script = paymentEntry.script as Record | null | undefined; + if (script && typeof script === "object" && script.type === "atLeast" && typeof script.required === "number") { + const numRequired = parseInt(process.env.CI_NUM_REQUIRED_SIGNERS ?? "2", 10); + if (script.required !== numRequired) { + throw new Error( + `nativeScript: atLeast required=${script.required} does not match CI_NUM_REQUIRED_SIGNERS=${numRequired} for ${walletType}`, + ); + } + } + + return { + message: `nativeScript returned ${response.data.length} script entries for ${walletType} (payment script present)`, + artifacts: { + walletId: wallet.walletId, + walletType, + scriptCount: response.data.length, + scriptTypes: response.data.map((e) => e.type), + nativeScripts: response.data, + }, + }; + }, + }; +} + +export function createScenarioPendingAndDiscovery(ctx: CIBootstrapContext): Scenario { + return { + id: "scenario.wallet-discovery", + description: "Wallet discovery checks across bootstrap wallets", + steps: [ + createWalletIdsStep(), + ...ctx.walletTypes.map((walletType) => createPendingTransactionsZeroStep(walletType)), + ...ctx.walletTypes.map((walletType) => createProxiesListStep(walletType)), + createLookupMultisigWalletStep(ctx), + ], + }; +} + +export function createScenarioAdaRouteHealth(ctx: CIBootstrapContext): Scenario { + return { + id: "scenario.ada-route-health", + description: "Route chain for transfer readiness (freeUtxos + nativeScript)", + steps: [ + ...ctx.walletTypes.map((walletType) => createFreeUtxosStep(walletType)), + ...ctx.walletTypes.map((walletType) => createNativeScriptStep(walletType)), + ], + }; +} diff --git a/scripts/ci/scenarios/steps/governance.ts b/scripts/ci/scenarios/steps/governance.ts new file mode 100644 index 00000000..a2eb6f67 --- /dev/null +++ b/scripts/ci/scenarios/steps/governance.ts @@ -0,0 +1,131 @@ +import type { CIBootstrapContext, Scenario } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; +import { + buildBallotUpsertPayload, + getDeterministicActiveProposals, + type ActiveProposal, +} from "../../framework/governance"; +import { getWalletByType } from "./helpers"; + +export function createScenarioGovernanceRoutes(ctx: CIBootstrapContext): Scenario { + const runtime: { + activeProposals: ActiveProposal[]; + } = { + activeProposals: [], + }; + return { + id: "scenario.governance-routes", + description: "Governance route checks for active proposals and ballot upsert", + steps: [ + { + id: "v1.governanceActiveProposals.preprod", + description: "Fetch active governance proposals on preprod", + severity: "critical", + execute: async (runCtx) => { + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const response = await requestJson<{ + proposals?: unknown[]; + activeCount?: number; + sourceCount?: number; + error?: string; + }>({ + url: `${runCtx.apiBaseUrl}/api/v1/governanceActiveProposals?network=0&count=20&page=1&order=desc&details=false`, + method: "GET", + token, + }); + if (response.status !== 200) { + throw new Error( + `governanceActiveProposals failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + runtime.activeProposals = getDeterministicActiveProposals(response.data, 2); + return { + message: `governanceActiveProposals returned ${runtime.activeProposals.length} usable active proposal(s)`, + artifacts: { + activeCount: response.data?.activeCount, + sourceCount: response.data?.sourceCount, + selectedProposalIds: runtime.activeProposals.map((proposal) => proposal.proposalId), + }, + }; + }, + }, + ...ctx.walletTypes.map((walletType) => ({ + id: `v1.botBallotsUpsert.${walletType}`, + description: `Upsert governance ballots from active proposals (${walletType} wallet, idempotent update)`, + severity: "critical" as const, + execute: async (runCtx: CIBootstrapContext) => { + if (!runtime.activeProposals.length) { + return { + message: "No active proposals available on preprod; ballot upsert route skipped", + artifacts: { + skipped: true, + }, + }; + } + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const wallet = getWalletByType(runCtx, walletType); + if (!wallet) { + throw new Error(`Missing ${walletType} wallet for governance ballot upsert`); + } + const ballotName = `CI governance ballot ${runCtx.createdAt} ${walletType}`; + const firstPayload = buildBallotUpsertPayload({ + walletId: wallet.walletId, + ballotName, + proposals: runtime.activeProposals, + }); + const firstResponse = await requestJson<{ + ballot?: { id?: string; items?: string[]; choices?: string[] }; + error?: string; + }>({ + url: `${runCtx.apiBaseUrl}/api/v1/botBallotsUpsert`, + method: "POST", + token, + body: firstPayload as unknown as Record, + }); + if (firstResponse.status !== 200 || !firstResponse.data?.ballot?.id) { + throw new Error( + `botBallotsUpsert seed failed (${firstResponse.status}): ${stringifyRedacted(firstResponse.data)}`, + ); + } + const secondPayload = buildBallotUpsertPayload({ + walletId: wallet.walletId, + ballotName, + proposals: runtime.activeProposals, + secondPass: true, + }); + const secondResponse = await requestJson<{ + ballot?: { id?: string; items?: string[]; choices?: string[] }; + error?: string; + }>({ + url: `${runCtx.apiBaseUrl}/api/v1/botBallotsUpsert`, + method: "POST", + token, + body: secondPayload as unknown as Record, + }); + if (secondResponse.status !== 200 || !secondResponse.data?.ballot?.id) { + throw new Error( + `botBallotsUpsert update failed (${secondResponse.status}): ${stringifyRedacted(secondResponse.data)}`, + ); + } + if (secondResponse.data.ballot.id !== firstResponse.data.ballot.id) { + throw new Error("botBallotsUpsert update should target the same ballot"); + } + return { + message: `botBallotsUpsert updated ballot ${secondResponse.data.ballot.id}`, + artifacts: { + walletId: wallet.walletId, + ballotId: secondResponse.data.ballot.id, + proposalCount: runtime.activeProposals.length, + choices: secondResponse.data.ballot.choices ?? [], + }, + }; + }, + })), + ], + }; +} diff --git a/scripts/ci/scenarios/steps/helpers.ts b/scripts/ci/scenarios/steps/helpers.ts new file mode 100644 index 00000000..4b7816d9 --- /dev/null +++ b/scripts/ci/scenarios/steps/helpers.ts @@ -0,0 +1,17 @@ +import type { CIBootstrapContext, CIWalletType } from "../../framework/types"; + +export function getWalletByType(ctx: CIBootstrapContext, typeRaw: string) { + const type = typeRaw.trim().toLowerCase(); + return ctx.wallets.find((w) => w.type === type); +} + +export function getRingWalletTypes(ctx: CIBootstrapContext): [CIWalletType, CIWalletType, CIWalletType] { + const expected: CIWalletType[] = ["legacy", "hierarchical", "sdk"]; + const missing = expected.filter((walletType) => !ctx.wallets.some((wallet) => wallet.type === walletType)); + if (missing.length) { + throw new Error( + `Ring transfer scenario requires wallet types: legacy,hierarchical,sdk; missing: ${missing.join(", ")}`, + ); + } + return ["legacy", "hierarchical", "sdk"]; +} diff --git a/scripts/ci/scenarios/steps/proxyBot.ts b/scripts/ci/scenarios/steps/proxyBot.ts new file mode 100644 index 00000000..680212ed --- /dev/null +++ b/scripts/ci/scenarios/steps/proxyBot.ts @@ -0,0 +1,1541 @@ +import type { CIBootstrapContext, CIWalletType, RouteStep, Scenario } from "../../framework/types"; +import { boolFromEnv } from "../../framework/env"; +import { requestJson } from "../../framework/http"; +import { authenticateBot } from "../../framework/botAuth"; +import { getDefaultBot } from "../../framework/botContext"; +import { stringifyRedacted } from "../../framework/redact"; +import { getDeterministicActiveProposals, type ActiveProposal } from "../../framework/governance"; +import { runSigningFlow } from "../flows/signingFlow"; +import { ensureProxyLifecycleUtxoShape } from "../flows/utxoShapeFlow"; +import { recoverProxyRowsFromChainForWalletType } from "../proxyChainRecovery"; +import { adoptProxyOrphansForWalletType } from "../proxyOrphanAdoption"; +import { getWalletByType } from "./helpers"; +import { + assertProxyFullLifecyclePreflight, + COLLATERAL_REQUIRED_LOVELACE, + DREP_REGISTER_REQUIRED_LOVELACE, + formatAda, + FULL_LIFECYCLE_FEE_BUFFER_LOVELACE, + key, + LIFECYCLE_PROXY_LOVELACE, + parseLovelace, + PROXY_FULL_LIFECYCLE_WALLET_TYPES, + PROXY_SPEND_LOVELACE, + sameRef, + SETUP_UTXO_REQUIRED_LOVELACE, + toRef, + type ScriptUtxo, + type UtxoRef, +} from "../proxyLifecyclePreflight"; + +export { + analyzeProxyFullLifecycleUtxoShape, + assertProxyFullLifecyclePreflight, + DREP_REGISTER_REQUIRED_LOVELACE, + FULL_LIFECYCLE_FEE_BUFFER_LOVELACE, + LIFECYCLE_PROXY_LOVELACE, + PROXY_FULL_LIFECYCLE_WALLET_TYPES, + type ProxyLifecycleUtxoShapeAnalysis, + type ProxyLifecycleUtxoShapeStatus, + type ScriptUtxo, + type UtxoRef, +} from "../proxyLifecyclePreflight"; + +type ProxyRow = { id: string; proxyAddress: string; authTokenId: string; isActive?: boolean }; +type ProxySetup = { proxyAddress: string; authTokenId: string; paramUtxo: UtxoRef }; +type ProxyActionRequestRefs = { utxoRefs: UtxoRef[]; collateralRef: UtxoRef }; +type ProxyActionSelection = ProxyActionRequestRefs & Record; +type ProxyDRepInfoResponse = { active: boolean; dRepId: string; error?: string }; +type ProxyLifecycleSignerIndex = 0 | 1 | 2; +type ProxyLifecycleMnemonicEnvName = "CI_MNEMONIC_1" | "CI_MNEMONIC_2" | "CI_MNEMONIC_3"; + +const PROXY_LIFECYCLE_COLLATERAL_SIGNER_INDEX = 0; +const PROXY_LIFECYCLE_SIGNER_INDEXES = [0, 1] as const; +export const PROXY_ACTION_REQUIRED_LOVELACE = 2_000_000n; +export const PROXY_ACTION_FEE_BUFFER_LOVELACE = 2_000_000n; + +export function getProxyDRepAnchorUrl( + env: Record = process.env, +): string { + const anchorUrl = env.CI_DREP_ANCHOR_URL?.trim(); + if (!anchorUrl) { + throw new Error("CI_DREP_ANCHOR_URL is required for proxy DRep registration"); + } + return anchorUrl; +} + +function getTransactionId(data: unknown): string | undefined { + if (typeof data === "object" && data !== null) { + const record = data as Record; + if (typeof record.id === "string") return record.id; + return getTransactionId(record.transaction); + } + return undefined; +} + +function getSubmittedTxHash(data: unknown): string | undefined { + if (typeof data === "string") return data; + if (typeof data === "object" && data !== null) { + const record = data as Record; + if (typeof record.txHash === "string") return record.txHash; + return getSubmittedTxHash(record.transaction); + } + return undefined; +} + +function getCleanupPhase(data: unknown): "sweep" | "burn" | undefined { + if (typeof data === "object" && data !== null) { + const record = data as Record; + const cleanup = record.cleanup; + if (typeof cleanup === "object" && cleanup !== null) { + const phase = (cleanup as Record).phase; + if (phase === "sweep" || phase === "burn") return phase; + } + } + return undefined; +} + +export function normalizeJsonArtifact(value: unknown): unknown { + if (typeof value === "bigint") return value.toString(); + if (Array.isArray(value)) return value.map(normalizeJsonArtifact); + if (typeof value === "object" && value !== null) { + return Object.fromEntries( + Object.entries(value).map(([key, child]) => [key, normalizeJsonArtifact(child)]), + ); + } + return value; +} + +export function splitProxyActionSelection(selection: ProxyActionSelection): { + requestRefs: ProxyActionRequestRefs; + selectionArtifacts: Record; +} { + const { utxoRefs, collateralRef, ...selectionArtifacts } = selection; + return { + requestRefs: { utxoRefs, collateralRef }, + selectionArtifacts: normalizeJsonArtifact(selectionArtifacts) as Record, + }; +} + +export function shouldSkipCleanupBurnPropose(runtime: { + cleanupPhase?: "sweep" | "burn"; + cleanupBurnTransactionId?: string; +}): boolean { + return runtime.cleanupPhase === "burn" && !runtime.cleanupBurnTransactionId; +} + +export function shouldSkipCleanupBurnSigning(runtime: { + cleanupBurnSkipped?: boolean; + cleanupBurnTransactionId?: string; +}): boolean { + return runtime.cleanupBurnSkipped === true || !runtime.cleanupBurnTransactionId; +} + +export function shouldSkipActionConfirmation(runtime: { + actionTransactionId?: string; + actionUtxoRefs?: UtxoRef[]; +}): boolean { + return !runtime.actionTransactionId || !runtime.actionUtxoRefs?.length; +} + +async function fetchFreeUtxos(args: { + ctx: CIBootstrapContext; + walletId: string; + token: string; + address: string; + fresh?: boolean; +}): Promise { + const fresh = args.fresh ? "&fresh=true" : ""; + const response = await requestJson({ + url: `${args.ctx.apiBaseUrl}/api/v1/freeUtxos?walletId=${encodeURIComponent(args.walletId)}&address=${encodeURIComponent(args.address)}${fresh}`, + method: "GET", + token: args.token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error(`freeUtxos failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + return response.data; +} + +async function fetchKeyAddressUtxos(args: { + ctx: CIBootstrapContext; + address: string; +}): Promise { + const apiKey = process.env.CI_BLOCKFROST_PREPROD_API_KEY?.trim(); + if (!apiKey) { + throw new Error("CI_BLOCKFROST_PREPROD_API_KEY is required to fetch proxy lifecycle key-address collateral"); + } + if (args.ctx.networkId !== 0) { + throw new Error(`Proxy lifecycle key collateral lookup is preprod-only. Expected networkId=0, received networkId=${args.ctx.networkId}`); + } + + const { BlockfrostProvider } = await import("@meshsdk/core"); + const provider = new BlockfrostProvider(apiKey); + const utxos = await provider.fetchAddressUTxOs(args.address); + return utxos.map((utxo) => ({ + input: utxo.input, + output: utxo.output, + })); +} + +function isAdaOnlyCollateral(utxo: ScriptUtxo): boolean { + return ( + parseLovelace(utxo) >= COLLATERAL_REQUIRED_LOVELACE && + utxo.output.amount.every((asset) => asset.unit === "lovelace") + ); +} + +function selectSeparateCollateral( + utxos: ScriptUtxo[], + context: string, +): ScriptUtxo { + const collateral = [...utxos] + .filter(isAdaOnlyCollateral) + .sort((left, right) => { + const leftLovelace = parseLovelace(left); + const rightLovelace = parseLovelace(right); + if (leftLovelace < rightLovelace) return -1; + if (leftLovelace > rightLovelace) return 1; + return 0; + })[0]; + if (!collateral) { + throw new Error( + `${context} requires an ADA-only bot payment-address collateral UTxO with at least ${formatAda(COLLATERAL_REQUIRED_LOVELACE)}`, + ); + } + return collateral; +} + +export function selectSetupRefs(args: { + walletUtxos: ScriptUtxo[]; + collateralUtxos: ScriptUtxo[]; +}): { utxoRefs: UtxoRef[]; collateralRef: UtxoRef } { + const setupUtxo = args.walletUtxos.find((utxo) => parseLovelace(utxo) >= SETUP_UTXO_REQUIRED_LOVELACE); + if (!setupUtxo) { + throw new Error(`proxy setup requires a wallet UTxO with at least ${formatAda(SETUP_UTXO_REQUIRED_LOVELACE)}`); + } + const setupRef = toRef(setupUtxo); + const collateral = selectSeparateCollateral(args.collateralUtxos, "proxy setup"); + return { utxoRefs: [setupRef], collateralRef: toRef(collateral) }; +} + +export function selectAuthTokenRefs(args: { + walletUtxos: ScriptUtxo[]; + collateralUtxos: ScriptUtxo[]; + authTokenId: string; + includeAllAuthTokens?: boolean; +}): { utxoRefs: UtxoRef[]; collateralRef: UtxoRef } { + const authTokenUtxos = args.walletUtxos.filter((utxo) => + utxo.output.amount.some((asset) => asset.unit === args.authTokenId && BigInt(asset.quantity) > 0n), + ); + if (!authTokenUtxos.length) { + throw new Error("No proxy auth-token UTxO found in freeUtxos response"); + } + const spendUtxos = args.includeAllAuthTokens ? authTokenUtxos : [authTokenUtxos[0]!]; + const refs = spendUtxos.map(toRef); + const collateral = selectSeparateCollateral(args.collateralUtxos, "proxy action"); + return { utxoRefs: refs, collateralRef: toRef(collateral) }; +} + +export function selectDRepRegisterRefs(args: { + walletUtxos: ScriptUtxo[]; + collateralUtxos: ScriptUtxo[]; + authTokenId: string; + requiredLovelace?: bigint; +}): { utxoRefs: UtxoRef[]; collateralRef: UtxoRef; selectedLovelace: bigint; requiredLovelace: bigint } { + const requiredLovelace = args.requiredLovelace ?? DREP_REGISTER_REQUIRED_LOVELACE; + const authTokenUtxo = args.walletUtxos.find((utxo) => + utxo.output.amount.some((asset) => asset.unit === args.authTokenId && BigInt(asset.quantity) > 0n), + ); + if (!authTokenUtxo) { + throw new Error("No proxy auth-token UTxO found in freeUtxos response"); + } + + const authRef = toRef(authTokenUtxo); + const collateral = selectSeparateCollateral(args.collateralUtxos, "proxy DRep register"); + const collateralRef = toRef(collateral); + const selectedRefs = [authRef]; + let selectedLovelace = parseLovelace(authTokenUtxo); + const fundingCandidates = [...args.walletUtxos] + .filter((utxo) => { + const ref = toRef(utxo); + return !sameRef(ref, authRef); + }) + .sort((left, right) => { + const leftLovelace = parseLovelace(left); + const rightLovelace = parseLovelace(right); + if (leftLovelace > rightLovelace) return -1; + if (leftLovelace < rightLovelace) return 1; + return 0; + }); + + for (const utxo of fundingCandidates) { + if (selectedLovelace >= requiredLovelace) break; + selectedRefs.push(toRef(utxo)); + selectedLovelace += parseLovelace(utxo); + } + + if (selectedLovelace < requiredLovelace) { + throw new Error( + `proxy DRep register requires ${formatAda(requiredLovelace)} in selected wallet inputs but only ${formatAda(selectedLovelace)} is available after reserving separate collateral. Fund or consolidate the CI wallet before running scenario.proxy-full-lifecycle.`, + ); + } + + return { + utxoRefs: selectedRefs, + collateralRef, + selectedLovelace, + requiredLovelace, + }; +} + +export function selectAuthTokenRefsWithMinLovelace(args: { + walletUtxos: ScriptUtxo[]; + collateralUtxos: ScriptUtxo[]; + authTokenId: string; + requiredLovelace: bigint; + context: string; +}): { utxoRefs: UtxoRef[]; collateralRef: UtxoRef; selectedLovelace: bigint; requiredLovelace: bigint } { + const authTokenUtxo = args.walletUtxos.find((utxo) => + utxo.output.amount.some((asset) => asset.unit === args.authTokenId && BigInt(asset.quantity) > 0n), + ); + if (!authTokenUtxo) { + throw new Error("No proxy auth-token UTxO found in freeUtxos response"); + } + + const authRef = toRef(authTokenUtxo); + const collateral = selectSeparateCollateral(args.collateralUtxos, args.context); + const collateralRef = toRef(collateral); + const selectedRefs = [authRef]; + let selectedLovelace = parseLovelace(authTokenUtxo); + const fundingCandidates = [...args.walletUtxos] + .filter((utxo) => { + const ref = toRef(utxo); + return !sameRef(ref, authRef); + }) + .sort((left, right) => { + const leftLovelace = parseLovelace(left); + const rightLovelace = parseLovelace(right); + if (leftLovelace > rightLovelace) return -1; + if (leftLovelace < rightLovelace) return 1; + return 0; + }); + + for (const utxo of fundingCandidates) { + if (selectedLovelace >= args.requiredLovelace) break; + selectedRefs.push(toRef(utxo)); + selectedLovelace += parseLovelace(utxo); + } + + if (selectedLovelace < args.requiredLovelace) { + throw new Error( + `${args.context} requires ${formatAda(args.requiredLovelace)} in selected wallet inputs but only ${formatAda(selectedLovelace)} is available after reserving separate collateral. Fund or consolidate the CI wallet before running scenario.proxy-full-lifecycle.`, + ); + } + + return { + utxoRefs: selectedRefs, + collateralRef, + selectedLovelace, + requiredLovelace: args.requiredLovelace, + }; +} + +async function pollUntilUtxosConsumed(args: { + ctx: CIBootstrapContext; + walletId: string; + token: string; + address: string; + spentUtxoRefs: UtxoRef[]; + maxRetries?: number; + retryDelayMs?: number; +}): Promise<{ attempts: number }> { + const maxRetries = args.maxRetries ?? 30; + const retryDelayMs = args.retryDelayMs ?? 8000; + const spent = new Set(args.spentUtxoRefs.map(key)); + for (let attempt = 0; attempt < maxRetries; attempt++) { + if (attempt > 0) { + await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); + } + const utxos = await fetchFreeUtxos({ ...args, fresh: true }); + if (!utxos.some((utxo) => spent.has(key(toRef(utxo))))) { + return { attempts: attempt + 1 }; + } + } + throw new Error(`Timed out waiting for proxy transaction inputs to be confirmed`); +} + +type ProxyLifecycleHygieneDeps = { + requestJson: typeof requestJson; + authenticateBot: typeof authenticateBot; + getDefaultBot: typeof getDefaultBot; + fetchFreeUtxos: typeof fetchFreeUtxos; + fetchKeyAddressUtxos: typeof fetchKeyAddressUtxos; + runSigningFlow: typeof runSigningFlow; + pollUntilUtxosConsumed: typeof pollUntilUtxosConsumed; + env: Record; +}; + +const defaultProxyLifecycleHygieneDeps: ProxyLifecycleHygieneDeps = { + requestJson, + authenticateBot, + getDefaultBot, + fetchFreeUtxos, + fetchKeyAddressUtxos, + runSigningFlow, + pollUntilUtxosConsumed, + env: process.env, +}; + +async function listActiveProxies(args: { + ctx: CIBootstrapContext; + walletId: string; + address: string; + token: string; + requestJsonFn: typeof requestJson; +}): Promise { + const response = await args.requestJsonFn({ + url: `${args.ctx.apiBaseUrl}/api/v1/proxies?walletId=${encodeURIComponent(args.walletId)}&address=${encodeURIComponent(args.address)}`, + method: "GET", + token: args.token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error(`proxies list failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + return response.data; +} + +async function fetchProxyDRepInfo(args: { + ctx: CIBootstrapContext; + walletId: string; + address: string; + proxyId: string; + token: string; + requestJsonFn: typeof requestJson; +}): Promise { + const response = await args.requestJsonFn({ + url: `${args.ctx.apiBaseUrl}/api/v1/proxyDRepInfo?walletId=${encodeURIComponent(args.walletId)}&address=${encodeURIComponent(args.address)}&proxyId=${encodeURIComponent(args.proxyId)}`, + method: "GET", + token: args.token, + }); + if (response.status !== 200 || typeof response.data?.active !== "boolean" || typeof response.data?.dRepId !== "string") { + throw new Error(`proxyDRepInfo failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + return response.data; +} + +export async function runProxyFullLifecycleHygiene(args: { + ctx: CIBootstrapContext; + walletType: CIWalletType; + deps?: Partial; +}): Promise<{ message: string; artifacts: Record }> { + const deps = { ...defaultProxyLifecycleHygieneDeps, ...args.deps }; + const wallet = getWalletByType(args.ctx, args.walletType); + if (!wallet) throw new Error(`Missing ${args.walletType} wallet`); + const bot = deps.getDefaultBot(args.ctx); + const token = await deps.authenticateBot({ ctx: args.ctx, bot }); + const initialProxies = await listActiveProxies({ + ctx: args.ctx, + walletId: wallet.walletId, + address: bot.paymentAddress, + token, + requestJsonFn: deps.requestJson, + }); + + if (!initialProxies.length) { + return { + message: `proxy full lifecycle hygiene found no active proxies for ${args.walletType}`, + artifacts: { walletId: wallet.walletId, cleaned: [], noOp: true }, + }; + } + + const cleaned: Record[] = []; + const signer0Mnemonic = deps.env.CI_MNEMONIC_1; + const signer1Mnemonic = deps.env.CI_MNEMONIC_2; + if (!signer0Mnemonic?.trim()) throw new Error("CI_MNEMONIC_1 is required for proxy lifecycle hygiene signing"); + if (!signer1Mnemonic?.trim()) throw new Error("CI_MNEMONIC_2 is required for proxy lifecycle hygiene signing"); + + for (const proxy of initialProxies) { + let finalTxHash: string | undefined; + let finalTransactionId: string | undefined; + let finalPhase: "sweep" | "burn" | undefined; + const cleanupTransactions: Record[] = []; + let dRepDeregisterTransaction: Record | undefined; + + const dRepInfo = await fetchProxyDRepInfo({ + ctx: args.ctx, + walletId: wallet.walletId, + address: bot.paymentAddress, + proxyId: proxy.id, + token, + requestJsonFn: deps.requestJson, + }); + if (dRepInfo.active) { + const [walletUtxos, collateralUtxos] = await Promise.all([ + deps.fetchFreeUtxos({ + ctx: args.ctx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + fresh: true, + }), + deps.fetchKeyAddressUtxos({ ctx: args.ctx, address: bot.paymentAddress }), + ]); + const selection = selectAuthTokenRefsWithMinLovelace({ + walletUtxos, + collateralUtxos, + authTokenId: proxy.authTokenId, + requiredLovelace: PROXY_ACTION_REQUIRED_LOVELACE + PROXY_ACTION_FEE_BUFFER_LOVELACE, + context: "proxy hygiene DRep deregister", + }); + const { requestRefs, selectionArtifacts } = splitProxyActionSelection(selection); + const response = await deps.requestJson({ + url: `${args.ctx.apiBaseUrl}/api/v1/proxyDRepCertificate`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + proxyId: proxy.id, + ...requestRefs, + action: "deregister", + description: `CI proxy full lifecycle hygiene DRep deregister (${args.walletType})`, + }, + }); + if (response.status !== 201) { + throw new Error(`proxyDRepCertificate hygiene failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + + const txId = getTransactionId(response.data); + if (!txId) { + throw new Error(`proxyDRepCertificate hygiene response did not include a transaction id: ${stringifyRedacted(response.data)}`); + } + let txHash = getSubmittedTxHash(response.data); + + const signer0Result = await deps.runSigningFlow({ + ctx: args.ctx, + mnemonic: signer0Mnemonic, + signWalletType: args.walletType, + signerIndex: 0, + signBroadcast: false, + preferredTransactionId: txId, + requireBroadcastSuccess: false, + }); + const signer1Result = await deps.runSigningFlow({ + ctx: args.ctx, + mnemonic: signer1Mnemonic, + signWalletType: args.walletType, + signerIndex: 1, + signBroadcast: true, + preferredTransactionId: txId, + requireBroadcastSuccess: true, + }); + txHash = signer1Result.txHash ?? txHash; + + const confirmation = await deps.pollUntilUtxosConsumed({ + ctx: args.ctx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + spentUtxoRefs: requestRefs.utxoRefs, + }); + dRepDeregisterTransaction = { + dRepId: dRepInfo.dRepId, + transactionId: txId, + txHash, + selectedUtxoRefs: requestRefs.utxoRefs, + selectionArtifacts, + confirmationAttempts: confirmation.attempts, + signer0Status: signer0Result.status, + signer1Status: signer1Result.status, + }; + } + + for (let pass = 0; pass < 2; pass += 1) { + const [walletUtxos, collateralUtxos] = await Promise.all([ + deps.fetchFreeUtxos({ + ctx: args.ctx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + fresh: true, + }), + deps.fetchKeyAddressUtxos({ ctx: args.ctx, address: bot.paymentAddress }), + ]); + const selection = selectAuthTokenRefs({ + walletUtxos, + collateralUtxos, + authTokenId: proxy.authTokenId, + includeAllAuthTokens: true, + }); + const response = await deps.requestJson({ + url: `${args.ctx.apiBaseUrl}/api/v1/proxyCleanup`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + proxyId: proxy.id, + ...selection, + deactivateProxy: true, + description: `CI proxy full lifecycle hygiene (${args.walletType})`, + }, + }); + if (response.status !== 201) { + throw new Error(`proxyCleanup hygiene failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + + const txId = getTransactionId(response.data); + if (!txId) { + throw new Error(`proxyCleanup hygiene response did not include a transaction id: ${stringifyRedacted(response.data)}`); + } + finalTransactionId = txId; + finalTxHash = getSubmittedTxHash(response.data); + finalPhase = getCleanupPhase(response.data); + + const signer0Result = await deps.runSigningFlow({ + ctx: args.ctx, + mnemonic: signer0Mnemonic, + signWalletType: args.walletType, + signerIndex: 0, + signBroadcast: false, + preferredTransactionId: txId, + requireBroadcastSuccess: false, + }); + const signer1Result = await deps.runSigningFlow({ + ctx: args.ctx, + mnemonic: signer1Mnemonic, + signWalletType: args.walletType, + signerIndex: 1, + signBroadcast: true, + preferredTransactionId: txId, + requireBroadcastSuccess: true, + }); + finalTxHash = signer1Result.txHash ?? finalTxHash; + + const confirmation = await deps.pollUntilUtxosConsumed({ + ctx: args.ctx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + spentUtxoRefs: selection.utxoRefs, + }); + cleanupTransactions.push({ + phase: finalPhase, + transactionId: txId, + txHash: finalTxHash, + selectedUtxoRefs: selection.utxoRefs, + confirmationAttempts: confirmation.attempts, + signer0Status: signer0Result.status, + signer1Status: signer1Result.status, + }); + + if (finalPhase === "burn") break; + } + + if (finalPhase !== "burn") { + throw new Error(`proxy hygiene could not reach burn phase for active proxy ${proxy.id}`); + } + + const finalizeResponse = await deps.requestJson<{ proxy?: ProxyRow; error?: string }>({ + url: `${args.ctx.apiBaseUrl}/api/v1/proxyCleanupFinalize`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + proxyId: proxy.id, + txHash: finalTxHash ?? finalTransactionId ?? "submitted", + }, + retries: 3, + }); + if (finalizeResponse.status !== 201 || finalizeResponse.data?.proxy?.isActive !== false) { + throw new Error(`proxyCleanupFinalize hygiene failed (${finalizeResponse.status}): ${stringifyRedacted(finalizeResponse.data)}`); + } + + const remainingProxies = await listActiveProxies({ + ctx: args.ctx, + walletId: wallet.walletId, + address: bot.paymentAddress, + token, + requestJsonFn: deps.requestJson, + }); + if (remainingProxies.some((candidate) => candidate.id === proxy.id)) { + throw new Error(`hygiene-cleaned proxy ${proxy.id} is still listed as active`); + } + + cleaned.push({ + proxyId: proxy.id, + authTokenId: proxy.authTokenId, + proxyAddress: proxy.proxyAddress, + dRep: { + dRepId: dRepInfo.dRepId, + wasActive: dRepInfo.active, + deregisterTransaction: dRepDeregisterTransaction, + }, + finalTxHash, + cleanupTransactions, + }); + } + + return { + message: `proxy full lifecycle hygiene cleaned ${cleaned.length} active proxy/proxies for ${args.walletType}`, + artifacts: normalizeJsonArtifact({ walletId: wallet.walletId, cleaned, noOp: false }) as Record, + }; +} + +function createExpectedStatusStep(args: { + id: string; + description: string; + method: "GET" | "POST"; + url: (ctx: CIBootstrapContext) => string; + token?: (ctx: CIBootstrapContext) => Promise; + body?: (ctx: CIBootstrapContext) => Record; + expectedStatus: number; + validate?: (data: unknown) => void; +}): RouteStep { + return { + id: args.id, + description: args.description, + severity: "critical", + execute: async (ctx) => { + const token = args.token ? await args.token(ctx) : undefined; + const response = await requestJson<{ error?: string }>({ + url: args.url(ctx), + method: args.method, + token, + body: args.body?.(ctx), + }); + if (response.status !== args.expectedStatus) { + throw new Error( + `${args.id} expected ${args.expectedStatus}, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + args.validate?.(response.data); + return { message: `${args.id} returned expected ${args.expectedStatus}` }; + }, + }; +} + +export function createScenarioProxySmoke(ctx: CIBootstrapContext): Scenario { + return { + id: "scenario.proxy-smoke", + description: "Proxy bot API smoke and negative validation checks", + steps: [ + ...ctx.walletTypes.map((walletType) => { + const wallet = getWalletByType(ctx, walletType); + return createExpectedStatusStep({ + id: `v1.proxies.missingToken.${walletType}`, + description: `Assert /api/v1/proxies rejects missing token (${walletType})`, + method: "GET", + url: (runCtx) => { + const target = wallet ?? getWalletByType(runCtx, walletType); + if (!target) throw new Error(`Missing ${walletType} wallet`); + const address = target.signerAddresses[0] ?? runCtx.signerAddresses[0] ?? ""; + return `${runCtx.apiBaseUrl}/api/v1/proxies?walletId=${encodeURIComponent(target.walletId)}&address=${encodeURIComponent(address)}`; + }, + expectedStatus: 401, + }); + }), + ...ctx.walletTypes.map((walletType) => + createExpectedStatusStep({ + id: `v1.proxies.list.${walletType}`, + description: `Assert /api/v1/proxies returns active proxy list (${walletType})`, + method: "GET", + token: async (runCtx) => authenticateBot({ ctx: runCtx, bot: getDefaultBot(runCtx) }), + url: (runCtx) => { + const wallet = getWalletByType(runCtx, walletType); + if (!wallet) throw new Error(`Missing ${walletType} wallet`); + const bot = getDefaultBot(runCtx); + return `${runCtx.apiBaseUrl}/api/v1/proxies?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`; + }, + expectedStatus: 200, + validate: (data) => { + if (!Array.isArray(data)) { + throw new Error(`v1.proxies.list.${walletType} expected array response: ${stringifyRedacted(data)}`); + } + }, + }), + ), + ...ctx.walletTypes.map((walletType) => + createExpectedStatusStep({ + id: `v1.proxies.addressMismatch.${walletType}`, + description: `Assert /api/v1/proxies rejects address mismatch (${walletType})`, + method: "GET", + token: async (runCtx) => authenticateBot({ ctx: runCtx, bot: getDefaultBot(runCtx) }), + url: (runCtx) => { + const wallet = getWalletByType(runCtx, walletType); + if (!wallet) throw new Error(`Missing ${walletType} wallet`); + const bot = getDefaultBot(runCtx); + const mismatch = runCtx.bots.find((candidate) => candidate.id !== bot.id)?.paymentAddress ?? `${bot.paymentAddress}x`; + return `${runCtx.apiBaseUrl}/api/v1/proxies?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(mismatch)}`; + }, + expectedStatus: 403, + }), + ), + ...[ + "proxySetup", + "proxySetupFinalize", + "proxySpend", + "proxyDRepCertificate", + "proxyVote", + "proxyCleanup", + "proxyCleanupFinalize", + ].map((route) => + createExpectedStatusStep({ + id: `v1.${route}.malformedBody`, + description: `Assert /api/v1/${route} rejects malformed body before chain work`, + method: "POST", + token: async (runCtx) => authenticateBot({ ctx: runCtx, bot: getDefaultBot(runCtx) }), + url: (runCtx) => `${runCtx.apiBaseUrl}/api/v1/${route}`, + body: (runCtx) => ({ + walletId: runCtx.wallets[0]?.walletId ?? "missing-wallet", + address: getDefaultBot(runCtx).paymentAddress, + ...(route === "proxySetup" ? { initialProxyLovelace: "0" } : {}), + }), + expectedStatus: 400, + }), + ), + ], + }; +} + +function createSignStep(args: { + id: string; + description: string; + walletType: CIWalletType; + signerIndex: ProxyLifecycleSignerIndex; + mnemonicEnvName: ProxyLifecycleMnemonicEnvName; + signBroadcast: boolean; + getTransactionId: () => string | undefined; + setTxHash?: (txHash: string | undefined) => void; + shouldSkip?: () => boolean; +}): RouteStep { + return { + id: args.id, + description: args.description, + severity: "critical", + execute: async (ctx) => { + if (args.shouldSkip?.()) { + return { message: "Signing skipped", artifacts: { skipped: true } }; + } + const txId = args.getTransactionId(); + if (!txId) { + return { message: "No pending transaction id; signing skipped", artifacts: { skipped: true } }; + } + const mnemonic = process.env[args.mnemonicEnvName]; + if (!mnemonic?.trim()) { + throw new Error(`${args.mnemonicEnvName} is required for proxy lifecycle signing`); + } + const result = await runSigningFlow({ + ctx, + mnemonic, + signWalletType: args.walletType, + signerIndex: args.signerIndex, + signBroadcast: args.signBroadcast && boolFromEnv(process.env.SIGN_BROADCAST, true), + preferredTransactionId: txId, + requireBroadcastSuccess: args.signBroadcast, + }); + args.setTxHash?.(result.txHash); + return { + message: `Proxy lifecycle sign signerIndex=${args.signerIndex} status=${result.status} submitted=${String(result.submitted)}`, + artifacts: result as unknown as Record, + }; + }, + }; +} + +export function requireSetupTxHash(runtime: { + setupTransactionId?: string; + setupTxHash?: string; +}): string { + const txHash = runtime.setupTxHash?.trim(); + if (txHash) return txHash; + + throw new Error( + `proxy setup was not broadcast; signer step returned submitted=false for transaction ${runtime.setupTransactionId ?? "unknown"}`, + ); +} + +function createSetupLifecycleSteps(args: { + walletType: CIWalletType; + runtime: { + setup?: ProxySetup; + proxyId?: string; + setupTransactionId?: string; + setupTxHash?: string; + setupUtxoRefs?: UtxoRef[]; + }; +}): RouteStep[] { + const { walletType, runtime } = args; + return [ + { + id: `v1.proxy.lifecycle.setup.propose.${walletType}`, + description: `Build proxy setup transaction (${walletType})`, + severity: "critical", + execute: async (ctx) => { + const wallet = getWalletByType(ctx, walletType); + if (!wallet) throw new Error(`Missing ${walletType} wallet`); + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const [walletUtxos, collateralUtxos] = await Promise.all([ + fetchFreeUtxos({ ctx, walletId: wallet.walletId, token, address: bot.paymentAddress, fresh: true }), + fetchKeyAddressUtxos({ ctx, address: bot.paymentAddress }), + ]); + const refs = selectSetupRefs({ walletUtxos, collateralUtxos }); + const response = await requestJson<{ transaction?: unknown; setup?: ProxySetup; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/proxySetup`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + ...refs, + initialProxyLovelace: LIFECYCLE_PROXY_LOVELACE.toString(), + description: `CI proxy setup (${walletType})`, + }, + }); + if (response.status !== 201 || !response.data?.setup) { + throw new Error(`proxySetup failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + runtime.setup = response.data.setup; + runtime.setupUtxoRefs = refs.utxoRefs; + runtime.setupTransactionId = getTransactionId(response.data); + runtime.setupTxHash = getSubmittedTxHash(response.data); + return { + message: `proxySetup created setup for ${walletType}`, + artifacts: { + walletId: wallet.walletId, + setup: runtime.setup, + transactionId: runtime.setupTransactionId, + txHash: runtime.setupTxHash, + collateralRef: refs.collateralRef, + collateralOwnerSignerIndex: PROXY_LIFECYCLE_COLLATERAL_SIGNER_INDEX, + signerIndexes: [...PROXY_LIFECYCLE_SIGNER_INDEXES], + }, + }; + }, + }, + createSignStep({ + id: `v1.proxy.lifecycle.setup.signer0.${walletType}`, + description: `Signer index 0 adds collateral witness for proxy setup (${walletType})`, + walletType, + signerIndex: 0, + mnemonicEnvName: "CI_MNEMONIC_1", + signBroadcast: false, + getTransactionId: () => runtime.setupTransactionId, + }), + createSignStep({ + id: `v1.proxy.lifecycle.setup.signer1.${walletType}`, + description: `Signer index 1 broadcasts proxy setup (${walletType})`, + walletType, + signerIndex: 1, + mnemonicEnvName: "CI_MNEMONIC_2", + signBroadcast: true, + getTransactionId: () => runtime.setupTransactionId, + setTxHash: (txHash) => { + runtime.setupTxHash = txHash ?? runtime.setupTxHash; + }, + }), + { + id: `v1.proxy.lifecycle.setup.finalize.${walletType}`, + description: `Finalize confirmed proxy setup (${walletType})`, + severity: "critical", + execute: async (ctx) => { + const wallet = getWalletByType(ctx, walletType); + if (!wallet || !runtime.setup) throw new Error("Missing wallet or proxy setup metadata"); + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const setupTxHash = requireSetupTxHash(runtime); + if (runtime.setupUtxoRefs?.length && runtime.setupTransactionId) { + await pollUntilUtxosConsumed({ ctx, walletId: wallet.walletId, token, address: bot.paymentAddress, spentUtxoRefs: runtime.setupUtxoRefs }); + } + const response = await requestJson<{ proxy?: ProxyRow; error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/proxySetupFinalize`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + txHash: setupTxHash, + ...runtime.setup, + description: `CI proxy setup (${walletType})`, + }, + retries: 3, + }); + if (response.status !== 201 || !response.data?.proxy?.id) { + throw new Error(`proxySetupFinalize failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + runtime.proxyId = response.data.proxy.id; + return { message: `proxySetupFinalize created proxy ${runtime.proxyId}`, artifacts: { proxy: response.data.proxy } }; + }, + }, + { + id: `v1.proxy.lifecycle.proxies.active.${walletType}`, + description: `Assert finalized proxy is listed (${walletType})`, + severity: "critical", + execute: async (ctx) => { + const wallet = getWalletByType(ctx, walletType); + if (!wallet || !runtime.proxyId) throw new Error("Missing wallet or proxy id"); + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const response = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/proxies?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data) || !response.data.some((proxy) => proxy.id === runtime.proxyId)) { + throw new Error(`proxies did not include finalized proxy (${response.status}): ${stringifyRedacted(response.data)}`); + } + return { message: `proxies includes active proxy ${runtime.proxyId}`, artifacts: { proxyId: runtime.proxyId } }; + }, + }, + ]; +} + +function createProxyActionStep(args: { + id: string; + description: string; + walletType: CIWalletType; + endpoint: "proxySpend" | "proxyDRepCertificate" | "proxyVote" | "proxyCleanup"; + runtime: { + setup?: ProxySetup; + proxyId?: string; + activeProposals?: ActiveProposal[]; + actionTransactionId?: string; + actionTxHash?: string; + actionUtxoRefs?: UtxoRef[]; + cleanupPhase?: "sweep" | "burn"; + cleanupBurnSkipped?: boolean; + cleanupBurnTransactionId?: string; + }; + buildBody: (ctx: CIBootstrapContext, refs: ProxyActionRequestRefs) => Record | null; + selectRefs?: (args: { walletUtxos: ScriptUtxo[]; collateralUtxos: ScriptUtxo[]; authTokenId: string }) => ProxyActionSelection; + includeAllAuthTokens?: boolean; + shouldSkip?: () => boolean; + onSkip?: () => void; + onSuccess?: () => void; + beforeResolveRefs?: (ctx: CIBootstrapContext) => Promise; +}): RouteStep { + return { + id: args.id, + description: args.description, + severity: "critical", + execute: async (ctx) => { + const wallet = getWalletByType(ctx, args.walletType); + if (!wallet || !args.runtime.proxyId || !args.runtime.setup) throw new Error("Missing proxy lifecycle runtime"); + if (args.shouldSkip?.()) { + args.onSkip?.(); + return { message: `${args.endpoint} skipped`, artifacts: { skipped: true } }; + } + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + await args.beforeResolveRefs?.(ctx); + const [walletUtxos, collateralUtxos] = await Promise.all([ + fetchFreeUtxos({ ctx, walletId: wallet.walletId, token, address: bot.paymentAddress, fresh: true }), + fetchKeyAddressUtxos({ ctx, address: bot.paymentAddress }), + ]); + const selection = + args.selectRefs?.({ walletUtxos, collateralUtxos, authTokenId: args.runtime.setup.authTokenId }) ?? + selectAuthTokenRefs({ + walletUtxos, + collateralUtxos, + authTokenId: args.runtime.setup.authTokenId, + includeAllAuthTokens: args.includeAllAuthTokens, + }); + const { requestRefs, selectionArtifacts } = splitProxyActionSelection(selection); + args.runtime.actionTransactionId = undefined; + args.runtime.actionTxHash = undefined; + args.runtime.actionUtxoRefs = undefined; + const extraBody = args.buildBody(ctx, requestRefs); + if (!extraBody) { + return { message: `${args.endpoint} skipped`, artifacts: { skipped: true } }; + } + const response = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/${args.endpoint}`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + proxyId: args.runtime.proxyId, + ...requestRefs, + ...extraBody, + }, + }); + if (response.status !== 201) { + throw new Error(`${args.endpoint} failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + args.runtime.actionTransactionId = getTransactionId(response.data); + args.runtime.actionTxHash = getSubmittedTxHash(response.data); + args.runtime.actionUtxoRefs = requestRefs.utxoRefs; + if (args.endpoint === "proxyCleanup") { + args.runtime.cleanupPhase = getCleanupPhase(response.data); + } + args.onSuccess?.(); + const hasSelectionArtifacts = Object.keys(selectionArtifacts).length > 0; + return { + message: `${args.endpoint} transaction created`, + artifacts: { + transactionId: args.runtime.actionTransactionId, + txHash: args.runtime.actionTxHash, + cleanupPhase: args.runtime.cleanupPhase, + collateralRef: requestRefs.collateralRef, + collateralOwnerSignerIndex: PROXY_LIFECYCLE_COLLATERAL_SIGNER_INDEX, + signerIndexes: [...PROXY_LIFECYCLE_SIGNER_INDEXES], + ...(hasSelectionArtifacts ? { selectionArtifacts } : {}), + }, + }; + }, + }; +} + +function createActionSigningSteps(args: { + prefix: string; + walletType: CIWalletType; + runtime: { actionTransactionId?: string; actionTxHash?: string }; + shouldSkip?: () => boolean; +}): RouteStep[] { + return [ + createSignStep({ + id: `${args.prefix}.signer0`, + description: `${args.prefix} signer index 0 collateral witness`, + walletType: args.walletType, + signerIndex: 0, + mnemonicEnvName: "CI_MNEMONIC_1", + signBroadcast: false, + getTransactionId: () => args.runtime.actionTransactionId, + shouldSkip: args.shouldSkip, + }), + createSignStep({ + id: `${args.prefix}.signer1`, + description: `${args.prefix} signer index 1 broadcast`, + walletType: args.walletType, + signerIndex: 1, + mnemonicEnvName: "CI_MNEMONIC_2", + signBroadcast: true, + getTransactionId: () => args.runtime.actionTransactionId, + shouldSkip: args.shouldSkip, + setTxHash: (txHash) => { + args.runtime.actionTxHash = txHash ?? args.runtime.actionTxHash; + }, + }), + ]; +} + +function createWaitForActionConfirmationStep(args: { + id: string; + description: string; + walletType: CIWalletType; + runtime: { actionTransactionId?: string; actionUtxoRefs?: UtxoRef[] }; + shouldSkip?: () => boolean; +}): RouteStep { + return { + id: args.id, + description: args.description, + severity: "critical", + execute: async (ctx) => { + if (args.shouldSkip?.() || shouldSkipActionConfirmation(args.runtime)) { + return { message: "Confirmation wait skipped", artifacts: { skipped: true } }; + } + const wallet = getWalletByType(ctx, args.walletType); + if (!wallet) throw new Error(`Missing ${args.walletType} wallet`); + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const result = await pollUntilUtxosConsumed({ + ctx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + spentUtxoRefs: args.runtime.actionUtxoRefs!, + }); + return { + message: `Confirmed proxy action inputs consumed after ${result.attempts} attempt(s)`, + artifacts: { + transactionId: args.runtime.actionTransactionId, + attempts: result.attempts, + }, + }; + }, + }; +} + +function createProxyFullLifecycleHygieneStep(walletType: CIWalletType): RouteStep { + return { + id: `v1.proxy.full.hygiene.${walletType}`, + description: "Clean stale active proxy lifecycle rows before starting", + severity: "critical", + execute: async (ctx) => runProxyFullLifecycleHygiene({ ctx, walletType }), + }; +} + +function createProxyFullLifecycleChainRecoveryStep(walletType: CIWalletType): RouteStep { + return { + id: `v1.proxy.full.recoverFromChain.${walletType}`, + description: "Recover stale proxy rows from on-chain CI wallet evidence", + severity: "critical", + execute: async (ctx) => { + const result = await recoverProxyRowsFromChainForWalletType({ ctx, walletType }); + return { + message: result.recovered.length + ? `recovered ${result.recovered.length} proxy row(s) from chain for ${walletType}` + : `no proxy rows recovered from chain for ${walletType}`, + artifacts: normalizeJsonArtifact(result) as Record, + }; + }, + }; +} + +function createProxyFullLifecycleAdoptionStep(walletType: CIWalletType): RouteStep { + return { + id: `v1.proxy.full.adoptOrphans.${walletType}`, + description: "Adopt stale proxy rows from historical deterministic CI wallets", + severity: "critical", + execute: async (ctx) => { + const result = await adoptProxyOrphansForWalletType({ ctx, walletType }); + return { + message: result.adopted.length + ? `adopted ${result.adopted.length} orphan proxy row(s) for ${walletType}` + : `no orphan proxy rows adopted for ${walletType}`, + artifacts: normalizeJsonArtifact(result) as Record, + }; + }, + }; +} + +function createProxyFullLifecycleSteps(walletType: CIWalletType): RouteStep[] { + const runtime: { + setup?: ProxySetup; + proxyId?: string; + setupTransactionId?: string; + setupTxHash?: string; + setupUtxoRefs?: UtxoRef[]; + actionTransactionId?: string; + actionTxHash?: string; + actionUtxoRefs?: UtxoRef[]; + activeProposals?: ActiveProposal[]; + attemptedVote?: boolean; + cleanupPhase?: "sweep" | "burn"; + cleanupBurnSkipped?: boolean; + cleanupBurnTransactionId?: string; + } = {}; + + return [ + createProxyFullLifecycleChainRecoveryStep(walletType), + createProxyFullLifecycleAdoptionStep(walletType), + createProxyFullLifecycleHygieneStep(walletType), + { + id: `v1.proxy.full.utxoShape.${walletType}`, + description: "Ensure proxy full-lifecycle wallet has separate setup and collateral UTxOs", + severity: "critical", + execute: async (runCtx) => { + const result = await ensureProxyLifecycleUtxoShape({ ctx: runCtx, walletType }); + return { + message: + result.status === "already-shaped" + ? `proxy full lifecycle UTxO shape already satisfied for ${walletType}` + : `proxy full lifecycle UTxO self-split confirmed for ${walletType}`, + artifacts: result as unknown as Record, + }; + }, + }, + { + id: `v1.proxy.full.preflight.${walletType}`, + description: "Verify proxy full-lifecycle ADA budget and UTxO shape", + severity: "critical", + execute: async (runCtx) => { + const wallet = getWalletByType(runCtx, walletType); + if (!wallet) throw new Error(`Missing ${walletType} wallet`); + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const [walletUtxos, collateralUtxos] = await Promise.all([ + fetchFreeUtxos({ + ctx: runCtx, + walletId: wallet.walletId, + token, + address: bot.paymentAddress, + fresh: true, + }), + fetchKeyAddressUtxos({ ctx: runCtx, address: bot.paymentAddress }), + ]); + const result = assertProxyFullLifecyclePreflight({ + walletUtxos, + collateralUtxos, + }); + return { + message: `proxy full lifecycle preflight passed with ${formatAda(result.totalLovelace)} available and ${formatAda(result.requiredTotalLovelace)} required`, + artifacts: { + totalLovelace: result.totalLovelace.toString(), + largestUtxoLovelace: result.largestUtxoLovelace.toString(), + setupCandidates: result.setupCandidates, + keyCollateralCandidates: result.keyCollateralCandidates, + drepSelectableLovelace: result.drepSelectableLovelace.toString(), + drepRequiredLovelace: result.drepRequiredLovelace.toString(), + requiredTotalLovelace: result.requiredTotalLovelace.toString(), + }, + }; + }, + }, + ...createSetupLifecycleSteps({ walletType, runtime }), + createProxyActionStep({ + id: `v1.proxy.full.spend.propose.${walletType}`, + description: "Build proxy spend transaction", + walletType, + endpoint: "proxySpend", + runtime, + buildBody: (runCtx) => ({ + outputs: [{ address: getWalletByType(runCtx, walletType)?.walletAddress ?? "", unit: "lovelace", amount: PROXY_SPEND_LOVELACE.toString() }], + description: "CI proxy spend", + }), + }), + ...createActionSigningSteps({ prefix: `v1.proxy.full.spend.${walletType}`, walletType, runtime }), + createWaitForActionConfirmationStep({ + id: `v1.proxy.full.spend.confirmed.${walletType}`, + description: "Wait for proxy spend inputs to be confirmed consumed", + walletType, + runtime, + }), + createProxyActionStep({ + id: `v1.proxy.full.drepRegister.propose.${walletType}`, + description: "Build proxy DRep register transaction", + walletType, + endpoint: "proxyDRepCertificate", + runtime, + selectRefs: ({ walletUtxos, collateralUtxos, authTokenId }) => { + return selectDRepRegisterRefs({ + walletUtxos, + collateralUtxos, + authTokenId, + requiredLovelace: DREP_REGISTER_REQUIRED_LOVELACE + FULL_LIFECYCLE_FEE_BUFFER_LOVELACE, + }); + }, + buildBody: () => ({ + action: "register", + anchorUrl: getProxyDRepAnchorUrl(), + anchorJson: { name: "CI Proxy DRep", purpose: "route-chain" }, + description: "CI proxy DRep register", + }), + }), + ...createActionSigningSteps({ prefix: `v1.proxy.full.drepRegister.${walletType}`, walletType, runtime }), + createWaitForActionConfirmationStep({ + id: `v1.proxy.full.drepRegister.confirmed.${walletType}`, + description: "Wait for proxy DRep register inputs to be confirmed consumed", + walletType, + runtime, + }), + { + id: `v1.proxy.full.activeProposals.${walletType}`, + description: "Fetch active proposals for optional proxy vote", + severity: "critical", + execute: async (runCtx) => { + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const response = await requestJson<{ proposals?: unknown[]; activeCount?: number; sourceCount?: number; error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/governanceActiveProposals?network=0&count=20&page=1&order=desc&details=false`, + method: "GET", + token, + }); + if (response.status !== 200) { + throw new Error(`governanceActiveProposals failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + runtime.activeProposals = getDeterministicActiveProposals(response.data, 1); + return { + message: `selected ${runtime.activeProposals.length} active proposal(s) for optional proxy vote`, + artifacts: { selectedProposalIds: runtime.activeProposals.map((proposal) => proposal.proposalId) }, + }; + }, + }, + createProxyActionStep({ + id: `v1.proxy.full.vote.propose.${walletType}`, + description: "Build proxy vote transaction when proposals exist", + walletType, + endpoint: "proxyVote", + runtime, + selectRefs: ({ walletUtxos, collateralUtxos, authTokenId }) => + selectAuthTokenRefsWithMinLovelace({ + walletUtxos, + collateralUtxos, + authTokenId, + requiredLovelace: PROXY_ACTION_REQUIRED_LOVELACE + PROXY_ACTION_FEE_BUFFER_LOVELACE, + context: "proxy vote", + }), + buildBody: () => { + const proposal = runtime.activeProposals?.[0]; + if (!proposal) return null; + runtime.attemptedVote = true; + return { + votes: [{ proposalId: proposal.proposalId, voteKind: "Abstain" }], + description: "CI proxy vote", + }; + }, + }), + ...createActionSigningSteps({ prefix: `v1.proxy.full.vote.${walletType}`, walletType, runtime }), + createWaitForActionConfirmationStep({ + id: `v1.proxy.full.vote.confirmed.${walletType}`, + description: "Wait for proxy vote inputs to be confirmed consumed", + walletType, + runtime, + }), + createProxyActionStep({ + id: `v1.proxy.full.drepDeregister.propose.${walletType}`, + description: "Build proxy DRep deregister transaction", + walletType, + endpoint: "proxyDRepCertificate", + runtime, + selectRefs: ({ walletUtxos, collateralUtxos, authTokenId }) => + selectAuthTokenRefsWithMinLovelace({ + walletUtxos, + collateralUtxos, + authTokenId, + requiredLovelace: PROXY_ACTION_REQUIRED_LOVELACE + PROXY_ACTION_FEE_BUFFER_LOVELACE, + context: "proxy DRep deregister", + }), + buildBody: () => ({ + action: "deregister", + description: "CI proxy DRep deregister", + }), + }), + ...createActionSigningSteps({ prefix: `v1.proxy.full.drepDeregister.${walletType}`, walletType, runtime }), + createWaitForActionConfirmationStep({ + id: `v1.proxy.full.drepDeregister.confirmed.${walletType}`, + description: "Wait for proxy DRep deregister inputs to be confirmed consumed", + walletType, + runtime, + }), + createProxyActionStep({ + id: `v1.proxy.full.cleanup.initial.propose.${walletType}`, + description: "Build initial proxy cleanup transaction", + walletType, + endpoint: "proxyCleanup", + runtime, + includeAllAuthTokens: true, + buildBody: () => ({ + deactivateProxy: true, + description: "CI proxy cleanup", + }), + }), + ...createActionSigningSteps({ prefix: `v1.proxy.full.cleanup.initial.${walletType}`, walletType, runtime }), + createWaitForActionConfirmationStep({ + id: `v1.proxy.full.cleanup.initial.confirmed.${walletType}`, + description: "Wait for initial proxy cleanup inputs to be confirmed consumed", + walletType, + runtime, + }), + createProxyActionStep({ + id: `v1.proxy.full.cleanup.burn.propose.${walletType}`, + description: "Build proxy cleanup burn transaction after sweep", + walletType, + endpoint: "proxyCleanup", + runtime, + includeAllAuthTokens: true, + shouldSkip: () => shouldSkipCleanupBurnPropose(runtime), + onSkip: () => { + runtime.cleanupBurnSkipped = true; + runtime.cleanupBurnTransactionId = undefined; + }, + onSuccess: () => { + runtime.cleanupBurnSkipped = false; + runtime.cleanupBurnTransactionId = runtime.actionTransactionId; + }, + buildBody: () => ({ + deactivateProxy: true, + description: "CI proxy cleanup burn", + }), + }), + ...createActionSigningSteps({ + prefix: `v1.proxy.full.cleanup.burn.${walletType}`, + walletType, + runtime, + shouldSkip: () => shouldSkipCleanupBurnSigning(runtime), + }), + createWaitForActionConfirmationStep({ + id: `v1.proxy.full.cleanup.burn.confirmed.${walletType}`, + description: "Wait for proxy cleanup burn inputs to be confirmed consumed", + walletType, + runtime, + shouldSkip: () => shouldSkipCleanupBurnSigning(runtime), + }), + { + id: `v1.proxy.full.cleanup.finalize.${walletType}`, + description: "Finalize proxy cleanup and deactivate proxy", + severity: "critical", + execute: async (runCtx) => { + const wallet = getWalletByType(runCtx, walletType); + if (!wallet || !runtime.proxyId) throw new Error("Missing wallet or proxy id for cleanup finalize"); + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + if (runtime.actionUtxoRefs?.length && runtime.actionTransactionId) { + await pollUntilUtxosConsumed({ ctx: runCtx, walletId: wallet.walletId, token, address: bot.paymentAddress, spentUtxoRefs: runtime.actionUtxoRefs }); + } + const response = await requestJson<{ proxy?: ProxyRow; error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/proxyCleanupFinalize`, + method: "POST", + token, + body: { + walletId: wallet.walletId, + address: bot.paymentAddress, + proxyId: runtime.proxyId, + txHash: runtime.actionTxHash ?? runtime.actionTransactionId ?? "submitted", + }, + retries: 3, + }); + if (response.status !== 201 || response.data?.proxy?.isActive !== false) { + throw new Error(`proxyCleanupFinalize failed (${response.status}): ${stringifyRedacted(response.data)}`); + } + return { message: `proxy ${runtime.proxyId} deactivated after cleanup`, artifacts: { proxy: response.data.proxy } }; + }, + }, + { + id: `v1.proxy.full.cleanup.proxies.inactive.${walletType}`, + description: "Assert cleaned proxy is no longer listed as active", + severity: "critical", + execute: async (runCtx) => { + const wallet = getWalletByType(runCtx, walletType); + if (!wallet || !runtime.proxyId) throw new Error("Missing wallet or proxy id after cleanup"); + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const response = await requestJson({ + url: `${runCtx.apiBaseUrl}/api/v1/proxies?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error(`proxies list failed after cleanup (${response.status}): ${stringifyRedacted(response.data)}`); + } + if (response.data.some((proxy) => proxy.id === runtime.proxyId)) { + throw new Error(`cleaned proxy ${runtime.proxyId} is still listed as active`); + } + return { message: `proxy ${runtime.proxyId} is no longer listed as active` }; + }, + }, + ]; +} + +export function createScenarioProxyFullLifecycle(ctx: CIBootstrapContext): Scenario { + const eligibleWalletTypes = PROXY_FULL_LIFECYCLE_WALLET_TYPES.filter( + (walletType) => + ctx.walletTypes.includes(walletType) && + ctx.wallets.some((wallet) => wallet.type === walletType), + ); + + const steps: RouteStep[] = eligibleWalletTypes.length + ? eligibleWalletTypes.flatMap((walletType) => createProxyFullLifecycleSteps(walletType)) + : [ + { + id: "v1.proxy.full.precondition", + description: "Assert proxy full lifecycle has an eligible wallet type", + severity: "critical", + execute: async () => { + throw new Error( + `scenario.proxy-full-lifecycle requires at least one of ${PROXY_FULL_LIFECYCLE_WALLET_TYPES.join(", ")} in CI_WALLET_TYPES`, + ); + }, + }, + ]; + + return { + id: "scenario.proxy-full-lifecycle", + description: "Proxy spend, governance, and cleanup lifecycle for legacy, hierarchical, and SDK wallets", + steps, + }; +} diff --git a/scripts/ci/scenarios/steps/template-route-step.ts b/scripts/ci/scenarios/steps/template-route-step.ts new file mode 100644 index 00000000..00374812 --- /dev/null +++ b/scripts/ci/scenarios/steps/template-route-step.ts @@ -0,0 +1,51 @@ +import type { CIBootstrapContext, RouteStep, StepRunResult } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; + +/** + * Copy this file when adding a new route step. + * + * Suggested flow: + * 1) Rename the exported factory function. + * 2) Replace `id` and `description` with route-specific values. + * 3) Define deterministic inputs from context/env. + * 4) Perform request(s) with requestJson(). + * 5) Add strict assertions and return concise artifacts. + */ +export function createTemplateRouteStep(): RouteStep { + return { + id: "template.route.step", + description: "Template step - replace with real route behavior", + severity: "critical", + execute: async (ctx: CIBootstrapContext): Promise => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const wallet = ctx.wallets[0]; + if (!wallet) { + throw new Error("No wallets available in CI bootstrap context"); + } + + const response = await requestJson({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(wallet.walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + + if (response.status !== 200) { + throw new Error( + `Template step expected 200, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + + return { + message: "Template route step passed", + artifacts: { + walletId: wallet.walletId, + status: response.status, + }, + }; + }, + }; +} diff --git a/scripts/ci/scenarios/steps/transferRing.ts b/scripts/ci/scenarios/steps/transferRing.ts new file mode 100644 index 00000000..17b00f8b --- /dev/null +++ b/scripts/ci/scenarios/steps/transferRing.ts @@ -0,0 +1,243 @@ +import type { CIBootstrapContext, CIWalletType, RouteStep, Scenario } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { runSigningFlow } from "../flows/signingFlow"; +import { seedRealTransferTransaction } from "../flows/transferFlow"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; +import { boolFromEnv } from "../../framework/env"; + +export type TransferLegRuntime = { + fromWalletType: CIWalletType; + toWalletType: CIWalletType; + fromWalletId?: string; + transferTxId?: string; +}; + +function createSigningStep(args: { + id: string; + description: string; + signerIndex: number; + mnemonicEnvName: "CI_MNEMONIC_1" | "CI_MNEMONIC_2" | "CI_MNEMONIC_3"; + signWalletType?: string; + signBroadcast: boolean; + requireBroadcastSuccess: boolean; + preferredTransactionId?: () => string | undefined; +}): RouteStep { + return { + id: args.id, + description: args.description, + severity: "critical", + execute: async (ctx) => { + const mnemonic = process.env[args.mnemonicEnvName]; + if (!mnemonic || !mnemonic.trim()) { + throw new Error(`${args.mnemonicEnvName} is required for signing scenario`); + } + const result = await runSigningFlow({ + ctx, + mnemonic, + signWalletType: args.signWalletType ?? process.env.CI_SIGN_WALLET_TYPE ?? "legacy", + signerIndex: args.signerIndex, + signerLabel: `signer${args.signerIndex}`, + signBroadcast: args.signBroadcast && boolFromEnv(process.env.SIGN_BROADCAST, true), + preferredTransactionId: args.preferredTransactionId?.(), + requireBroadcastSuccess: args.requireBroadcastSuccess, + }); + return { + message: `signTransaction completed for ${result.walletType} (status=${result.status}, submitted=${String(result.submitted)})`, + artifacts: result as unknown as Record, + }; + }, + }; +} + +export function createScenarioRealTransferAndSign(runtime: { transferLegs: TransferLegRuntime[] }): Scenario { + return { + id: "scenario.real-transfer-and-sign", + description: "Build ring transfer txs across multisig wallets and sign+broadcast each leg", + steps: runtime.transferLegs.flatMap((leg, index) => { + const legName = `${leg.fromWalletType}To${leg.toWalletType}`; + const legOrdinal = index + 1; + return [ + { + id: `v1.addTransaction.realTransfer.${legName}`, + description: `Create ring leg ${legOrdinal} transfer (${leg.fromWalletType} -> ${leg.toWalletType})`, + severity: "critical" as const, + execute: async (ctx: CIBootstrapContext) => { + const mnemonic = process.env.CI_MNEMONIC_2; + if (!mnemonic || !mnemonic.trim()) { + throw new Error("CI_MNEMONIC_2 is required for transfer scenario"); + } + const transferResult = await seedRealTransferTransaction({ + ctx, + fromMnemonic: mnemonic, + fromWalletType: leg.fromWalletType, + toWalletType: leg.toWalletType, + transferLovelace: process.env.CI_TRANSFER_LOVELACE, + }); + leg.transferTxId = transferResult.transactionId; + leg.fromWalletId = transferResult.fromWalletId; + return { + message: `Real transfer tx created (${transferResult.transactionId}) for ${leg.fromWalletType} -> ${leg.toWalletType}`, + artifacts: transferResult as unknown as Record, + }; + }, + }, + { + id: `v1.pendingTransactions.ringTransfer.present.${legName}`, + description: `Assert ring leg ${legOrdinal} transaction is pending in source wallet`, + severity: "critical" as const, + execute: async (ctx: CIBootstrapContext) => { + const txId = leg.transferTxId; + const walletId = leg.fromWalletId; + if (!txId || !walletId) { + throw new Error(`Transfer runtime context missing for ring leg ${legName}`); + } + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const response = await requestJson | { error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `pendingTransactions ring leg present check failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + const found = response.data.some((tx) => tx.id === txId); + if (!found) { + throw new Error(`Transfer tx ${txId} not found in pending for wallet ${walletId}`); + } + return { + message: `Transfer tx ${txId} is present in pending transactions`, + artifacts: { walletId, transactionId: txId, pendingCount: response.data.length }, + }; + }, + }, + createSigningStep({ + id: `v1.signTransaction.ringTransfer.signer1.${legName}`, + description: `Signer 1 adds witness without broadcast for ring leg ${legOrdinal}`, + signerIndex: 1, + mnemonicEnvName: "CI_MNEMONIC_2", + signWalletType: leg.fromWalletType, + signBroadcast: false, + requireBroadcastSuccess: false, + preferredTransactionId: () => leg.transferTxId, + }), + createSigningStep({ + id: `v1.signTransaction.ringTransfer.signer2.${legName}`, + description: `Signer 2 signs and broadcasts ring leg ${legOrdinal}`, + signerIndex: 2, + mnemonicEnvName: "CI_MNEMONIC_3", + signWalletType: leg.fromWalletType, + signBroadcast: true, + requireBroadcastSuccess: true, + preferredTransactionId: () => leg.transferTxId, + }), + { + id: `v1.pendingTransactions.ringTransfer.removed.${legName}`, + description: `Assert ring leg ${legOrdinal} transaction is cleared from pending`, + severity: "critical" as const, + execute: async (ctx: CIBootstrapContext) => { + const txId = leg.transferTxId; + const walletId = leg.fromWalletId; + if (!txId || !walletId) { + throw new Error(`Transfer runtime context missing for ring leg ${legName}`); + } + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const response = await requestJson | { error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `pendingTransactions ring leg removed check failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + const stillPending = response.data.some((tx) => tx.id === txId); + if (stillPending) { + throw new Error(`Transfer tx ${txId} is still pending after sign+broadcast`); + } + return { + message: `Transfer tx ${txId} removed from pending transactions`, + artifacts: { walletId, transactionId: txId, pendingCount: response.data.length }, + }; + }, + }, + ]; + }), + }; +} + +export function createScenarioFinalAssertions(runtime: { transferLegs: TransferLegRuntime[] }): Scenario { + return { + id: "scenario.final-assertions", + description: "Validate final state after transfer/sign route chain", + steps: [ + { + id: "v1.pendingTransactions.allRingTransfersRemoved", + description: "Assert all signed ring transfer transactions are no longer pending", + severity: "critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const checked: Array<{ walletId: string; transactionId: string; pendingCount: number }> = []; + for (const leg of runtime.transferLegs) { + const txId = leg.transferTxId; + const walletId = leg.fromWalletId; + if (!txId || !walletId) { + throw new Error( + `Transfer runtime context missing transaction/wallet id for ${leg.fromWalletType} -> ${leg.toWalletType}`, + ); + } + const response = await requestJson | { error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/pendingTransactions?walletId=${encodeURIComponent(walletId)}&address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `pendingTransactions final assertion failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + const stillPending = response.data.some((tx) => tx.id === txId); + if (stillPending) { + throw new Error(`Transfer tx ${txId} is still pending after sign+broadcast`); + } + checked.push({ walletId, transactionId: txId, pendingCount: response.data.length }); + } + return { + message: `All ${checked.length} ring transfer txs are no longer present in pending transactions`, + artifacts: { checked }, + }; + }, + }, + { + id: "v1.walletIds.postTransfer", + description: "Assert wallet discovery remains consistent after transfer flow", + severity: "non-critical", + execute: async (ctx) => { + const bot = getDefaultBot(ctx); + const token = await authenticateBot({ ctx, bot }); + const response = await requestJson | { error?: string }>({ + url: `${ctx.apiBaseUrl}/api/v1/walletIds?address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `walletIds post-transfer failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + return { + message: `walletIds remains healthy after transfer (${response.data.length} wallets)`, + artifacts: { walletCount: response.data.length }, + }; + }, + }, + ], + }; +} diff --git a/scripts/ci/scenarios/steps/walletLifecycle.ts b/scripts/ci/scenarios/steps/walletLifecycle.ts new file mode 100644 index 00000000..4781844f --- /dev/null +++ b/scripts/ci/scenarios/steps/walletLifecycle.ts @@ -0,0 +1,129 @@ +import type { CIBootstrapContext, Scenario } from "../../framework/types"; +import { requestJson } from "../../framework/http"; +import { getDefaultBot } from "../../framework/botContext"; +import { authenticateBot } from "../../framework/botAuth"; +import { stringifyRedacted } from "../../framework/redact"; + +export function createScenarioCreateWallet(ctx: CIBootstrapContext): Scenario { + const runtime: { createdWalletId?: string } = {}; + return { + id: "scenario.create-wallet", + description: "Verify POST /api/v1/createWallet creates a wallet via the bot API", + steps: [ + { + id: "v1.createWallet.botCreate", + description: "Create a new multisig wallet via /api/v1/createWallet (bot-authenticated)", + severity: "critical", + execute: async (runCtx) => { + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const signerAddresses = runCtx.signerAddresses.slice(0, 3).filter(Boolean); + if (signerAddresses.length < 1) { + throw new Error("createWallet: no signer addresses in bootstrap context"); + } + const numRequiredSigners = Math.min( + parseInt(process.env.CI_NUM_REQUIRED_SIGNERS ?? "2", 10), + signerAddresses.length, + ); + const response = await requestJson<{ + walletId?: string; + address?: string; + name?: string; + error?: string; + }>({ + url: `${runCtx.apiBaseUrl}/api/v1/createWallet`, + method: "POST", + token, + body: { + name: `CI create-wallet ${runCtx.createdAt}`, + signersAddresses: signerAddresses, + numRequiredSigners, + scriptType: "atLeast", + network: runCtx.networkId, + }, + }); + if (response.status !== 201) { + throw new Error( + `createWallet expected 201, got ${response.status}: ${stringifyRedacted(response.data)}`, + ); + } + if (typeof response.data.walletId !== "string" || !response.data.walletId) { + throw new Error("createWallet: response missing walletId"); + } + if (typeof response.data.address !== "string" || !response.data.address) { + throw new Error("createWallet: response missing address"); + } + runtime.createdWalletId = response.data.walletId; + return { + message: `createWallet succeeded: walletId=${response.data.walletId}`, + artifacts: { + walletId: response.data.walletId, + address: response.data.address, + name: response.data.name, + }, + }; + }, + }, + { + id: "v1.createWallet.appearsInWalletIds", + description: "Confirm created wallet appears in /api/v1/walletIds for the bot", + severity: "critical", + execute: async (runCtx) => { + if (!runtime.createdWalletId) { + throw new Error("createWallet.appearsInWalletIds: no walletId from prior step"); + } + const bot = getDefaultBot(runCtx); + const token = await authenticateBot({ ctx: runCtx, bot }); + const response = await requestJson | { error?: string }>({ + url: `${runCtx.apiBaseUrl}/api/v1/walletIds?address=${encodeURIComponent(bot.paymentAddress)}`, + method: "GET", + token, + }); + if (response.status !== 200 || !Array.isArray(response.data)) { + throw new Error( + `walletIds check after createWallet failed (${response.status}): ${stringifyRedacted(response.data)}`, + ); + } + const found = response.data.some( + (w) => w.walletId === runtime.createdWalletId, + ); + if (!found) { + throw new Error( + `createWallet: walletId ${runtime.createdWalletId} not found in walletIds after creation`, + ); + } + return { + message: `Created wallet ${runtime.createdWalletId} confirmed in walletIds`, + artifacts: { + walletId: runtime.createdWalletId, + totalWallets: response.data.length, + }, + }; + }, + }, + { + id: "v1.createWallet.cleanup", + description: "Delete the CI test wallet from the database (WalletBotAccess then Wallet)", + severity: "non-critical", + execute: async () => { + if (!runtime.createdWalletId) { + return { message: "createWallet.cleanup: no walletId to clean up; skipping" }; + } + const { PrismaClient } = await import("@prisma/client"); + const prisma = new PrismaClient(); + try { + // WalletBotAccess has no cascade relation — must be deleted before the Wallet row. + await prisma.walletBotAccess.deleteMany({ where: { walletId: runtime.createdWalletId } }); + await prisma.wallet.delete({ where: { id: runtime.createdWalletId } }); + return { + message: `createWallet cleanup: deleted wallet ${runtime.createdWalletId}`, + artifacts: { walletId: runtime.createdWalletId }, + }; + } finally { + await prisma.$disconnect(); + } + }, + }, + ], + }; +} diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 00000000..eae98e16 --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,10 @@ +{ + "version": 1, + "skills": { + "supabase-postgres-best-practices": { + "source": "supabase/agent-skills", + "sourceType": "github", + "computedHash": "9c87c315aed143ee3b34bec8117100f5035e0df09e6b23e1ecc772cff434c9ad" + } + } +} diff --git a/src/__tests__/__mocks__/styleMock.cjs b/src/__tests__/__mocks__/styleMock.cjs new file mode 100644 index 00000000..f053ebf7 --- /dev/null +++ b/src/__tests__/__mocks__/styleMock.cjs @@ -0,0 +1 @@ +module.exports = {}; diff --git a/src/__tests__/addTransaction.bot.test.ts b/src/__tests__/addTransaction.bot.test.ts new file mode 100644 index 00000000..484f7cf3 --- /dev/null +++ b/src/__tests__/addTransaction.bot.test.ts @@ -0,0 +1,119 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { BOT_TEST_ADDRESS, createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const enforceBodySizeMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const assertBotWalletAccessMock: jest.Mock = jest.fn(); +const createTransactionMock: jest.Mock = jest.fn(); +const transactionFromHexMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, + enforceBodySize: enforceBodySizeMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/lib/auth/botAccess", () => ({ + __esModule: true, + assertBotWalletAccess: assertBotWalletAccessMock, +}), { virtual: true }); + +jest.mock("@/utils/get-provider", () => ({ + __esModule: true, + getProvider: () => ({ submitTx: jest.fn() }), +}), { virtual: true }); + +jest.mock("@meshsdk/core-csl", () => ({ + __esModule: true, + csl: { + Transaction: { + from_hex: transactionFromHexMock, + }, + }, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: { + transaction: { create: createTransactionMock }, + wallet: { findUnique: jest.fn() }, + }, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/addTransaction")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + enforceBodySizeMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + transactionFromHexMock.mockReturnValue({}); + (assertBotWalletAccessMock as any).mockResolvedValue({ + wallet: { id: "wallet-1", signersAddresses: [BOT_TEST_ADDRESS], numRequiredSigners: 2, type: "atLeast" }, + role: "cosigner", + }); + (createTransactionMock as any).mockResolvedValue({ id: "tx-1" }); +}); + +describe("addTransaction bot API", () => { + it("returns 403 when bot wallet access fails", async () => { + (assertBotWalletAccessMock as any).mockRejectedValue(new Error("no access")); + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + address: BOT_TEST_ADDRESS, + txCbor: "deadbeef", + txJson: "{}", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(403); + }); + + it("creates pending transaction for authorized bot", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + address: BOT_TEST_ADDRESS, + txCbor: "deadbeef", + txJson: "{}", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(createTransactionMock).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ id: "tx-1" }); + }); +}); diff --git a/src/__tests__/addTransaction.test.ts b/src/__tests__/addTransaction.test.ts new file mode 100644 index 00000000..651b05b1 --- /dev/null +++ b/src/__tests__/addTransaction.test.ts @@ -0,0 +1,246 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from '@jest/globals'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +// --- mocks --------------------------------------------------------------- + +const addCorsCacheBustingHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); + +jest.mock( + '@/lib/cors', + () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsCacheBustingHeadersMock, + cors: corsMock, + }), + { virtual: true }, +); + +const verifyJwtMock = jest.fn<(token: string | undefined) => { address: string } | null>(); +const isBotJwtMock = jest.fn<(payload: unknown) => boolean>(); + +jest.mock( + '@/lib/verifyJwt', + () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, + }), + { virtual: true }, +); + +const applyRateLimitMock = jest.fn< + (req: NextApiRequest, res: NextApiResponse, options?: unknown) => boolean +>(); +const applyBotRateLimitMock = jest.fn< + (req: NextApiRequest, res: NextApiResponse, botId: string) => boolean +>(); +const enforceBodySizeMock = jest.fn< + (req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean +>(); + +jest.mock( + '@/lib/security/requestGuards', + () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, + enforceBodySize: enforceBodySizeMock, + }), + { virtual: true }, +); + +const assertBotWalletAccessMock = jest.fn< + (db: unknown, walletId: string, payload: unknown, ...rest: unknown[]) => Promise<{ wallet: unknown }> +>(); + +jest.mock( + '@/lib/auth/botAccess', + () => ({ + __esModule: true, + assertBotWalletAccess: assertBotWalletAccessMock, + }), + { virtual: true }, +); + +const dbTransactionCreateMock = jest.fn<(args: unknown) => Promise>(); +const dbWalletFindUniqueMock = jest.fn<(args: unknown) => Promise>(); + +const dbMock = { + transaction: { create: dbTransactionCreateMock }, + wallet: { findUnique: dbWalletFindUniqueMock }, +}; + +jest.mock( + '@/server/db', + () => ({ + __esModule: true, + db: dbMock, + }), + { virtual: true }, +); + +const getProviderMock = jest.fn<(network: number) => { submitTx: (cbor: string) => unknown }>(); + +jest.mock( + '@/utils/get-provider', + () => ({ + __esModule: true, + getProvider: getProviderMock, + }), + { virtual: true }, +); + +const transactionFromHexMock = jest.fn<(hex: string) => { _parsed: true }>(); + +jest.mock( + '@meshsdk/core-csl', + () => ({ + __esModule: true, + csl: { + Transaction: { from_hex: transactionFromHexMock }, + }, + }), + { virtual: true }, +); + +// --- helpers ------------------------------------------------------------- + +type ResponseMock = NextApiResponse & { statusCode?: number }; + +function createMockResponse(): ResponseMock { + const res = { + statusCode: undefined as number | undefined, + status: jest.fn<(code: number) => NextApiResponse>(), + json: jest.fn<(payload: unknown) => unknown>(), + end: jest.fn<() => void>(), + setHeader: jest.fn<(name: string, value: string) => void>(), + }; + + res.status.mockImplementation((code: number) => { + res.statusCode = code; + return res as unknown as NextApiResponse; + }); + + res.json.mockImplementation((payload: unknown) => payload); + + return res as unknown as ResponseMock; +} + +const VALID_CBOR = '84a3'.padEnd(64, '0'); +const ADDRESS = 'addr_test1qpcallerexample'; +const WALLET_ID = 'wallet-id-1'; +const TOKEN = 'caller-token'; + +function baseBody(overrides: Record = {}) { + return { + walletId: WALLET_ID, + address: ADDRESS, + txCbor: VALID_CBOR, + txJson: JSON.stringify({ outputs: [] }), + description: 'test tx', + ...overrides, + }; +} + +function buildReq(body: Record): NextApiRequest { + return { + method: 'POST', + headers: { authorization: `Bearer ${TOKEN}` }, + body, + } as unknown as NextApiRequest; +} + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import('../pages/api/v1/addTransaction')); +}); + +beforeEach(() => { + jest.clearAllMocks(); + + corsMock.mockResolvedValue(undefined); + addCorsCacheBustingHeadersMock.mockImplementation(() => undefined); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + enforceBodySizeMock.mockReturnValue(true); + verifyJwtMock.mockReturnValue({ address: ADDRESS }); + isBotJwtMock.mockReturnValue(false); + transactionFromHexMock.mockReturnValue({ _parsed: true }); + dbWalletFindUniqueMock.mockResolvedValue({ + id: WALLET_ID, + type: 'atLeast', + numRequiredSigners: 2, + signersAddresses: [ADDRESS], + }); + dbTransactionCreateMock.mockResolvedValue({ id: 'new-tx-id' }); +}); + +// --- tests --------------------------------------------------------------- + +describe('addTransaction API route validation', () => { + it('rejects malformed CBOR with 400 and does not write to the DB', async () => { + transactionFromHexMock.mockImplementation(() => { + throw new Error('cbor deserialization failed'); + }); + + const res = createMockResponse(); + await handler(buildReq(baseBody({ txCbor: 'deadbeef' })), res); + + expect(res.status).toHaveBeenCalledWith(400); + expect(res.json).toHaveBeenCalledWith( + expect.objectContaining({ + error: expect.stringContaining('Invalid transaction CBOR'), + }), + ); + expect(dbTransactionCreateMock).not.toHaveBeenCalled(); + }); + + it('rejects non-string txCbor with 400', async () => { + const res = createMockResponse(); + await handler(buildReq(baseBody({ txCbor: 12345 })), res); + + expect(res.status).toHaveBeenCalledWith(400); + expect(res.json).toHaveBeenCalledWith( + expect.objectContaining({ + error: expect.stringContaining('Invalid txCbor'), + }), + ); + expect(transactionFromHexMock).not.toHaveBeenCalled(); + expect(dbTransactionCreateMock).not.toHaveBeenCalled(); + }); + + it('rejects unparseable txJson string with 400', async () => { + const res = createMockResponse(); + await handler(buildReq(baseBody({ txJson: '{not json' })), res); + + expect(res.status).toHaveBeenCalledWith(400); + expect(res.json).toHaveBeenCalledWith( + expect.objectContaining({ + error: expect.stringContaining('Invalid txJson'), + }), + ); + expect(dbTransactionCreateMock).not.toHaveBeenCalled(); + }); + + it('persists the transaction when CBOR and JSON are both valid', async () => { + const res = createMockResponse(); + await handler(buildReq(baseBody()), res); + + expect(transactionFromHexMock).toHaveBeenCalledWith(VALID_CBOR); + expect(dbTransactionCreateMock).toHaveBeenCalledTimes(1); + expect(res.status).toHaveBeenCalledWith(201); + }); + + it('accepts a txJson that is already an object', async () => { + const res = createMockResponse(); + await handler( + buildReq(baseBody({ txJson: { outputs: [], certificates: [] } })), + res, + ); + + expect(dbTransactionCreateMock).toHaveBeenCalledTimes(1); + expect(res.status).toHaveBeenCalledWith(201); + }); +}); diff --git a/src/__tests__/apiSecurity.test.ts b/src/__tests__/apiSecurity.test.ts index 667c6959..56843542 100644 --- a/src/__tests__/apiSecurity.test.ts +++ b/src/__tests__/apiSecurity.test.ts @@ -67,6 +67,8 @@ describe("wallet router authorization", () => { db: baseDb as any, session: null, sessionAddress: null, + sessionWallets: [], + primaryWallet: null, ip: "3.3.3.3", }); @@ -99,6 +101,8 @@ describe("wallet router authorization", () => { db: baseDb as any, session: { user: { id: "addr1" }, expires: new Date().toISOString() } as any, sessionAddress: "addr1", + sessionWallets: [], + primaryWallet: null, ip: "4.4.4.4", }); @@ -132,6 +136,8 @@ describe("wallet router authorization", () => { db: baseDb as any, session: { user: { id: "addr1" }, expires: new Date().toISOString() } as any, sessionAddress: "addr1", + sessionWallets: [], + primaryWallet: null, ip: "5.5.5.5", }); diff --git a/src/__tests__/apiTestUtils.ts b/src/__tests__/apiTestUtils.ts new file mode 100644 index 00000000..4070cf12 --- /dev/null +++ b/src/__tests__/apiTestUtils.ts @@ -0,0 +1,52 @@ +import { jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; + +export type BotJwtPayload = { + address: string; + botId: string; + type: "bot"; +}; + +export const BOT_TEST_ADDRESS = "addr_test1qpbotintegrationfixture000000000000000000000000"; +export const BOT_TEST_ID = "bot-test-id"; + +export function makeBotJwtPayload( + overrides: Partial = {}, +): BotJwtPayload { + return { + address: BOT_TEST_ADDRESS, + botId: BOT_TEST_ID, + type: "bot", + ...overrides, + }; +} + +export type ResponseMock = NextApiResponse & { statusCode?: number }; + +export function createMockResponse(): ResponseMock { + const res = { + statusCode: undefined as number | undefined, + status: jest.fn<(code: number) => NextApiResponse>(), + json: jest.fn<(payload: unknown) => unknown>(), + end: jest.fn<() => void>(), + setHeader: jest.fn<(name: string, value: string) => void>(), + }; + + res.status.mockImplementation((code: number) => { + res.statusCode = code; + return res as unknown as NextApiResponse; + }); + res.json.mockImplementation((payload: unknown) => payload); + + return res as unknown as ResponseMock; +} + +export function makeBearerAuth(token = "bot-token"): Record { + return { authorization: `Bearer ${token}` }; +} + +export function makeApiRequest( + request: Partial, +): NextApiRequest { + return request as NextApiRequest; +} diff --git a/src/__tests__/bot-api-testing.md b/src/__tests__/bot-api-testing.md new file mode 100644 index 00000000..85e45955 --- /dev/null +++ b/src/__tests__/bot-api-testing.md @@ -0,0 +1,111 @@ +# Bot API Testing Guide + +## Bot-Runnable Route Matrix + +| Route | Unit Test File | Happy Path | Auth/Access Failure | +| --- | --- | --- | --- | +| `/api/v1/botAuth` | `src/__tests__/botAuth.test.ts` | token + bot id returned | invalid secret rejected | +| `/api/v1/botMe` | `src/__tests__/botMe.test.ts` | profile payload returned | non-bot token rejected | +| `/api/v1/createWallet` | `src/__tests__/createWallet.bot.test.ts` | wallet created + bot access upserted | invalid signer address rejected | +| `/api/v1/walletIds` | `src/__tests__/walletIds.bot.test.ts` | wallet ids returned | address mismatch rejected | +| `/api/v1/pendingTransactions` | `src/__tests__/pendingTransactions.bot.test.ts` | pending tx list returned | wallet access denied | +| `/api/v1/freeUtxos` | `src/__tests__/freeUtxos.bot.test.ts` | free UTxOs returned | wallet access denied | +| `/api/v1/addTransaction` | `src/__tests__/addTransaction.bot.test.ts` | tx record created | bot wallet access denied | +| `/api/v1/nativeScript` | `src/__tests__/nativeScript.bot.test.ts` | script response returned | address mismatch rejected | +| `/api/v1/governanceActiveProposals` | `src/__tests__/governanceActiveProposals.test.ts` | active proposals returned | missing/invalid token rejected | +| `/api/v1/botBallotsUpsert` | `src/__tests__/botBallotsUpsert.test.ts` | ballot upsert paths covered | input and conflict errors covered | +| `/api/v1/signTransaction` | `src/__tests__/signTransaction.bot.test.ts` | witness recorded for bot cosigner | non-cosigner role rejected | +| `/api/v1/submitDatum` | `src/__tests__/submitDatum.bot.test.ts` | signable datum created | invalid signature rejected | + +## New Bot Route Test Checklist + +- Add a `*.bot.test.ts` file in `src/__tests__/` with the route name. +- Use `createMockResponse()` and bot payload defaults from `src/__tests__/apiTestUtils.ts`. +- Cover at least: + - one success response with expected JSON shape, + - one auth/scope/access failure branch, + - one method/validation branch when route-specific risk is high. +- Keep network and chain helpers mocked; keep route logic and DB interactions under test. + +## Integration Smoke Tests + +- File: `src/__tests__/botApi.integration.test.ts` +- Default behavior: skipped unless `RUN_BOT_API_INTEGRATION=true` +- Purpose: exercise real Prisma DB writes/reads for bot auth, wallet access reads, mutating routes, and one signature-heavy route with mocked signature validator. + +### Required env for integration run + +- `RUN_BOT_API_INTEGRATION=true` +- `DATABASE_URL=` +- `JWT_SECRET=<32+ char secret>` +- `SKIP_ENV_VALIDATION=true` (recommended for test-only runs) + +## PR Workflow: Containers + CI Wallet Smoke + +- Workflow: `.github/workflows/pr-multisig-v1-smoke.yml` +- Triggers: `pull_request` and `workflow_dispatch` (manual test runs) +- Compose stack: `docker-compose.ci.yml` +- CI scripts: + - `scripts/ci/cli/bootstrap.ts` + - `scripts/ci/cli/route-chain.ts` (route-chain runner; filter with `CI_ROUTE_SCENARIOS`) + - `scripts/ci/cli/sign-transaction.ts` (ad-hoc sign helper) + - `scripts/ci/scenarios/manifest.ts` (scenario registry) + +### Required GitHub repository secrets + +- `CI_JWT_SECRET` (32+ chars) +- `CI_MNEMONIC_1` (space-separated words) +- `CI_MNEMONIC_2` (space-separated words) +- `CI_MNEMONIC_3` (space-separated words) +- `CI_BLOCKFROST_PREPROD_API_KEY` (required; transfer and signing scenarios use live preprod data) +- `CI_BLOCKFROST_MAINNET_API_KEY` (optional; only needed if smoke coverage is expanded to mainnet-dependent routes) + +### Runtime flags used by the workflow + +- `CI_NETWORK_ID` (default `0` for preprod/testnet) +- `CI_NUM_REQUIRED_SIGNERS` (default `2`; controls `numRequiredSigners` and hierarchical inner `atLeast.required`) +- `CI_WALLET_TYPES` (default `legacy,hierarchical,sdk`) +- `CI_SIGN_WALLET_TYPE` (which wallet type signing smoke targets: `legacy` | `hierarchical` | `sdk`) +- `SIGN_BROADCAST` (`true`; broadcast is always enabled for CI route-chain signing) +- `CI_TRANSFER_LOVELACE` (optional transfer amount for real-transfer scenario, default `2000000`) +- `CI_ROUTE_SCENARIOS` (optional comma-separated scenario ids for targeted route-chain runs) + +Validation behavior: + +- Invalid values in `CI_WALLET_TYPES` now fail fast (must be `legacy`, `hierarchical`, `sdk`). +- Unknown scenario ids in `CI_ROUTE_SCENARIOS` now fail fast with available ids listed. + +### What phase 1 validates + +- Starts Postgres + app containers on PR. +- Derives signer addresses from the three mnemonic secrets. +- Creates selected wallet types (`legacy`, `hierarchical`, `sdk`) through `/api/v1/createWallet`. +- Uses a nested payment script for `hierarchical` wallets (`all` wrapping `atLeast`) while keeping signer keys payment-only. +- Verifies route-chain health for bot routes (`walletIds`, `pendingTransactions`, `freeUtxos`, `signTransaction`) using shared bootstrap context. +- Executes a real transfer flow: + - build transfer tx via `/api/v1/addTransaction` + - sign and broadcast via `/api/v1/signTransaction` + - assert final state via `/api/v1/pendingTransactions` +- Uploads machine-readable route-chain report artifact from `ci-artifacts/ci-route-chain-report.json`. + +### Built-in route-chain scenarios + +- `scenario.pending-and-discovery` +- `scenario.pending-per-wallet` +- `scenario.ada-route-health` +- `scenario.real-transfer-and-sign` +- `scenario.final-assertions` + +### Add a new v1 route test step + +1. Add a new step module or helper in `scripts/ci/scenarios/`. + - You can start from `scripts/ci/scenarios/steps/template-route-step.ts`. +2. Implement the standard step contract: + - `id` + - `description` + - `execute(ctx)` with deterministic assertions + - optional `artifacts` for failure triage +3. Register the step in `scripts/ci/scenarios/manifest.ts`. +4. Run the route-chain smoke locally/CI and verify step-level report output. + +This keeps wallet bootstrap stable while route coverage grows through small, isolated step additions. diff --git a/src/__tests__/botApi.integration.test.ts b/src/__tests__/botApi.integration.test.ts new file mode 100644 index 00000000..56abceb0 --- /dev/null +++ b/src/__tests__/botApi.integration.test.ts @@ -0,0 +1,176 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { randomUUID } from "crypto"; +import { createMockResponse } from "./apiTestUtils"; +import { hashBotKeySecret } from "../lib/auth/botKey"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: () => true, + applyBotRateLimit: () => true, + applyStrictRateLimit: () => true, + enforceBodySize: () => true, +}), { virtual: true }); + +jest.mock("@/env", () => ({ + __esModule: true, + env: { + DATABASE_URL: process.env.DATABASE_URL, + NODE_ENV: "test", + }, +}), { virtual: true }); + +jest.mock("@meshsdk/core-cst", () => ({ + __esModule: true, + checkSignature: async () => true, +})); + +const runIntegration = process.env.RUN_BOT_API_INTEGRATION === "true"; +const describeIntegration = runIntegration ? describe : describe.skip; + +let botAuthHandler: (req: NextApiRequest, res: NextApiResponse) => Promise; +let botMeHandler: (req: NextApiRequest, res: NextApiResponse) => Promise; +let addTransactionHandler: (req: NextApiRequest, res: NextApiResponse) => Promise; +let submitDatumHandler: (req: NextApiRequest, res: NextApiResponse) => Promise; +let db: any; + +function firstJsonCall(res: ReturnType): T { + return (res.json as unknown as jest.Mock).mock.calls[0]?.[0] as T; +} + +describeIntegration("bot API integration smoke", () => { + beforeAll(async () => { + ({ db } = await import("../server/db")); + ({ default: botAuthHandler } = await import("../pages/api/v1/botAuth")); + ({ default: botMeHandler } = await import("../pages/api/v1/botMe")); + ({ default: addTransactionHandler } = await import("../pages/api/v1/addTransaction")); + ({ default: submitDatumHandler } = await import("../pages/api/v1/submitDatum")); + }); + + beforeEach(() => { + jest.clearAllMocks(); + corsMock.mockResolvedValue(undefined); + }); + + it("authenticates bot and fetches bot profile", async () => { + const suffix = randomUUID().replace(/-/g, "").slice(0, 12); + const ownerAddress = `owner_${suffix}`; + const paymentAddress = `addr_test1qpbotintegration${suffix}000000000000000000000000`; + const secret = `secret-${suffix}`; + + const botKey = await db.botKey.create({ + data: { + ownerAddress, + name: `bot-${suffix}`, + keyHash: hashBotKeySecret(secret), + scope: JSON.stringify(["multisig:create", "multisig:read", "multisig:sign"]), + }, + }); + + const authReq = { + method: "POST", + body: { botKeyId: botKey.id, secret, paymentAddress }, + } as unknown as NextApiRequest; + const authRes = createMockResponse(); + await botAuthHandler(authReq, authRes); + expect(authRes.status).toHaveBeenCalledWith(200); + const authBody = firstJsonCall<{ token: string; botId: string }>(authRes); + expect(authBody.token).toBeTruthy(); + + const meReq = { + method: "GET", + headers: { authorization: `Bearer ${authBody.token}` }, + query: {}, + } as unknown as NextApiRequest; + const meRes = createMockResponse(); + await botMeHandler(meReq, meRes); + expect(meRes.status).toHaveBeenCalledWith(200); + await db.botUser.deleteMany({ where: { botKeyId: botKey.id } }); + await db.botKey.delete({ where: { id: botKey.id } }); + }); + + it("runs mutating and signature-heavy bot routes against real db", async () => { + const suffix = randomUUID().replace(/-/g, "").slice(0, 12); + const paymentAddress = `addr_test1qpbotintegrationmut${suffix}000000000000000000000`; + const secret = `secret-mut-${suffix}`; + + const botKey = await db.botKey.create({ + data: { + ownerAddress: `owner_mut_${suffix}`, + name: `bot-mut-${suffix}`, + keyHash: hashBotKeySecret(secret), + scope: JSON.stringify(["multisig:read", "multisig:sign"]), + }, + }); + + const wallet = await db.wallet.create({ + data: { + name: `wallet-mut-${suffix}`, + description: null, + signersAddresses: [paymentAddress], + signersStakeKeys: [], + signersDRepKeys: [], + signersDescriptions: [""], + numRequiredSigners: 2, + scriptCbor: "deadbeef", + stakeCredentialHash: null, + type: "atLeast", + ownerAddress: "all", + }, + }); + + const authReq = { + method: "POST", + body: { botKeyId: botKey.id, secret, paymentAddress }, + } as unknown as NextApiRequest; + const authRes = createMockResponse(); + await botAuthHandler(authReq, authRes); + const authBody = firstJsonCall<{ token: string }>(authRes); + + const addReq = { + method: "POST", + headers: { authorization: `Bearer ${authBody.token}` }, + body: { + walletId: wallet.id, + address: paymentAddress, + txCbor: "deadbeef", + txJson: "{\"body\":{}}", + }, + } as unknown as NextApiRequest; + const addRes = createMockResponse(); + await addTransactionHandler(addReq, addRes); + expect(addRes.status).toHaveBeenCalledWith(201); + + const submitReq = { + method: "POST", + headers: { authorization: `Bearer ${authBody.token}`, origin: "https://integration.test" }, + body: { + walletId: wallet.id, + signature: "sig", + key: "key", + address: paymentAddress, + datum: "payload", + callbackUrl: "https://integration.test/callback", + }, + } as unknown as NextApiRequest; + const submitRes = createMockResponse(); + await submitDatumHandler(submitReq, submitRes); + expect(submitRes.status).toHaveBeenCalledWith(201); + + await db.transaction.deleteMany({ where: { walletId: wallet.id } }); + await db.signable.deleteMany({ where: { walletId: wallet.id } }); + await db.walletBotAccess.deleteMany({ where: { walletId: wallet.id } }); + await db.wallet.delete({ where: { id: wallet.id } }); + await db.botUser.deleteMany({ where: { botKeyId: botKey.id } }); + await db.botKey.delete({ where: { id: botKey.id } }); + }); +}); diff --git a/src/__tests__/botAuth.test.ts b/src/__tests__/botAuth.test.ts new file mode 100644 index 00000000..a9cf3122 --- /dev/null +++ b/src/__tests__/botAuth.test.ts @@ -0,0 +1,120 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { createMockResponse } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyStrictRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const enforceBodySizeMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean>(); +const verifyBotKeySecretMock = jest.fn<(secret: string, hash: string) => boolean>(); +const parseScopeMock = jest.fn<(scope: string) => string[]>(); +const scopeIncludesMock = jest.fn<(scopes: string[], minScope: string) => boolean>(); +const signMock: jest.Mock = jest.fn(); +const findBotKeyMock: jest.Mock = jest.fn(); +const findBotUserByAddressMock: jest.Mock = jest.fn(); +const upsertBotUserMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyStrictRateLimit: applyStrictRateLimitMock, + enforceBodySize: enforceBodySizeMock, +}), { virtual: true }); + +jest.mock("@/lib/auth/botKey", () => ({ + __esModule: true, + verifyBotKeySecret: verifyBotKeySecretMock, + parseScope: parseScopeMock, + scopeIncludes: scopeIncludesMock, +}), { virtual: true }); + +jest.mock("jsonwebtoken", () => ({ + __esModule: true, + sign: signMock, +})); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: { + botKey: { findUnique: findBotKeyMock }, + botUser: { + findUnique: findBotUserByAddressMock, + upsert: upsertBotUserMock, + }, + }, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + process.env.JWT_SECRET = "x".repeat(32); + ({ default: handler } = await import("../pages/api/v1/botAuth")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyStrictRateLimitMock.mockReturnValue(true); + enforceBodySizeMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyBotKeySecretMock.mockReturnValue(true); + parseScopeMock.mockReturnValue(["multisig:read"]); + scopeIncludesMock.mockReturnValue(true); + signMock.mockReturnValue("signed-jwt"); + (findBotKeyMock as any).mockResolvedValue({ + id: "bot-key-id", + keyHash: "hashed", + scope: JSON.stringify(["multisig:read"]), + }); + (findBotUserByAddressMock as any).mockResolvedValue(null); + (upsertBotUserMock as any).mockResolvedValue({ + id: "bot-user-id", + paymentAddress: "addr_test1qpbot00000000000000000000000000000000000", + }); +}); + +describe("botAuth API", () => { + it("returns 401 for invalid bot secret", async () => { + verifyBotKeySecretMock.mockReturnValue(false); + const req = { + method: "POST", + body: { + botKeyId: "bot-key-id", + secret: "wrong", + paymentAddress: "addr_test1qpbot00000000000000000000000000000000000", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(401); + expect(res.json).toHaveBeenCalledWith({ error: "Invalid bot key" }); + }); + + it("returns token and botId for valid request", async () => { + const req = { + method: "POST", + body: { + botKeyId: "bot-key-id", + secret: "secret", + paymentAddress: "addr_test1qpbot00000000000000000000000000000000000", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(upsertBotUserMock).toHaveBeenCalled(); + expect(signMock).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith({ + token: "signed-jwt", + botId: "bot-user-id", + }); + }); +}); diff --git a/src/__tests__/botBallotsUpsert.test.ts b/src/__tests__/botBallotsUpsert.test.ts index 1d487b77..4c5d202c 100644 --- a/src/__tests__/botBallotsUpsert.test.ts +++ b/src/__tests__/botBallotsUpsert.test.ts @@ -6,22 +6,24 @@ const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise< const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); const enforceBodySizeMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean>(); -const verifyJwtMock = jest.fn(); -const isBotJwtMock = jest.fn(); -const assertBotWalletAccessMock = jest.fn(); -const findBotUserMock = jest.fn(); -const transactionMock = jest.fn(); -const parseScopeMock = jest.fn(); -const scopeIncludesMock = jest.fn(); +const verifyJwtMock = jest.fn<() => unknown>(); +const isBotJwtMock = jest.fn<() => boolean>(); +const assertBotWalletAccessMock = jest.fn<() => Promise>(); +const findBotUserMock = jest.fn<() => Promise>(); +const transactionMock = jest.fn<(cb: (tx: typeof txMock) => Promise) => Promise>(); +const parseScopeMock = jest.fn<(scope: string) => string[]>(); +const scopeIncludesMock = jest.fn<(scopes: string[], required: string) => boolean>(); const isValidChoiceMock = jest.fn(); -const parseProposalIdMock = jest.fn(); +const parseProposalIdMock = jest.fn< + (value: string) => { txHash: string; certIndex: number } +>(); const txMock = { ballot: { - findUnique: jest.fn(), - findMany: jest.fn(), - create: jest.fn(), - updateMany: jest.fn(), + findUnique: jest.fn<() => Promise>(), + findMany: jest.fn<() => Promise>(), + create: jest.fn<() => Promise>(), + updateMany: jest.fn<() => Promise>(), }, }; @@ -132,14 +134,14 @@ beforeEach(() => { corsMock.mockResolvedValue(undefined); verifyJwtMock.mockReturnValue({ address: "addr_test1", botId: "bot-1", type: "bot" }); isBotJwtMock.mockReturnValue(true); - parseScopeMock.mockImplementation((scope: string) => JSON.parse(scope)); - scopeIncludesMock.mockImplementation((scopes: string[], required: string) => + parseScopeMock.mockImplementation((scope) => JSON.parse(scope) as string[]); + scopeIncludesMock.mockImplementation((scopes, required) => scopes.includes(required), ); isValidChoiceMock.mockReturnValue(true); - parseProposalIdMock.mockImplementation((value: string) => { + parseProposalIdMock.mockImplementation((value) => { const [txHash, certIndex] = value.split("#"); - return { txHash, certIndex: Number(certIndex) }; + return { txHash: txHash ?? "", certIndex: Number(certIndex) }; }); findBotUserMock.mockResolvedValue({ id: "bot-1", diff --git a/src/__tests__/botMe.test.ts b/src/__tests__/botMe.test.ts new file mode 100644 index 00000000..9e146990 --- /dev/null +++ b/src/__tests__/botMe.test.ts @@ -0,0 +1,89 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const findBotUserMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: { + botUser: { findUnique: findBotUserMock }, + }, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/botMe")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + (findBotUserMock as any).mockResolvedValue({ + id: "bot-test-id", + paymentAddress: "addr_test1qpbot", + displayName: null, + botKey: { ownerAddress: "addr_test1qphuman", name: "My Bot" }, + }); +}); + +describe("botMe API", () => { + it("rejects non-bot tokens", async () => { + isBotJwtMock.mockReturnValue(false); + const req = { + method: "GET", + headers: makeBearerAuth(), + query: {}, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(403); + }); + + it("returns bot profile for valid bot token", async () => { + const req = { + method: "GET", + headers: makeBearerAuth(), + query: {}, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith({ + botId: "bot-test-id", + paymentAddress: "addr_test1qpbot", + displayName: null, + botName: "My Bot", + ownerAddress: "addr_test1qphuman", + }); + }); +}); diff --git a/src/__tests__/ciHttp.test.ts b/src/__tests__/ciHttp.test.ts new file mode 100644 index 00000000..5ad6e4cc --- /dev/null +++ b/src/__tests__/ciHttp.test.ts @@ -0,0 +1,119 @@ +import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import { requestJson } from "../../scripts/ci/framework/http"; + +function jsonResponse(status: number, data: unknown, headers?: HeadersInit): Response { + return new Response(JSON.stringify(data), { status, headers }); +} + +describe("CI requestJson retry policy", () => { + let fetchMock: jest.SpiedFunction; + + beforeEach(() => { + fetchMock = jest.spyOn(globalThis, "fetch"); + }); + + afterEach(() => { + fetchMock.mockRestore(); + }); + + it("retries transient 429 responses", async () => { + fetchMock + .mockResolvedValueOnce(jsonResponse(429, { error: "Too many requests" })) + .mockResolvedValueOnce(jsonResponse(200, { ok: true })); + + const response = await requestJson<{ ok?: boolean }>({ + url: "http://example.test/rate-limited", + retries: 1, + retryDelayMs: 0, + maxRetryDelayMs: 0, + }); + + expect(response).toEqual({ status: 200, data: { ok: true } }); + expect(fetchMock).toHaveBeenCalledTimes(2); + }); + + it("does not retry non-transient validation responses", async () => { + fetchMock.mockResolvedValueOnce(jsonResponse(400, { error: "Bad Request" })); + + const response = await requestJson<{ error?: string }>({ + url: "http://example.test/bad-request", + retries: 3, + retryDelayMs: 0, + maxRetryDelayMs: 0, + }); + + expect(response).toEqual({ status: 400, data: { error: "Bad Request" } }); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); + + it("returns the final transient response after retries are exhausted", async () => { + fetchMock + .mockResolvedValueOnce(jsonResponse(429, { error: "Too many requests" })) + .mockResolvedValueOnce(jsonResponse(429, { error: "Still rate limited" })); + + const response = await requestJson<{ error?: string }>({ + url: "http://example.test/rate-limited", + retries: 1, + retryDelayMs: 0, + maxRetryDelayMs: 0, + }); + + expect(response).toEqual({ status: 429, data: { error: "Still rate limited" } }); + expect(fetchMock).toHaveBeenCalledTimes(2); + }); + + it("does not retry transient responses when retries are disabled", async () => { + fetchMock.mockResolvedValueOnce( + jsonResponse(502, { + error: "Transaction witness recorded, but submission to network failed", + }), + ); + + const response = await requestJson<{ error?: string }>({ + url: "http://example.test/signTransaction", + method: "POST", + body: { transactionId: "tx-1" }, + retries: 0, + }); + + expect(response).toEqual({ + status: 502, + data: { + error: "Transaction witness recorded, but submission to network failed", + }, + }); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); + + it("retries failed fetch attempts", async () => { + fetchMock + .mockRejectedValueOnce(new Error("connection reset")) + .mockResolvedValueOnce(jsonResponse(200, { ok: true })); + + const response = await requestJson<{ ok?: boolean }>({ + url: "http://example.test/flaky", + retries: 1, + retryDelayMs: 0, + maxRetryDelayMs: 0, + }); + + expect(response).toEqual({ status: 200, data: { ok: true } }); + expect(fetchMock).toHaveBeenCalledTimes(2); + }); + + it("rejects BigInt request bodies before fetch retries", async () => { + await expect( + requestJson({ + url: "http://example.test/bigint", + method: "POST", + body: { + nested: { + selectedLovelace: 1n, + }, + }, + }), + ).rejects.toThrow(/non-JSON BigInt at body\.nested\.selectedLovelace/); + + expect(fetchMock).not.toHaveBeenCalled(); + }); +}); diff --git a/src/__tests__/ciScenarioManifest.test.ts b/src/__tests__/ciScenarioManifest.test.ts new file mode 100644 index 00000000..0fae816f --- /dev/null +++ b/src/__tests__/ciScenarioManifest.test.ts @@ -0,0 +1,68 @@ +import { describe, expect, it } from "@jest/globals"; +import { getScenarioManifest, ROUTE_SCENARIO_IDS } from "../../scripts/ci/scenarios/manifest"; +import type { CIBootstrapContext, CIWalletType } from "../../scripts/ci/framework/types"; + +const mkContext = (walletTypes: CIWalletType[]): CIBootstrapContext => ({ + schemaVersion: 3, + createdAt: "2026-04-29T00:00:00.000Z", + apiBaseUrl: "http://localhost:3000", + networkId: 0, + walletTypes, + wallets: walletTypes.map((type) => ({ + type, + walletId: `${type}-wallet-id`, + walletAddress: `addr_test_${type}`, + signerAddresses: ["addr_test_signer_1", "addr_test_signer_2", "addr_test_signer_3"], + })), + bots: [ + { + id: "bot-1", + paymentAddress: "addr_test_signer_1", + botKeyId: "bot-key-1", + botId: "bot-user-1", + }, + ], + defaultBotId: "bot-1", + signerAddresses: ["addr_test_signer_1", "addr_test_signer_2", "addr_test_signer_3"], + signerStakeAddresses: ["stake_test_1", "stake_test_2", "stake_test_3"], +}); + +describe("route-chain scenario manifest", () => { + it("exposes all known scenario ids for filter validation", () => { + expect(ROUTE_SCENARIO_IDS).toContain("scenario.proxy-smoke"); + expect(ROUTE_SCENARIO_IDS).toContain("scenario.real-transfer-and-sign"); + }); + + it("runs create-wallet before request-heavy default-bot scenarios", () => { + const scenarios = getScenarioManifest(mkContext(["legacy", "hierarchical", "sdk"])); + const ids = scenarios.map((scenario) => scenario.id); + + expect(ids.indexOf("scenario.create-wallet")).toBeLessThan( + ids.indexOf("scenario.bot-identity"), + ); + expect(ids.indexOf("scenario.create-wallet")).toBeLessThan( + ids.indexOf("scenario.auth-plane"), + ); + expect(ids.indexOf("scenario.create-wallet")).toBeLessThan( + ids.indexOf("scenario.proxy-smoke"), + ); + }); + + it("builds a proxy-smoke subset without requiring ring-transfer wallets", () => { + const scenarios = getScenarioManifest(mkContext(["legacy"]), ["scenario.proxy-smoke"]); + + expect(scenarios.map((scenario) => scenario.id)).toEqual(["scenario.proxy-smoke"]); + }); + + it("builds a create-wallet subset without running prior auth/proxy scenarios", () => { + const scenarios = getScenarioManifest(mkContext(["legacy"]), ["scenario.create-wallet"]); + + expect(scenarios.map((scenario) => scenario.id)).toEqual(["scenario.create-wallet"]); + }); + + it("still fails clearly when ring transfer is requested without all wallet types", () => { + expect(() => + getScenarioManifest(mkContext(["legacy"]), ["scenario.real-transfer-and-sign"]), + ).toThrow(/Ring transfer scenario requires wallet types/); + }); +}); diff --git a/src/__tests__/ciSigningSelection.test.ts b/src/__tests__/ciSigningSelection.test.ts new file mode 100644 index 00000000..5cf729a1 --- /dev/null +++ b/src/__tests__/ciSigningSelection.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, it } from "@jest/globals"; +import { + SIGN_TRANSACTION_REQUEST_OPTIONS, + selectPendingTransactionForSigning, +} from "../../scripts/ci/scenarios/flows/signingFlow"; + +describe("route-chain pending transaction selection", () => { + it("does not retry signTransaction after a witness may have been recorded", () => { + expect(SIGN_TRANSACTION_REQUEST_OPTIONS).toEqual({ retries: 0 }); + }); + + it("selects the preferred transaction when present", () => { + expect( + selectPendingTransactionForSigning( + [ + { id: "stale", txCbor: "deadbeef" }, + { id: "target", txCbor: "cafebabe" }, + ], + "target", + ), + ).toEqual({ id: "target", txCbor: "cafebabe" }); + }); + + it("fails instead of falling back when the preferred transaction is missing", () => { + expect(() => + selectPendingTransactionForSigning( + [ + { id: "stale", txCbor: "deadbeef" }, + { id: "other", txCbor: "cafebabe" }, + ], + "target", + ), + ).toThrow(/Preferred pending transaction target was not found/); + }); + + it("fails instead of falling back when the preferred transaction has no txCbor", () => { + expect(() => + selectPendingTransactionForSigning( + [ + { id: "target" }, + { id: "other", txCbor: "cafebabe" }, + ], + "target", + ), + ).toThrow(/Preferred pending transaction target does not include txCbor/); + }); + + it("keeps the old first-signable fallback when no preferred id is provided", () => { + expect( + selectPendingTransactionForSigning([ + { id: "empty" }, + { id: "first-signable", txCbor: "deadbeef" }, + ]), + ).toEqual({ id: "first-signable", txCbor: "deadbeef" }); + }); +}); diff --git a/src/__tests__/common.walletType.test.ts b/src/__tests__/common.walletType.test.ts new file mode 100644 index 00000000..8d8333ac --- /dev/null +++ b/src/__tests__/common.walletType.test.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from "@jest/globals"; +import { getWalletType } from "@/utils/common"; +import { DbWalletWithLegacy } from "@/types/wallet"; + +function makeWallet(overrides: Partial = {}): DbWalletWithLegacy { + return { + signersStakeKeys: [], + signersDRepKeys: [], + rawImportBodies: null, + ...overrides, + } as unknown as DbWalletWithLegacy; +} + +describe("getWalletType", () => { + it("returns summon when raw import multisig body is present", () => { + const wallet = makeWallet({ + rawImportBodies: { + multisig: { + address: "addr_test1...", + }, + }, + signersStakeKeys: ["stake_test1..."], + signersDRepKeys: ["drep_key"], + }); + + expect(getWalletType(wallet)).toBe("summon"); + }); + + it("returns legacy when stake/drep arrays only contain empty values", () => { + const wallet = makeWallet({ + signersStakeKeys: ["", " "], + signersDRepKeys: ["", " "], + }); + + expect(getWalletType(wallet)).toBe("legacy"); + }); + + it("returns sdk when there is at least one non-empty trimmed stake key", () => { + const wallet = makeWallet({ + signersStakeKeys: [" ", "stake_test1uq..."], + signersDRepKeys: ["", " "], + }); + + expect(getWalletType(wallet)).toBe("sdk"); + }); + + it("returns sdk when there is at least one non-empty trimmed drep key", () => { + const wallet = makeWallet({ + signersStakeKeys: ["", " "], + signersDRepKeys: [" ", "drep_key_hash"], + }); + + expect(getWalletType(wallet)).toBe("sdk"); + }); +}); diff --git a/src/__tests__/completeTxWithFreshCostModels.test.ts b/src/__tests__/completeTxWithFreshCostModels.test.ts new file mode 100644 index 00000000..16b6f7cf --- /dev/null +++ b/src/__tests__/completeTxWithFreshCostModels.test.ts @@ -0,0 +1,208 @@ +import { beforeEach, describe, expect, it, jest } from "@jest/globals"; + +const insertedLanguages: string[] = []; +const costModelValues: number[][] = []; +const setScriptDataHashMock = jest.fn(); +const hashScriptDataMock = jest.fn(() => ({ hash: "fresh-script-data-hash" })); + +class MockCostModel { + values: number[] = []; + + static new() { + const model = new MockCostModel(); + costModelValues.push(model.values); + return model; + } + + set(index: number, cost: { value: number }) { + this.values[index] = cost.value; + return cost; + } +} + +class MockCostmdls { + static new() { + return new MockCostmdls(); + } + + insert(language: { label: string }, _costModel: MockCostModel) { + insertedLanguages.push(language.label); + return undefined; + } +} + +class MockLanguage { + static new_plutus_v1() { + return { label: "V1" }; + } + + static new_plutus_v2() { + return { label: "V2" }; + } + + static new_plutus_v3() { + return { label: "V3" }; + } +} + +class MockInt { + static new_i32(value: number) { + return { value }; + } +} + +class MockTransaction { + private static redeemerCount = 0; + private static updatedHex = "updated-tx-hex"; + + static configure(args: { redeemerCount: number; updatedHex?: string }) { + MockTransaction.redeemerCount = args.redeemerCount; + MockTransaction.updatedHex = args.updatedHex ?? "updated-tx-hex"; + } + + static from_hex(hex: string) { + return { + witness_set: () => ({ + redeemers: () => + MockTransaction.redeemerCount > 0 + ? { len: () => MockTransaction.redeemerCount } + : undefined, + plutus_data: () => ({ datum: true }), + }), + body: () => ({ set_script_data_hash: setScriptDataHashMock }), + auxiliary_data: () => ({ metadata: true }), + is_valid: () => true, + to_hex: () => hex, + }; + } + + static new() { + return { + set_is_valid: jest.fn(), + to_hex: () => MockTransaction.updatedHex, + }; + } +} + +jest.mock( + "@meshsdk/core-csl", + () => ({ + __esModule: true, + csl: { + CostModel: MockCostModel, + Costmdls: MockCostmdls, + Int: MockInt, + Language: MockLanguage, + Transaction: MockTransaction, + hash_script_data: hashScriptDataMock, + }, + }), + { virtual: true }, +); + +jest.mock( + "@/env", + () => ({ + __esModule: true, + env: { + NEXT_PUBLIC_BLOCKFROST_API_KEY_PREPROD: "preprod-key", + NEXT_PUBLIC_BLOCKFROST_API_KEY_MAINNET: "mainnet-key", + }, + }), + { virtual: true }, +); + +describe("refreshScriptDataHash", () => { + beforeEach(() => { + insertedLanguages.length = 0; + costModelValues.length = 0; + setScriptDataHashMock.mockClear(); + hashScriptDataMock.mockClear(); + MockTransaction.configure({ redeemerCount: 0 }); + }); + + it("leaves transactions without redeemers unchanged", async () => { + const { refreshScriptDataHash } = await import("@/lib/completeTxWithFreshCostModels"); + + expect(refreshScriptDataHash("unsigned-tx-hex", {}, {})).toBe("unsigned-tx-hex"); + expect(hashScriptDataMock).not.toHaveBeenCalled(); + expect(setScriptDataHashMock).not.toHaveBeenCalled(); + }); + + it("recomputes script data hash with Plutus V3 cost_models_raw arrays", async () => { + MockTransaction.configure({ redeemerCount: 1, updatedHex: "fresh-tx-hex" }); + const { refreshScriptDataHash } = await import("@/lib/completeTxWithFreshCostModels"); + + const refreshed = refreshScriptDataHash( + "unsigned-tx-hex", + { + PlutusV3: [10, 20], + }, + { + mints: [ + { + type: "Plutus", + scriptSource: { script: { version: "V3" } }, + }, + ], + }, + ); + + expect(refreshed).toBe("fresh-tx-hex"); + expect(insertedLanguages).toEqual(["V3"]); + expect(costModelValues).toEqual([[10, 20]]); + expect(hashScriptDataMock).toHaveBeenCalled(); + expect(setScriptDataHashMock).toHaveBeenCalledWith({ hash: "fresh-script-data-hash" }); + }); + + it("orders indexed cost model objects by numeric key", async () => { + MockTransaction.configure({ redeemerCount: 1, updatedHex: "fresh-tx-hex" }); + const { refreshScriptDataHash } = await import("@/lib/completeTxWithFreshCostModels"); + + refreshScriptDataHash( + "unsigned-tx-hex", + { + PlutusV3: { + "2": 30, + "0": 10, + "1": 20, + }, + }, + { + mints: [ + { + type: "Plutus", + scriptSource: { script: { version: "V3" } }, + }, + ], + }, + ); + + expect(costModelValues).toEqual([[10, 20, 30]]); + }); + + it("rejects named cost_models objects that are not in ledger order", async () => { + MockTransaction.configure({ redeemerCount: 1 }); + const { refreshScriptDataHash } = await import("@/lib/completeTxWithFreshCostModels"); + + expect(() => + refreshScriptDataHash( + "unsigned-tx-hex", + { + PlutusV3: { + "addInteger-cpu-arguments-intercept": 10, + "addInteger-cpu-arguments-slope": 20, + }, + }, + { + mints: [ + { + type: "Plutus", + scriptSource: { script: { version: "V3" } }, + }, + ], + }, + ), + ).toThrow(/cost_models_raw/); + }); +}); diff --git a/src/__tests__/createPendingMultisigTransaction.test.ts b/src/__tests__/createPendingMultisigTransaction.test.ts new file mode 100644 index 00000000..9c53ce87 --- /dev/null +++ b/src/__tests__/createPendingMultisigTransaction.test.ts @@ -0,0 +1,99 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { PrismaClient } from "@prisma/client"; + +const submitTxMock = jest.fn(); + +jest.mock("@/utils/get-provider", () => ({ + __esModule: true, + getProvider: () => ({ submitTx: submitTxMock }), +}), { virtual: true }); + +let createPendingMultisigTransaction: typeof import("@/lib/server/createPendingMultisigTransaction").createPendingMultisigTransaction; + +function makeDb() { + return { + transaction: { + create: jest.fn().mockResolvedValue({ id: "tx-1" }), + }, + } as unknown as PrismaClient; +} + +const baseArgs = { + walletId: "wallet-1", + wallet: { numRequiredSigners: 2, type: "atLeast" }, + proposerAddress: "addr_test_proposer", + txCbor: "tx-cbor", + txJson: { body: "json" }, + description: "test transaction", + network: 0, +}; + +describe("createPendingMultisigTransaction", () => { + beforeAll(async () => { + ({ createPendingMultisigTransaction } = await import("@/lib/server/createPendingMultisigTransaction")); + }); + + beforeEach(() => { + jest.clearAllMocks(); + submitTxMock.mockResolvedValue("submitted-hash"); + }); + + it("defaults pending transactions to signed by the proposer", async () => { + const db = makeDb(); + + await createPendingMultisigTransaction(db, baseArgs); + + expect(db.transaction.create).toHaveBeenCalledWith({ + data: expect.objectContaining({ + walletId: "wallet-1", + signedAddresses: ["addr_test_proposer"], + }), + }); + }); + + it("allows server-built transactions to start with no signed addresses", async () => { + const db = makeDb(); + + await createPendingMultisigTransaction(db, { + ...baseArgs, + initialSignedAddresses: [], + }); + + expect(db.transaction.create).toHaveBeenCalledWith({ + data: expect.objectContaining({ + signedAddresses: [], + }), + }); + }); + + it("keeps one-signer server-built transactions pending until a witness exists", async () => { + const db = makeDb(); + + await createPendingMultisigTransaction(db, { + ...baseArgs, + wallet: { numRequiredSigners: 1, type: "all" }, + initialSignedAddresses: [], + }); + + expect(db.transaction.create).toHaveBeenCalledWith({ + data: expect.objectContaining({ + signedAddresses: [], + }), + }); + expect(submitTxMock).not.toHaveBeenCalled(); + }); + + it("submits single-signer transactions without creating a pending row", async () => { + const db = makeDb(); + + await expect( + createPendingMultisigTransaction(db, { + ...baseArgs, + wallet: { numRequiredSigners: 1, type: "atLeast" }, + }), + ).resolves.toBe("submitted-hash"); + + expect(submitTxMock).toHaveBeenCalledWith("tx-cbor"); + expect(db.transaction.create).not.toHaveBeenCalled(); + }); +}); diff --git a/src/__tests__/createWallet.bot.test.ts b/src/__tests__/createWallet.bot.test.ts new file mode 100644 index 00000000..5611e0ce --- /dev/null +++ b/src/__tests__/createWallet.bot.test.ts @@ -0,0 +1,454 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { BotWalletRole } from "@prisma/client"; +import { createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string, limit?: number) => boolean>(); +const enforceBodySizeMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const parseScopeMock: jest.Mock = jest.fn(); +const scopeIncludesMock: jest.Mock = jest.fn(); +const resolvePaymentKeyHashMock: jest.Mock = jest.fn(); +const resolveStakeKeyHashMock: jest.Mock = jest.fn(); +const serializeNativeScriptMock: jest.Mock = jest.fn(); +const findBotUserMock: jest.Mock = jest.fn(); +const createWalletMock: jest.Mock = jest.fn(); +const upsertWalletAccessMock: jest.Mock = jest.fn(); +const getScriptMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, + enforceBodySize: enforceBodySizeMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/lib/auth/botKey", () => ({ + __esModule: true, + parseScope: parseScopeMock, + scopeIncludes: scopeIncludesMock, +}), { virtual: true }); + +jest.mock("@meshsdk/core", () => ({ + __esModule: true, + resolvePaymentKeyHash: resolvePaymentKeyHashMock, + resolveStakeKeyHash: resolveStakeKeyHashMock, + serializeNativeScript: serializeNativeScriptMock, +}), { virtual: true }); + +jest.mock("@/utils/multisigSDK", () => ({ + __esModule: true, + MultisigWallet: class { + getScript() { + return getScriptMock(); + } + }, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: { + botUser: { findUnique: findBotUserMock }, + wallet: { create: createWalletMock }, + walletBotAccess: { upsert: upsertWalletAccessMock }, + }, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/createWallet")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + enforceBodySizeMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + parseScopeMock.mockReturnValue(["multisig:create", "multisig:read"]); + scopeIncludesMock.mockReturnValue(true); + resolvePaymentKeyHashMock.mockReturnValue("payment-hash"); + resolveStakeKeyHashMock.mockReturnValue("stake-hash"); + serializeNativeScriptMock.mockReturnValue({ + scriptCbor: "explicit-script-cbor", + address: "addr_explicit_script", + }); + getScriptMock.mockReturnValue({ scriptCbor: "script-cbor", address: "addr_wallet_script" }); + (findBotUserMock as any).mockResolvedValue({ id: "bot-test-id", botKey: { scope: JSON.stringify(["multisig:create"]) } }); + (createWalletMock as any).mockResolvedValue({ id: "wallet-1", name: "Bot Wallet" }); + (upsertWalletAccessMock as any).mockResolvedValue({ role: BotWalletRole.cosigner }); +}); + +describe("createWallet bot API", () => { + it("returns 400 for invalid signer address", async () => { + resolvePaymentKeyHashMock.mockImplementation(() => { + throw new Error("bad address"); + }); + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: ["invalid"], + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(400); + }); + + it("creates wallet and bot access for valid bot payload", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: ["addr_test1qpsigner0000000000000000000000000000000000"], + signersDescriptions: ["Signer 1"], + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(createWalletMock).toHaveBeenCalled(); + expect(upsertWalletAccessMock).toHaveBeenCalledWith(expect.objectContaining({ + create: expect.objectContaining({ role: BotWalletRole.cosigner }), + })); + expect(serializeNativeScriptMock).toHaveBeenCalled(); + expect(getScriptMock).not.toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ + walletId: "wallet-1", + address: "addr_explicit_script", + name: "Bot Wallet", + }); + }); + + it("preserves signer input order for legacy payment script", async () => { + resolvePaymentKeyHashMock + .mockReturnValueOnce("hash-2") + .mockReturnValueOnce("hash-1"); + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: [ + "addr_test1qpsigner0000000000000000000000000000000000", + "addr_test1qpsigner1111111111111111111111111111111111", + ], + numRequiredSigners: 2, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(serializeNativeScriptMock).toHaveBeenCalledWith( + { + type: "atLeast", + required: 2, + scripts: [ + { type: "sig", keyHash: "hash-2" }, + { type: "sig", keyHash: "hash-1" }, + ], + }, + undefined, + 1, + true, + ); + expect(res.status).toHaveBeenCalledWith(201); + }); + + it("creates wallet from explicit payment native script", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: ["addr_test1qpsigner0000000000000000000000000000000000"], + scriptType: "all", + paymentNativeScript: { + type: "all", + scripts: [ + { + type: "atLeast", + required: 1, + scripts: [{ type: "sig", keyHash: "payment-hash" }], + }, + ], + }, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(serializeNativeScriptMock).toHaveBeenCalled(); + expect(getScriptMock).not.toHaveBeenCalled(); + expect(createWalletMock).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + scriptCbor: "explicit-script-cbor", + type: "all", + numRequiredSigners: 1, + }), + }), + ); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ + walletId: "wallet-1", + address: "addr_explicit_script", + name: "Bot Wallet", + }); + }); + + it("derives type=all from explicit payment script root", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: ["addr_test1qpsigner0000000000000000000000000000000000"], + paymentNativeScript: { + type: "all", + scripts: [ + { + type: "atLeast", + required: 1, + scripts: [{ type: "sig", keyHash: "payment-hash" }], + }, + ], + }, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(createWalletMock).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + type: "all", + numRequiredSigners: 1, + }), + }), + ); + expect(res.status).toHaveBeenCalledWith(201); + }); + + it("persists the computed threshold for explicit hierarchical scripts", async () => { + resolvePaymentKeyHashMock + .mockReturnValueOnce("hash-1") + .mockReturnValueOnce("hash-2") + .mockReturnValueOnce("hash-3"); + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: [ + "addr_test1qpsigner0000000000000000000000000000000000", + "addr_test1qpsigner1111111111111111111111111111111111", + "addr_test1qpsigner2222222222222222222222222222222222", + ], + scriptType: "all", + paymentNativeScript: { + type: "all", + scripts: [ + { + type: "atLeast", + required: 2, + scripts: [ + { type: "sig", keyHash: "hash-1" }, + { type: "sig", keyHash: "hash-2" }, + { type: "sig", keyHash: "hash-3" }, + ], + }, + ], + }, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(createWalletMock).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + type: "all", + numRequiredSigners: 2, + }), + }), + ); + expect(res.status).toHaveBeenCalledWith(201); + }); + + it("keeps flat all wallets without explicit scripts as all-of-N metadata", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: [ + "addr_test1qpsigner0000000000000000000000000000000000", + "addr_test1qpsigner1111111111111111111111111111111111", + ], + scriptType: "all", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(createWalletMock).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + type: "all", + numRequiredSigners: null, + }), + }), + ); + expect(res.status).toHaveBeenCalledWith(201); + }); + + it("accepts explicit hierarchical script with inner any", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: [ + "addr_test1qpsigner0000000000000000000000000000000000", + "addr_test1qpsigner1111111111111111111111111111111111", + ], + paymentNativeScript: { + type: "all", + scripts: [ + { + type: "any", + scripts: [ + { type: "sig", keyHash: "payment-hash" }, + { type: "sig", keyHash: "payment-hash" }, + ], + }, + ], + }, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(201); + }); + + it("accepts explicit hierarchical script with inner all", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: ["addr_test1qpsigner0000000000000000000000000000000000"], + paymentNativeScript: { + type: "all", + scripts: [ + { + type: "all", + scripts: [{ type: "sig", keyHash: "payment-hash" }], + }, + ], + }, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(201); + }); + + it("returns 400 for malformed payment native script", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: ["addr_test1qpsigner0000000000000000000000000000000000"], + paymentNativeScript: { + type: "all", + scripts: [], + }, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(400); + }); + + it("returns 400 when explicit payment native script root is not all", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: ["addr_test1qpsigner0000000000000000000000000000000000"], + paymentNativeScript: { + type: "atLeast", + required: 1, + scripts: [{ type: "sig", keyHash: "payment-hash" }], + }, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(400); + }); + + it("returns 400 when payment native script hashes do not match signers", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + name: "Wallet", + signersAddresses: ["addr_test1qpsigner0000000000000000000000000000000000"], + paymentNativeScript: { + type: "all", + scripts: [ + { + type: "sig", + keyHash: "other-hash", + }, + ], + }, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(400); + }); +}); diff --git a/src/__tests__/freeUtxos.bot.test.ts b/src/__tests__/freeUtxos.bot.test.ts new file mode 100644 index 00000000..62a7407b --- /dev/null +++ b/src/__tests__/freeUtxos.bot.test.ts @@ -0,0 +1,208 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { BOT_TEST_ADDRESS, createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const getBotWalletAccessMock: jest.Mock = jest.fn(); +const assertBotWalletAccessMock: jest.Mock = jest.fn(); +const findPendingTransactionsMock: jest.Mock = jest.fn(); +const buildMultisigWalletMock: jest.Mock = jest.fn(); +const addressToNetworkMock: jest.Mock = jest.fn(); +const getProviderMock: jest.Mock = jest.fn(); +const cachedFetchAddressUTxOsMock: jest.Mock = jest.fn(); +const serializeNativeScriptMock: jest.Mock = jest.fn(); +const decodeNativeScriptFromCborMock: jest.Mock = jest.fn(); +const decodedToNativeScriptMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/lib/auth/botAccess", () => ({ + __esModule: true, + getBotWalletAccess: getBotWalletAccessMock, + assertBotWalletAccess: assertBotWalletAccessMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: { + transaction: { findMany: findPendingTransactionsMock }, + }, +}), { virtual: true }); + +jest.mock("@/utils/common", () => ({ + __esModule: true, + buildMultisigWallet: buildMultisigWalletMock, +}), { virtual: true }); + +jest.mock("@/utils/multisigSDK", () => ({ + __esModule: true, + addressToNetwork: addressToNetworkMock, +}), { virtual: true }); + +jest.mock("@/utils/get-provider", () => ({ + __esModule: true, + getProvider: getProviderMock, +}), { virtual: true }); + +jest.mock("@/utils/blockchain-cache", () => ({ + __esModule: true, + cachedFetchAddressUTxOs: cachedFetchAddressUTxOsMock, +}), { virtual: true }); + +jest.mock("@/utils/nativeScriptUtils", () => ({ + __esModule: true, + decodeNativeScriptFromCbor: decodeNativeScriptFromCborMock, + decodedToNativeScript: decodedToNativeScriptMock, +}), { virtual: true }); + +jest.mock("@meshsdk/core", () => ({ + __esModule: true, + serializeNativeScript: serializeNativeScriptMock, +}), { virtual: true }); + +jest.mock("@/server/api/root", () => ({ + __esModule: true, + createCaller: () => ({ + transaction: { getPendingTransactions: jest.fn() }, + wallet: { getWallet: jest.fn() }, + }), +}), { virtual: true }); + +jest.mock("@/lib/security/rateLimit", () => ({ + __esModule: true, + getClientIP: () => "127.0.0.1", +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/freeUtxos")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + (getBotWalletAccessMock as any).mockResolvedValue({ allowed: true, role: "cosigner" }); + (findPendingTransactionsMock as any).mockResolvedValue([]); + (assertBotWalletAccessMock as any).mockResolvedValue({ wallet: { id: "wallet-1" }, role: "cosigner" }); + buildMultisigWalletMock.mockReturnValue({ + getScript: () => ({ address: "addr_test1walletscript" }), + }); + decodeNativeScriptFromCborMock.mockReturnValue({ any: "decoded" }); + decodedToNativeScriptMock.mockReturnValue({ type: "all", scripts: [] }); + serializeNativeScriptMock.mockReturnValue({ address: "addr_test1canonicalwalletscript" }); + addressToNetworkMock.mockReturnValue(0); + getProviderMock.mockReturnValue({ get: jest.fn() }); + (cachedFetchAddressUTxOsMock as any).mockResolvedValue([ + { input: { txHash: "a", outputIndex: 0 } }, + ]); +}); + +describe("freeUtxos bot API", () => { + it("returns 403 when bot lacks wallet access", async () => { + (getBotWalletAccessMock as any).mockResolvedValue({ allowed: false }); + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(403); + }); + + it("returns free utxos for authorized bot", async () => { + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(cachedFetchAddressUTxOsMock).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith([{ input: { txHash: "a", outputIndex: 0 } }]); + }); + + it("falls back to canonical scriptCbor when multisig wallet is unavailable", async () => { + buildMultisigWalletMock.mockReturnValue(undefined); + (assertBotWalletAccessMock as any).mockResolvedValue({ + wallet: { + id: "wallet-1", + scriptCbor: "canonical-cbor", + signersAddresses: [BOT_TEST_ADDRESS], + stakeCredentialHash: null, + }, + role: "cosigner", + }); + + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(decodeNativeScriptFromCborMock).toHaveBeenCalledWith("canonical-cbor"); + expect(serializeNativeScriptMock).toHaveBeenCalled(); + expect(cachedFetchAddressUTxOsMock).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(200); + }); + + it("returns clear 500 when canonical script fallback cannot decode", async () => { + buildMultisigWalletMock.mockReturnValue(undefined); + decodeNativeScriptFromCborMock.mockImplementation(() => { + throw new Error("invalid canonical cbor"); + }); + (assertBotWalletAccessMock as any).mockResolvedValue({ + wallet: { + id: "wallet-1", + scriptCbor: "broken-cbor", + signersAddresses: [BOT_TEST_ADDRESS], + stakeCredentialHash: null, + }, + role: "cosigner", + }); + + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(500); + expect(res.json).toHaveBeenCalledWith({ + error: "Wallet script address resolution failed: invalid canonical cbor", + }); + }); +}); diff --git a/src/__tests__/governanceActiveProposals.test.ts b/src/__tests__/governanceActiveProposals.test.ts index 3fdfb895..450b5b0b 100644 --- a/src/__tests__/governanceActiveProposals.test.ts +++ b/src/__tests__/governanceActiveProposals.test.ts @@ -5,12 +5,12 @@ const addCorsCacheBustingHeadersMock = jest.fn<(res: NextApiResponse) => void>() const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); -const verifyJwtMock = jest.fn(); -const isBotJwtMock = jest.fn(); -const findBotUserMock = jest.fn(); -const providerGetMock = jest.fn(); -const parseScopeMock = jest.fn(); -const scopeIncludesMock = jest.fn(); +const verifyJwtMock = jest.fn<() => unknown>(); +const isBotJwtMock = jest.fn<() => boolean>(); +const findBotUserMock = jest.fn<() => Promise>(); +const providerGetMock = jest.fn<(path: string) => Promise>(); +const parseScopeMock = jest.fn<(scope: string) => string[]>(); +const scopeIncludesMock = jest.fn<(scopes: string[], required: string) => boolean>(); const getProposalStatusMock = jest.fn(); jest.mock( @@ -118,8 +118,8 @@ beforeEach(() => { corsMock.mockResolvedValue(undefined); verifyJwtMock.mockReturnValue({ address: "addr_test1", botId: "bot-1", type: "bot" }); isBotJwtMock.mockReturnValue(true); - parseScopeMock.mockImplementation((scope: string) => JSON.parse(scope)); - scopeIncludesMock.mockImplementation((scopes: string[], required: string) => + parseScopeMock.mockImplementation((scope) => JSON.parse(scope) as string[]); + scopeIncludesMock.mockImplementation((scopes, required) => scopes.includes(required), ); getProposalStatusMock.mockImplementation((details: any) => { @@ -146,7 +146,7 @@ describe("governanceActiveProposals API", () => { }); it("returns only active proposals and tolerates metadata 404", async () => { - providerGetMock.mockImplementation(async (path: string) => { + providerGetMock.mockImplementation(async (path) => { if (path.startsWith("governance/proposals?")) { return [ { @@ -214,7 +214,7 @@ describe("governanceActiveProposals API", () => { await handler(req, res); expect(res.status).toHaveBeenCalledWith(200); - const payload = res.json.mock.calls[0]?.[0] as any; + const payload = (res.json as jest.Mock).mock.calls[0]?.[0] as any; expect(Array.isArray(payload.proposals)).toBe(true); expect(payload.proposals).toHaveLength(1); expect(payload.proposals[0]).toMatchObject({ diff --git a/src/__tests__/mergeSignerWitnesses.test.ts b/src/__tests__/mergeSignerWitnesses.test.ts new file mode 100644 index 00000000..00e0971f --- /dev/null +++ b/src/__tests__/mergeSignerWitnesses.test.ts @@ -0,0 +1,189 @@ +import { describe, expect, it } from "@jest/globals"; +import { csl, calculateTxHash } from "@meshsdk/core-csl"; + +import { mergeSignerWitnesses } from "@/utils/txSignUtils"; + +function buildMinimalTxHex(): string { + const inputs = csl.TransactionInputs.new(); + const inputHash = csl.TransactionHash.from_bytes( + Buffer.from("00".repeat(32), "hex"), + ); + inputs.add(csl.TransactionInput.new(inputHash, 0)); + + const outputs = csl.TransactionOutputs.new(); + const sinkKey = csl.PrivateKey.generate_ed25519().to_public(); + const outAddr = csl.EnterpriseAddress.new( + csl.NetworkInfo.testnet_preview().network_id(), + csl.Credential.from_keyhash(sinkKey.hash()), + ).to_address(); + outputs.add( + csl.TransactionOutput.new(outAddr, csl.Value.new(csl.BigNum.from_str("1000000"))), + ); + + const body = csl.TransactionBody.new( + inputs, + outputs, + csl.BigNum.from_str("100000"), + undefined, + ); + const witnesses = csl.TransactionWitnessSet.new(); + return csl.Transaction.new(body, witnesses, undefined).to_hex(); +} + +function witnessSetHexFor( + signer: csl.PrivateKey, + bodyHashHex: string, +): string { + const sig = signer.sign(Buffer.from(bodyHashHex, "hex")); + const witness = csl.Vkeywitness.new(csl.Vkey.new(signer.to_public()), sig); + const witnesses = csl.Vkeywitnesses.new(); + witnesses.add(witness); + + const witnessSet = csl.TransactionWitnessSet.new(); + witnessSet.set_vkeys(witnesses); + return witnessSet.to_hex(); +} + +// Build a full signed Transaction hex whose body bytes differ from +// `originalTxHex` (one input flipped) and whose vkey signature targets the +// wallet's body — the shape a wallet returns when it re-canonicalises CBOR +// before signing. +function fullSignedTxHexWithDifferentBody( + originalTxHex: string, + signer: csl.PrivateKey, +): { hex: string; walletBodyHashHex: string } { + const inputs = csl.TransactionInputs.new(); + inputs.add( + csl.TransactionInput.new( + csl.TransactionHash.from_bytes(Buffer.from("11".repeat(32), "hex")), + 0, + ), + ); + + const orig = csl.Transaction.from_hex(originalTxHex); + const body = csl.TransactionBody.new( + inputs, + orig.body().outputs(), + orig.body().fee(), + undefined, + ); + + // Build a transient tx (no witnesses) just to take its body hash. + const probeHex = csl.Transaction.new( + body, + csl.TransactionWitnessSet.new(), + undefined, + ).to_hex(); + const walletBodyHashHex = calculateTxHash(probeHex); + + const sig = signer.sign(Buffer.from(walletBodyHashHex, "hex")); + const vkeys = csl.Vkeywitnesses.new(); + vkeys.add(csl.Vkeywitness.new(csl.Vkey.new(signer.to_public()), sig)); + const witnessSet = csl.TransactionWitnessSet.new(); + witnessSet.set_vkeys(vkeys); + + // Re-parse the body so it's not consumed by the probe tx above. + return { + hex: csl.Transaction.new( + csl.TransactionBody.from_bytes(body.to_bytes()), + witnessSet, + undefined, + ).to_hex(), + walletBodyHashHex, + }; +} + +describe("mergeSignerWitnesses", () => { + it("returns an empty invalidVkeyPubKeysHex when the new vkey verifies", () => { + const txHex = buildMinimalTxHex(); + const signer = csl.PrivateKey.generate_ed25519(); + const payload = witnessSetHexFor(signer, calculateTxHash(txHex)); + + const result = mergeSignerWitnesses(txHex, payload); + + expect(result.invalidVkeyPubKeysHex).toEqual([]); + expect( + csl.Transaction.from_hex(result.txHex).witness_set().vkeys()?.len(), + ).toBe(1); + }); + + it("flags a vkey whose signature targets a different body", () => { + const txHex = buildMinimalTxHex(); + const signer = csl.PrivateKey.generate_ed25519(); + + // Sign a hash that does NOT match the body — simulates a wallet that + // re-canonicalised the CBOR before signing, producing a witness whose + // signature verifies against the wallet's re-encoded body but not ours. + const payload = witnessSetHexFor(signer, "ff".repeat(32)); + + const result = mergeSignerWitnesses(txHex, payload); + + const expectedPubKey = Buffer.from(signer.to_public().as_bytes()) + .toString("hex") + .toLowerCase(); + expect(result.invalidVkeyPubKeysHex).toEqual([expectedPubKey]); + + // The merged tx still contains the witness (callers decide what to do); + // we just surface the validity verdict. + expect( + csl.Transaction.from_hex(result.txHex).witness_set().vkeys()?.len(), + ).toBe(1); + }); + + it("adopts the wallet's body when the wallet returned a full signed tx whose body differs and there are no pre-existing witnesses", () => { + // First-signer scenario: the wallet re-canonicalised the body before + // signing. We should use the wallet's body (so the signature verifies) + // and report no invalid vkeys. + const txHex = buildMinimalTxHex(); + const signer = csl.PrivateKey.generate_ed25519(); + const { hex: walletSignedHex, walletBodyHashHex } = + fullSignedTxHexWithDifferentBody(txHex, signer); + + // Sanity: the wallet's body hash is NOT the original body hash. + expect(walletBodyHashHex).not.toEqual(calculateTxHash(txHex)); + + const result = mergeSignerWitnesses(txHex, walletSignedHex); + + expect(result.invalidVkeyPubKeysHex).toEqual([]); + expect(calculateTxHash(result.txHex)).toEqual(walletBodyHashHex); + }); + + it("does not re-verify witnesses that were already present", () => { + const txHex = buildMinimalTxHex(); + const existingSigner = csl.PrivateKey.generate_ed25519(); + const newSigner = csl.PrivateKey.generate_ed25519(); + + // Pre-seed an "invalid" existing witness (signed against the wrong body). + // mergeSignerWitnesses should not flag it; only newly merged ones. + const wrongHashHex = "ff".repeat(32); + const sig = existingSigner.sign(Buffer.from(wrongHashHex, "hex")); + const existingWitness = csl.Vkeywitness.new( + csl.Vkey.new(existingSigner.to_public()), + sig, + ); + const tx = csl.Transaction.from_hex(txHex); + const witnessSet = csl.TransactionWitnessSet.from_bytes( + tx.witness_set().to_bytes(), + ); + const vkeys = csl.Vkeywitnesses.new(); + vkeys.add(existingWitness); + witnessSet.set_vkeys(vkeys); + const seededTxHex = csl.Transaction.new( + csl.TransactionBody.from_bytes(tx.body().to_bytes()), + witnessSet, + tx.auxiliary_data(), + ).to_hex(); + + // Merge a valid signature from a different signer. + const goodPayload = witnessSetHexFor( + newSigner, + calculateTxHash(seededTxHex), + ); + const result = mergeSignerWitnesses(seededTxHex, goodPayload); + + expect(result.invalidVkeyPubKeysHex).toEqual([]); + expect( + csl.Transaction.from_hex(result.txHex).witness_set().vkeys()?.len(), + ).toBe(2); + }); +}); diff --git a/src/__tests__/multisigSDK.test.ts b/src/__tests__/multisigSDK.test.ts index dbef91da..487e8cc9 100644 --- a/src/__tests__/multisigSDK.test.ts +++ b/src/__tests__/multisigSDK.test.ts @@ -39,9 +39,9 @@ describe('MultisigWallet', () => { ]; const testWallet = new MultisigWallet('Test', unsortedKeys); - expect(testWallet.keys[0].keyHash).toBe('aaaa'); - expect(testWallet.keys[1].keyHash).toBe('mmmm'); - expect(testWallet.keys[2].keyHash).toBe('zzzz'); + expect(testWallet.keys[0]!.keyHash).toBe('aaaa'); + expect(testWallet.keys[1]!.keyHash).toBe('mmmm'); + expect(testWallet.keys[2]!.keyHash).toBe('zzzz'); }); it('should filter out invalid keys', () => { @@ -54,7 +54,7 @@ describe('MultisigWallet', () => { const testWallet = new MultisigWallet('Test', keysWithInvalid); expect(testWallet.keys).toHaveLength(1); - expect(testWallet.keys[0].keyHash).toBe(mockKeyHashes.payment1); + expect(testWallet.keys[0]!.keyHash).toBe(mockKeyHashes.payment1); }); it('should use default values when optional parameters are not provided', () => { @@ -86,7 +86,7 @@ describe('MultisigWallet', () => { it('should return drep keys (role 3)', () => { const drepKeys = wallet.getKeysByRole(3); expect(drepKeys).toHaveLength(1); - expect(drepKeys?.[0].role).toBe(3); + expect(drepKeys?.[0]!.role).toBe(3); }); it('should return undefined for non-existent role', () => { diff --git a/src/__tests__/nativeScript.bot.test.ts b/src/__tests__/nativeScript.bot.test.ts new file mode 100644 index 00000000..f0d55bc5 --- /dev/null +++ b/src/__tests__/nativeScript.bot.test.ts @@ -0,0 +1,203 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { BOT_TEST_ADDRESS, createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const createCallerMock: jest.Mock = jest.fn(); +const buildMultisigWalletMock: jest.Mock = jest.fn(); +const decodeNativeScriptFromCborMock: jest.Mock = jest.fn(); +const decodedToNativeScriptMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, +}), { virtual: true }); + +jest.mock("@/utils/common", () => ({ + __esModule: true, + buildMultisigWallet: buildMultisigWalletMock, +}), { virtual: true }); + +jest.mock("@/server/api/root", () => ({ + __esModule: true, + createCaller: createCallerMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: {}, +}), { virtual: true }); + +jest.mock("@/lib/security/rateLimit", () => ({ + __esModule: true, + getClientIP: () => "127.0.0.1", +}), { virtual: true }); + +jest.mock("@/utils/nativeScriptUtils", () => ({ + __esModule: true, + decodeNativeScriptFromCbor: decodeNativeScriptFromCborMock, + decodedToNativeScript: decodedToNativeScriptMock, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/nativeScript")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + decodeNativeScriptFromCborMock.mockImplementation((cbor) => ({ cbor })); + decodedToNativeScriptMock.mockImplementation((decoded) => ({ + type: "decoded", + cbor: (decoded as { cbor: string }).cbor, + })); + createCallerMock.mockReturnValue({ + wallet: { + getWallet: (jest.fn() as any).mockResolvedValue({ + id: "wallet-1", + scriptCbor: "canonical-payment-cbor", + rawImportBodies: null, + }), + }, + }); + buildMultisigWalletMock.mockReturnValue({ + getAvailableTypes: () => ["payment"], + buildScript: () => ({ type: "all", scripts: [] }), + }); +}); + +describe("nativeScript bot-runnable API", () => { + it("returns 403 when address mismatches jwt address", async () => { + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: "addr_test1wrong" }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(403); + }); + + it("returns native scripts for matching bot address", async () => { + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith([ + { + type: "payment", + script: { type: "decoded", cbor: "canonical-payment-cbor" }, + }, + ]); + expect(buildMultisigWalletMock).not.toHaveBeenCalled(); + }); + + it("returns payment and stake scripts from canonical sources", async () => { + createCallerMock.mockReturnValue({ + wallet: { + getWallet: (jest.fn() as any).mockResolvedValue({ + id: "wallet-1", + scriptCbor: "canonical-payment-cbor", + rawImportBodies: { + multisig: { + stake_script: "canonical-stake-cbor", + }, + }, + }), + }, + }); + + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith([ + { + type: "payment", + script: { type: "decoded", cbor: "canonical-payment-cbor" }, + }, + { + type: "stake", + script: { type: "decoded", cbor: "canonical-stake-cbor" }, + }, + ]); + expect(buildMultisigWalletMock).not.toHaveBeenCalled(); + }); + + it("falls back to sdk wallet reconstruction when canonical decode fails", async () => { + decodeNativeScriptFromCborMock.mockImplementation(() => { + throw new Error("decode failed"); + }); + + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(buildMultisigWalletMock).toHaveBeenCalledTimes(1); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith([ + { type: "payment", script: { type: "all", scripts: [] } }, + ]); + }); + + it("returns 500 when canonical scripts are unavailable and wallet cannot be constructed", async () => { + decodeNativeScriptFromCborMock.mockImplementation(() => { + throw new Error("decode failed"); + }); + createCallerMock.mockReturnValue({ + wallet: { + getWallet: (jest.fn() as any).mockResolvedValue({ + id: "wallet-1", + scriptCbor: "", + rawImportBodies: null, + }), + }, + }); + buildMultisigWalletMock.mockReturnValue(undefined); + + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "wallet-1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(500); + expect(res.json).toHaveBeenCalledWith({ error: "Wallet could not be constructed" }); + }); +}); diff --git a/src/__tests__/normalizePoolId.test.ts b/src/__tests__/normalizePoolId.test.ts new file mode 100644 index 00000000..ae050603 --- /dev/null +++ b/src/__tests__/normalizePoolId.test.ts @@ -0,0 +1,10 @@ +import { describe, expect, it } from "@jest/globals"; +import { resolvePoolId } from "@meshsdk/core"; +import { normalizePoolIdForDelegation } from "@/lib/server/normalizePoolId"; + +describe("normalizePoolIdForDelegation", () => { + it("normalizes 56-char hex", () => { + const hex = "0".repeat(56); + expect(normalizePoolIdForDelegation(hex)).toBe(resolvePoolId(hex)); + }); +}); diff --git a/src/__tests__/og.test.ts b/src/__tests__/og.test.ts new file mode 100644 index 00000000..afa0a471 --- /dev/null +++ b/src/__tests__/og.test.ts @@ -0,0 +1,169 @@ +import { describe, expect, it, jest, beforeEach, afterEach } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; + +// SSRF tripwire suite for /api/v1/og +// +// The handler must reject: +// - non-https URLs +// - hosts not on the allowlist +// - hosts that resolve to private / loopback / link-local addresses +// - upstream redirects (no auto-follow) +// +// The most important regression is the IMDS URL case: +// http://169.254.169.254/latest/meta-data/ (AWS instance metadata) +// — historically the canonical SSRF target. If this ever returns 200, an +// attacker who can hit our public OG endpoint can pivot into cloud metadata. + +const dnsLookupMock = jest.fn() as jest.MockedFunction< + (host: string, opts?: unknown) => Promise> +>; + +jest.unstable_mockModule("dns", () => ({ + __esModule: true, + default: { promises: { lookup: dnsLookupMock } }, + promises: { lookup: dnsLookupMock }, +})); + +const envState: { OG_ALLOWED_HOSTS?: string } = {}; +jest.unstable_mockModule("@/env", () => ({ + __esModule: true, + env: new Proxy({}, { + get(_t, key: string) { + if (key === "OG_ALLOWED_HOSTS") return envState.OG_ALLOWED_HOSTS; + return undefined; + }, + }), +})); + +const fetchMock = jest.fn() as jest.MockedFunction; +const realFetch = global.fetch; + +function makeRes() { + const status = jest.fn(); + const json = jest.fn(); + const setHeader = jest.fn(); + const res = { + status: status.mockImplementation(() => res), + json: json.mockImplementation(() => res), + setHeader, + } as unknown as NextApiResponse; + return { res, status, json }; +} + +function makeReq(url: string | undefined): NextApiRequest { + return { + query: url === undefined ? {} : { url }, + method: "GET", + headers: {}, + } as unknown as NextApiRequest; +} + +const handlerPromise = import("../pages/api/v1/og"); + +beforeEach(() => { + dnsLookupMock.mockReset(); + fetchMock.mockReset(); + global.fetch = fetchMock as unknown as typeof fetch; + envState.OG_ALLOWED_HOSTS = undefined; +}); + +afterEach(() => { + global.fetch = realFetch; +}); + +describe("og handler — SSRF defense", () => { + it("rejects missing url with 400", async () => { + const { default: handler } = await handlerPromise; + const { res, status, json } = makeRes(); + await handler(makeReq(undefined), res); + expect(status).toHaveBeenCalledWith(400); + expect(json).toHaveBeenCalledWith(expect.objectContaining({ error: expect.stringMatching(/missing/i) })); + }); + + it("rejects http:// URLs with 400", async () => { + const { default: handler } = await handlerPromise; + const { res, status } = makeRes(); + await handler(makeReq("http://github.com/example"), res); + expect(status).toHaveBeenCalledWith(400); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it("rejects IMDS URL (http://169.254.169.254/...) — TRIPWIRE", async () => { + // This test is the one we never let regress. AWS instance metadata URL. + // Even if someone allowlists `*` for OG_ALLOWED_HOSTS, the http:// scheme + // check rejects this immediately. No DNS lookup, no fetch. + const { default: handler } = await handlerPromise; + const { res, status } = makeRes(); + await handler(makeReq("http://169.254.169.254/latest/meta-data/"), res); + expect(status).toHaveBeenCalledWith(400); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it("rejects https IMDS-style URL when wildcard hosts but private IP", async () => { + // Even with OG_ALLOWED_HOSTS=*, the DNS / address-class check must reject + // direct private-IP literals, including the link-local 169.254.0.0/16. + envState.OG_ALLOWED_HOSTS = "*"; + const { default: handler } = await handlerPromise; + const { res, status, json } = makeRes(); + await handler(makeReq("https://169.254.169.254/"), res); + expect(status).toHaveBeenCalledWith(400); + expect(json).toHaveBeenCalledWith(expect.objectContaining({ error: expect.stringMatching(/private|loopback/i) })); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it("rejects host not on the allowlist with 400", async () => { + envState.OG_ALLOWED_HOSTS = "github.com,x.com"; + const { default: handler } = await handlerPromise; + const { res, status } = makeRes(); + await handler(makeReq("https://evil.example.com/"), res); + expect(status).toHaveBeenCalledWith(400); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it("rejects when DNS resolves to an RFC1918 address", async () => { + envState.OG_ALLOWED_HOSTS = "internal.example.com"; + dnsLookupMock.mockResolvedValueOnce([{ address: "10.0.0.5", family: 4 }]); + const { default: handler } = await handlerPromise; + const { res, status, json } = makeRes(); + await handler(makeReq("https://internal.example.com/"), res); + expect(status).toHaveBeenCalledWith(400); + expect(json).toHaveBeenCalledWith(expect.objectContaining({ error: expect.stringMatching(/private|loopback/i) })); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it("rejects when upstream returns a redirect (no auto-follow)", async () => { + envState.OG_ALLOWED_HOSTS = "github.com"; + dnsLookupMock.mockResolvedValueOnce([{ address: "140.82.114.4", family: 4 }]); + fetchMock.mockResolvedValueOnce( + new Response(null, { status: 302, headers: { location: "http://169.254.169.254/" } }), + ); + const { default: handler } = await handlerPromise; + const { res, status } = makeRes(); + await handler(makeReq("https://github.com/example"), res); + expect(status).toHaveBeenCalledWith(500); + }); + + it("returns 200 with extracted OG metadata for an allowlisted public host", async () => { + envState.OG_ALLOWED_HOSTS = "example.com"; + dnsLookupMock.mockResolvedValueOnce([{ address: "93.184.216.34", family: 4 }]); + const html = ` + + + + + `; + fetchMock.mockResolvedValueOnce(new Response(html, { status: 200 })); + const { default: handler } = await handlerPromise; + const { res, status, json } = makeRes(); + await handler(makeReq("https://example.com/page"), res); + expect(status).toHaveBeenCalledWith(200); + expect(json).toHaveBeenCalledWith( + expect.objectContaining({ + title: "Hello", + description: "World", + image: "https://example.com/img.png", + siteName: "Example", + }), + ); + }); +}); diff --git a/src/__tests__/pendingTransactions.bot.test.ts b/src/__tests__/pendingTransactions.bot.test.ts new file mode 100644 index 00000000..f2a45483 --- /dev/null +++ b/src/__tests__/pendingTransactions.bot.test.ts @@ -0,0 +1,98 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { BOT_TEST_ADDRESS, createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const getBotWalletAccessMock: jest.Mock = jest.fn(); +const findPendingTransactionsMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/lib/auth/botAccess", () => ({ + __esModule: true, + getBotWalletAccess: getBotWalletAccessMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: { + transaction: { findMany: findPendingTransactionsMock }, + }, +}), { virtual: true }); + +jest.mock("@/server/api/root", () => ({ + __esModule: true, + createCaller: () => ({}), +}), { virtual: true }); + +jest.mock("@/lib/security/rateLimit", () => ({ + __esModule: true, + getClientIP: () => "127.0.0.1", +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/pendingTransactions")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + (getBotWalletAccessMock as any).mockResolvedValue({ allowed: true, role: "cosigner" }); + (findPendingTransactionsMock as any).mockResolvedValue([{ id: "tx-1" }]); +}); + +describe("pendingTransactions bot API", () => { + it("returns 403 when bot has no wallet access", async () => { + (getBotWalletAccessMock as any).mockResolvedValue({ allowed: false }); + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "w1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(403); + }); + + it("returns pending transactions when access is allowed", async () => { + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { walletId: "w1", address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(findPendingTransactionsMock).toHaveBeenCalledWith({ + where: { walletId: "w1", state: 0 }, + }); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith([{ id: "tx-1" }]); + }); +}); diff --git a/src/__tests__/proxyAccess.test.ts b/src/__tests__/proxyAccess.test.ts new file mode 100644 index 00000000..611ba223 --- /dev/null +++ b/src/__tests__/proxyAccess.test.ts @@ -0,0 +1,110 @@ +import { beforeEach, describe, expect, it, jest } from "@jest/globals"; +import { BOT_TEST_ADDRESS, BOT_TEST_ID, makeBotJwtPayload } from "./apiTestUtils"; + +const isBotJwtMock: jest.Mock = jest.fn(); +const getBotWalletAccessMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/lib/auth/botAccess", () => ({ + __esModule: true, + getBotWalletAccess: getBotWalletAccessMock, +}), { virtual: true }); + +const wallet = { + id: "wallet-1", + signersAddresses: [BOT_TEST_ADDRESS], +}; + +function createDb(walletRow: unknown = wallet) { + return { + wallet: { + findUnique: jest.fn(async () => walletRow), + }, + proxy: { + findFirst: jest.fn(), + }, + }; +} + +describe("proxyAccess", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("allows observer bots to read proxies", async () => { + const { authorizeProxyReadForV1 } = await import("@/lib/server/proxyAccess"); + const db = createDb(); + isBotJwtMock.mockReturnValue(true); + (getBotWalletAccessMock as any).mockResolvedValue({ + allowed: true, + role: "observer", + }); + + await expect( + authorizeProxyReadForV1({ + db: db as never, + payload: makeBotJwtPayload(), + walletId: "wallet-1", + address: BOT_TEST_ADDRESS, + }), + ).resolves.toEqual({ wallet }); + + expect(getBotWalletAccessMock).toHaveBeenCalledWith( + db, + "wallet-1", + BOT_TEST_ID, + ); + }); + + it("rejects address mismatches before wallet access checks", async () => { + const { authorizeProxyReadForV1 } = await import("@/lib/server/proxyAccess"); + const db = createDb(); + + await expect( + authorizeProxyReadForV1({ + db: db as never, + payload: makeBotJwtPayload({ address: "addr_test_other" }), + walletId: "wallet-1", + address: BOT_TEST_ADDRESS, + }), + ).rejects.toMatchObject({ code: "ADDRESS_MISMATCH" }); + expect(db.wallet.findUnique).not.toHaveBeenCalled(); + }); + + it("allows human signers to read proxies", async () => { + const { authorizeProxyReadForV1 } = await import("@/lib/server/proxyAccess"); + const db = createDb(); + isBotJwtMock.mockReturnValue(false); + + await expect( + authorizeProxyReadForV1({ + db: db as never, + payload: { address: BOT_TEST_ADDRESS } as never, + walletId: "wallet-1", + address: BOT_TEST_ADDRESS, + }), + ).resolves.toEqual({ wallet }); + }); + + it("loads only active proxies for the requested wallet", async () => { + const { loadActiveProxyForWallet } = await import("@/lib/server/proxyAccess"); + const proxy = { id: "proxy-1", isActive: true }; + const db = createDb(); + (db.proxy.findFirst as any).mockResolvedValue(proxy); + + await expect( + loadActiveProxyForWallet({ + db: db as never, + walletId: "wallet-1", + proxyId: "proxy-1", + }), + ).resolves.toBe(proxy); + expect(db.proxy.findFirst).toHaveBeenCalledWith({ + where: { id: "proxy-1", walletId: "wallet-1", isActive: true }, + }); + }); +}); diff --git a/src/__tests__/proxyBotSelection.test.ts b/src/__tests__/proxyBotSelection.test.ts new file mode 100644 index 00000000..f746c6de --- /dev/null +++ b/src/__tests__/proxyBotSelection.test.ts @@ -0,0 +1,204 @@ +import { describe, expect, it } from "@jest/globals"; +import { + DREP_REGISTER_REQUIRED_LOVELACE, + normalizeJsonArtifact, + PROXY_ACTION_FEE_BUFFER_LOVELACE, + PROXY_ACTION_REQUIRED_LOVELACE, + selectAuthTokenRefs, + selectAuthTokenRefsWithMinLovelace, + selectDRepRegisterRefs, + selectSetupRefs, + splitProxyActionSelection, + type ScriptUtxo, +} from "../../scripts/ci/scenarios/steps/proxyBot"; + +const AUTH_TOKEN_ID = "policy.asset"; + +const mkUtxo = ( + lovelace: string, + txHash: string, + outputIndex = 0, + tokenQuantity?: string, + address = "addr_test_wallet", +): ScriptUtxo => ({ + input: { txHash, outputIndex }, + output: { + address, + amount: [ + { unit: "lovelace", quantity: lovelace }, + ...(tokenQuantity ? [{ unit: AUTH_TOKEN_ID, quantity: tokenQuantity }] : []), + ], + }, +}); + +describe("proxy bot UTxO selection", () => { + it("selects setup from wallet UTxOs and collateral from key-address UTxOs", () => { + const refs = selectSetupRefs({ + walletUtxos: [mkUtxo("20000000", "setup")], + collateralUtxos: [mkUtxo("6000000", "collateral", 0, undefined, "addr_test_signer_1")], + }); + + expect(refs.utxoRefs).toEqual([{ txHash: "setup", outputIndex: 0 }]); + expect(refs.collateralRef).toEqual({ txHash: "collateral", outputIndex: 0 }); + }); + + it("rejects setup when only wallet script UTxOs could act as collateral", () => { + expect(() => + selectSetupRefs({ + walletUtxos: [mkUtxo("20000000", "setup"), mkUtxo("6000000", "script-collateral")], + collateralUtxos: [], + }), + ).toThrow( + /bot payment-address collateral UTxO/, + ); + }); + + it("rejects auth-token selection without key-address collateral", () => { + expect(() => + selectAuthTokenRefs({ + walletUtxos: [mkUtxo("6000000", "token", 0, "1")], + collateralUtxos: [], + authTokenId: AUTH_TOKEN_ID, + }), + ).toThrow(/bot payment-address collateral UTxO/); + }); + + it("adds funding inputs for DRep register while keeping collateral separate", () => { + const refs = selectDRepRegisterRefs({ + walletUtxos: [ + mkUtxo("2000000", "token", 0, "1"), + mkUtxo("300000000", "funding-a"), + mkUtxo("230000000", "funding-b"), + ], + collateralUtxos: [mkUtxo("6000000", "collateral", 0, undefined, "addr_test_signer_1")], + authTokenId: AUTH_TOKEN_ID, + requiredLovelace: DREP_REGISTER_REQUIRED_LOVELACE + 20_000_000n, + }); + + expect(refs.utxoRefs).toEqual([ + { txHash: "token", outputIndex: 0 }, + { txHash: "funding-a", outputIndex: 0 }, + { txHash: "funding-b", outputIndex: 0 }, + ]); + expect(refs.collateralRef).toEqual({ txHash: "collateral", outputIndex: 0 }); + expect(refs.selectedLovelace).toBe(532_000_000n); + }); + + it("splits DRep register diagnostics away from JSON request refs", () => { + const selection = selectDRepRegisterRefs({ + walletUtxos: [ + mkUtxo("2000000", "token", 0, "1"), + mkUtxo("300000000", "funding-a"), + mkUtxo("230000000", "funding-b"), + ], + collateralUtxos: [mkUtxo("6000000", "collateral", 0, undefined, "addr_test_signer_1")], + authTokenId: AUTH_TOKEN_ID, + requiredLovelace: DREP_REGISTER_REQUIRED_LOVELACE + 20_000_000n, + }); + + const { requestRefs, selectionArtifacts } = splitProxyActionSelection(selection); + + expect(requestRefs).toEqual({ + utxoRefs: [ + { txHash: "token", outputIndex: 0 }, + { txHash: "funding-a", outputIndex: 0 }, + { txHash: "funding-b", outputIndex: 0 }, + ], + collateralRef: { txHash: "collateral", outputIndex: 0 }, + }); + expect(selectionArtifacts).toEqual({ + selectedLovelace: "532000000", + requiredLovelace: "525000000", + }); + expect(requestRefs).not.toHaveProperty("selectedLovelace"); + expect(JSON.stringify(requestRefs)).not.toContain("532000000"); + }); + + it("adds funding inputs for auth-token actions while keeping collateral separate", () => { + const selection = selectAuthTokenRefsWithMinLovelace({ + walletUtxos: [ + mkUtxo("1200000", "token", 0, "1"), + mkUtxo("2500000", "funding-a"), + mkUtxo("900000", "funding-b"), + ], + collateralUtxos: [mkUtxo("6000000", "collateral", 0, undefined, "addr_test_signer_1")], + authTokenId: AUTH_TOKEN_ID, + requiredLovelace: PROXY_ACTION_REQUIRED_LOVELACE + PROXY_ACTION_FEE_BUFFER_LOVELACE, + context: "proxy vote", + }); + + expect(selection.utxoRefs).toEqual([ + { txHash: "token", outputIndex: 0 }, + { txHash: "funding-a", outputIndex: 0 }, + { txHash: "funding-b", outputIndex: 0 }, + ]); + expect(selection.collateralRef).toEqual({ txHash: "collateral", outputIndex: 0 }); + expect(selection.selectedLovelace).toBe(4_600_000n); + expect(selection.requiredLovelace).toBe(4_000_000n); + }); + + it("splits auth-token action diagnostics away from request refs", () => { + const selection = selectAuthTokenRefsWithMinLovelace({ + walletUtxos: [ + mkUtxo("1200000", "token", 0, "1"), + mkUtxo("3000000", "funding-a"), + ], + collateralUtxos: [mkUtxo("6000000", "collateral", 0, undefined, "addr_test_signer_1")], + authTokenId: AUTH_TOKEN_ID, + requiredLovelace: PROXY_ACTION_REQUIRED_LOVELACE + PROXY_ACTION_FEE_BUFFER_LOVELACE, + context: "proxy vote", + }); + + const { requestRefs, selectionArtifacts } = splitProxyActionSelection(selection); + + expect(requestRefs).toEqual({ + utxoRefs: [ + { txHash: "token", outputIndex: 0 }, + { txHash: "funding-a", outputIndex: 0 }, + ], + collateralRef: { txHash: "collateral", outputIndex: 0 }, + }); + expect(selectionArtifacts).toEqual({ + selectedLovelace: "4200000", + requiredLovelace: "4000000", + }); + expect(requestRefs).not.toHaveProperty("selectedLovelace"); + }); + + it("normalizes nested BigInt artifacts without changing request contracts", () => { + expect( + normalizeJsonArtifact({ + selectedLovelace: 1n, + nested: [{ requiredLovelace: 2n }], + }), + ).toEqual({ + selectedLovelace: "1", + nested: [{ requiredLovelace: "2" }], + }); + }); + + it("rejects DRep register when only token and collateral are available", () => { + expect(() => + selectDRepRegisterRefs({ + walletUtxos: [ + mkUtxo("2000000", "token", 0, "1"), + ], + collateralUtxos: [mkUtxo("6000000", "collateral", 0, undefined, "addr_test_signer_1")], + authTokenId: AUTH_TOKEN_ID, + requiredLovelace: DREP_REGISTER_REQUIRED_LOVELACE, + }), + ).toThrow(/requires 505 ADA in selected wallet inputs/); + }); + + it("rejects auth-token min-lovelace actions when selected wallet inputs are too small", () => { + expect(() => + selectAuthTokenRefsWithMinLovelace({ + walletUtxos: [mkUtxo("1200000", "token", 0, "1")], + collateralUtxos: [mkUtxo("6000000", "collateral", 0, undefined, "addr_test_signer_1")], + authTokenId: AUTH_TOKEN_ID, + requiredLovelace: PROXY_ACTION_REQUIRED_LOVELACE + PROXY_ACTION_FEE_BUFFER_LOVELACE, + context: "proxy vote", + }), + ).toThrow(/proxy vote requires 4 ADA in selected wallet inputs/); + }); +}); diff --git a/src/__tests__/proxyCiChainRecovery.test.ts b/src/__tests__/proxyCiChainRecovery.test.ts new file mode 100644 index 00000000..45cd0b07 --- /dev/null +++ b/src/__tests__/proxyCiChainRecovery.test.ts @@ -0,0 +1,294 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import { recoverProxyRowsFromChainForWalletType } from "../../scripts/ci/scenarios/proxyChainRecovery"; +import type { CIBootstrapContext } from "../../scripts/ci/framework/types"; +import { deriveProxyScripts } from "../lib/server/proxyTxBuilders"; +import type { UtxoRef } from "../lib/server/proxyUtxos"; + +type TestProxyRow = { + id: string; + walletId: string | null; + proxyAddress: string; + authTokenId: string; + paramUtxo: string; + isActive: boolean; +}; + +const walletAddress = "addr_test_wallet"; +const paramUtxo: UtxoRef = { + txHash: "a".repeat(64), + outputIndex: 0, +}; +const derivedProxy = deriveProxyScripts({ paramUtxo, network: 0 }); + +function createContext(): CIBootstrapContext { + return { + schemaVersion: 3, + createdAt: "2026-04-30T00:00:00.000Z", + apiBaseUrl: "http://localhost:3000", + networkId: 0, + walletTypes: ["legacy"], + wallets: [ + { + type: "legacy", + walletId: "current-wallet", + walletAddress, + signerAddresses: ["addr_test_signer_1", "addr_test_signer_2"], + }, + ], + bots: [], + signerAddresses: ["addr_test_signer_1", "addr_test_signer_2"], + signerStakeAddresses: [], + }; +} + +function createProxyRow(overrides: Partial = {}): TestProxyRow { + return { + id: "proxy-1", + walletId: "old-wallet", + proxyAddress: derivedProxy.proxyAddress, + authTokenId: derivedProxy.authTokenId, + paramUtxo: JSON.stringify(paramUtxo), + isActive: false, + ...overrides, + }; +} + +function createDb(args: { proxies?: TestProxyRow[] } = {}) { + const proxies = [...(args.proxies ?? [])]; + const creates: unknown[] = []; + const updates: unknown[] = []; + type TestDb = { + wallet: { + findUnique: ReturnType; + }; + proxy: { + findFirst: ReturnType; + create: ReturnType; + update: ReturnType; + }; + $transaction: ReturnType; + }; + const db: TestDb = { + wallet: { + findUnique: jest.fn(async ({ where }: { where: { id: string } }) => + where.id === "current-wallet" ? { id: "current-wallet" } : null, + ), + }, + proxy: { + findFirst: jest.fn(async ({ where }: { where: { authTokenId: string } }) => + proxies.find((proxy) => proxy.authTokenId === where.authTokenId) ?? null, + ), + create: jest.fn(async ({ data }: { data: Omit & { description: string } }) => { + creates.push(data); + const row: TestProxyRow = { id: `proxy-${creates.length}`, ...data }; + proxies.push(row); + return row; + }), + update: jest.fn(async ({ where, data }: { where: { id: string }; data: { walletId: string; isActive: true } }) => { + updates.push({ where, data }); + const row = proxies.find((proxy) => proxy.id === where.id); + if (!row) throw new Error(`missing proxy ${where.id}`); + row.walletId = data.walletId; + row.isActive = data.isActive; + return row; + }), + }, + $transaction: jest.fn(async (fn: (tx: TestDb) => Promise) => fn(db)), + }; + return { db, creates, updates, proxies }; +} + +function createProvider(args: { + walletAssets: string[]; + histories?: Record>; + txInputs?: Record>; + txErrors?: string[]; +}) { + return { + fetchAddressUTxOs: jest.fn(async (address: string) => [ + { + input: { txHash: "b".repeat(64), outputIndex: 0 }, + output: { + address, + amount: + address === walletAddress + ? [ + { unit: "lovelace", quantity: "2000000" }, + ...args.walletAssets.map((unit) => ({ unit, quantity: "1" })), + ] + : [{ unit: "lovelace", quantity: "2000000" }], + }, + }, + ]), + get: jest.fn(async (path: string) => { + const assetMatch = path.match(/^\/assets\/([^/]+)\/history/); + if (assetMatch) { + const assetUnit = decodeURIComponent(assetMatch[1]!); + return args.histories?.[assetUnit] ?? []; + } + + const txMatch = path.match(/^\/txs\/([^/]+)\/utxos$/); + if (txMatch) { + const txHash = decodeURIComponent(txMatch[1]!); + if (args.txErrors?.includes(txHash)) { + throw new Error(`tx lookup failed for ${txHash}`); + } + return { inputs: args.txInputs?.[txHash] ?? [] }; + } + + throw new Error(`unexpected path ${path}`); + }), + }; +} + +describe("CI proxy chain recovery", () => { + it("recovers a missing row when a wallet asset matches a mint transaction input", async () => { + const { db, creates, updates } = createDb(); + const provider = createProvider({ + walletAssets: [derivedProxy.authTokenId], + histories: { [derivedProxy.authTokenId]: [{ tx_hash: "mint-tx", action: "minted" }] }, + txInputs: { "mint-tx": [{ tx_hash: paramUtxo.txHash, output_index: paramUtxo.outputIndex }] }, + }); + + const result = await recoverProxyRowsFromChainForWalletType({ + ctx: createContext(), + walletType: "legacy", + db, + provider, + }); + + expect(result.recovered).toEqual([ + expect.objectContaining({ + proxyId: "proxy-1", + action: "created", + authTokenId: derivedProxy.authTokenId, + proxyAddress: derivedProxy.proxyAddress, + mintTxHash: "mint-tx", + dRepId: derivedProxy.dRepId, + }), + ]); + expect(creates).toEqual([ + expect.objectContaining({ + walletId: "current-wallet", + authTokenId: derivedProxy.authTokenId, + proxyAddress: derivedProxy.proxyAddress, + paramUtxo: JSON.stringify(paramUtxo), + description: "Recovered CI proxy from chain", + isActive: true, + }), + ]); + expect(updates).toEqual([]); + }); + + it("reattaches an existing historical row instead of creating a duplicate", async () => { + const existing = createProxyRow({ walletId: "old-wallet", isActive: false }); + const { db, creates, updates } = createDb({ proxies: [existing] }); + const provider = createProvider({ + walletAssets: [derivedProxy.authTokenId], + histories: { [derivedProxy.authTokenId]: [{ tx_hash: "mint-tx", action: "minted" }] }, + txInputs: { "mint-tx": [{ tx_hash: paramUtxo.txHash, output_index: paramUtxo.outputIndex }] }, + }); + + const result = await recoverProxyRowsFromChainForWalletType({ + ctx: createContext(), + walletType: "legacy", + db, + provider, + }); + + expect(result.recovered[0]).toEqual( + expect.objectContaining({ + proxyId: "proxy-1", + action: "reattached", + fromWalletId: "old-wallet", + }), + ); + expect(creates).toEqual([]); + expect(updates).toEqual([ + expect.objectContaining({ + where: { id: "proxy-1" }, + data: { walletId: "current-wallet", isActive: true }, + }), + ]); + }); + + it("skips unrelated wallet assets whose mint inputs do not derive the observed unit", async () => { + const unrelatedAsset = "f".repeat(56); + const { db, creates, updates } = createDb(); + const provider = createProvider({ + walletAssets: [unrelatedAsset], + histories: { [unrelatedAsset]: [{ tx_hash: "mint-tx", action: "minted" }] }, + txInputs: { "mint-tx": [{ tx_hash: "c".repeat(64), output_index: 1 }] }, + }); + + const result = await recoverProxyRowsFromChainForWalletType({ + ctx: createContext(), + walletType: "legacy", + db, + provider, + }); + + expect(result.recovered).toEqual([]); + expect(result.skipped).toEqual([ + expect.objectContaining({ assetUnit: unrelatedAsset, reason: "no-derived-match" }), + ]); + expect(creates).toEqual([]); + expect(updates).toEqual([]); + }); + + it("records diagnostics when asset history has no mint or tx UTxO lookup fails", async () => { + const noMintAsset = "1".repeat(56); + const txErrorAsset = "2".repeat(56); + const { db } = createDb(); + const provider = createProvider({ + walletAssets: [noMintAsset, txErrorAsset], + histories: { + [noMintAsset]: [{ tx_hash: "non-mint-tx", action: "burned" }], + [txErrorAsset]: [{ tx_hash: "error-tx", action: "minted" }], + }, + txInputs: {}, + txErrors: ["error-tx"], + }); + + const result = await recoverProxyRowsFromChainForWalletType({ + ctx: createContext(), + walletType: "legacy", + db, + provider, + }); + + expect(result.recovered).toEqual([]); + expect(result.skipped).toEqual( + expect.arrayContaining([ + expect.objectContaining({ assetUnit: noMintAsset, reason: "no-mint-transaction" }), + expect.objectContaining({ assetUnit: txErrorAsset, reason: "tx-utxos-fetch-error" }), + ]), + ); + }); + + it("enforces the candidate cap and records skipped excess assets", async () => { + const assetA = "a".repeat(56); + const assetB = "b".repeat(56); + const { db } = createDb(); + const provider = createProvider({ + walletAssets: [assetA, assetB], + histories: { [assetA]: [] }, + }); + + const result = await recoverProxyRowsFromChainForWalletType({ + ctx: createContext(), + walletType: "legacy", + db, + provider, + maxCandidates: 1, + }); + + expect(provider.get).toHaveBeenCalledTimes(1); + expect(result.skipped).toEqual( + expect.arrayContaining([ + expect.objectContaining({ assetUnit: assetA, reason: "no-mint-transaction" }), + expect.objectContaining({ assetUnit: assetB, reason: "candidate-cap-exceeded" }), + ]), + ); + }); +}); diff --git a/src/__tests__/proxyCiOrphanAdoption.test.ts b/src/__tests__/proxyCiOrphanAdoption.test.ts new file mode 100644 index 00000000..ea90b0c7 --- /dev/null +++ b/src/__tests__/proxyCiOrphanAdoption.test.ts @@ -0,0 +1,261 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import { resolvePaymentKeyHash, serializeNativeScript } from "@meshsdk/core"; +import { adoptProxyOrphansForWalletType } from "../../scripts/ci/scenarios/proxyOrphanAdoption"; +import type { CIBootstrapContext } from "../../scripts/ci/framework/types"; +import { deriveProxyScripts } from "../lib/server/proxyTxBuilders"; +import { realTestAddresses } from "./testUtils"; + +type TestWalletRow = { + id: string; + name: string; + signersAddresses: string[]; + signersStakeKeys: string[]; + signersDRepKeys: string[]; + signersDescriptions: string[]; + numRequiredSigners: number; + scriptCbor: string; + stakeCredentialHash: string | null; + type: string; + rawImportBodies: null; +}; + +type TestProxyRow = { + id: string; + walletId: string | null; + proxyAddress: string; + authTokenId: string; + paramUtxo: string; + isActive: boolean; +}; + +const paramUtxo = { + txHash: "a".repeat(64), + outputIndex: 0, +}; +const derivedProxy = deriveProxyScripts({ paramUtxo, network: 0 }); + +function createWalletRows(): { address: string; current: TestWalletRow; old: TestWalletRow } { + const paymentScript = { + type: "atLeast" as const, + required: 1, + scripts: [ + { type: "sig" as const, keyHash: resolvePaymentKeyHash(realTestAddresses.address1) }, + { type: "sig" as const, keyHash: resolvePaymentKeyHash(realTestAddresses.address2) }, + ], + }; + const serialized = serializeNativeScript(paymentScript, undefined, 0, true); + if (!serialized.scriptCbor) { + throw new Error("Expected test native script CBOR"); + } + + const base = { + name: "CI legacy wallet", + signersAddresses: [realTestAddresses.address1, realTestAddresses.address2], + signersStakeKeys: [], + signersDRepKeys: [], + signersDescriptions: ["one", "two"], + numRequiredSigners: 1, + scriptCbor: serialized.scriptCbor, + stakeCredentialHash: null, + type: "atLeast", + rawImportBodies: null, + }; + + return { + address: serialized.address, + current: { ...base, id: "current-wallet" }, + old: { ...base, id: "old-wallet" }, + }; +} + +function createContext(walletAddress: string): CIBootstrapContext { + return { + schemaVersion: 3, + createdAt: "2026-04-30T00:00:00.000Z", + apiBaseUrl: "http://localhost:3000", + networkId: 0, + walletTypes: ["legacy"], + wallets: [ + { + type: "legacy", + walletId: "current-wallet", + walletAddress, + signerAddresses: [realTestAddresses.address1, realTestAddresses.address2], + }, + ], + bots: [], + signerAddresses: [realTestAddresses.address1, realTestAddresses.address2], + signerStakeAddresses: [], + }; +} + +function createProxyRow(overrides: Partial = {}): TestProxyRow { + return { + id: "proxy-1", + walletId: "old-wallet", + proxyAddress: derivedProxy.proxyAddress, + authTokenId: derivedProxy.authTokenId, + paramUtxo: JSON.stringify(paramUtxo), + isActive: true, + ...overrides, + }; +} + +function createDb(args: { wallets: TestWalletRow[]; proxies: TestProxyRow[] }) { + const updates: Array<{ where: { id: string }; data: { walletId: string; isActive: true } }> = []; + type TestDb = { + wallet: { + findUnique: ReturnType; + findMany: ReturnType; + }; + proxy: { + findMany: ReturnType; + update: ReturnType; + }; + $transaction: ReturnType; + }; + const db: TestDb = { + wallet: { + findUnique: jest.fn(async ({ where }: { where: { id: string } }) => + args.wallets.find((wallet) => wallet.id === where.id) ?? null, + ), + findMany: jest.fn(async () => args.wallets), + }, + proxy: { + findMany: jest.fn(async ({ where }: { where: { walletId: { in: string[] } } }) => + args.proxies.filter((proxy) => proxy.walletId && where.walletId.in.includes(proxy.walletId)), + ), + update: jest.fn(async (updateArgs: { where: { id: string }; data: { walletId: string; isActive: true } }) => { + updates.push(updateArgs); + return { + id: updateArgs.where.id, + walletId: updateArgs.data.walletId, + isActive: updateArgs.data.isActive, + }; + }), + }, + $transaction: jest.fn(async (fn: (tx: TestDb) => Promise) => fn(db)), + }; + return { db, updates }; +} + +function createProvider(args: { walletAddress: string; includeAuthToken: boolean }) { + return { + fetchAddressUTxOs: jest.fn(async (address: string) => { + if (address === args.walletAddress) { + return [ + { + input: { txHash: "b".repeat(64), outputIndex: 0 }, + output: { + address, + amount: [ + { unit: "lovelace", quantity: "2000000" }, + ...(args.includeAuthToken + ? [{ unit: derivedProxy.authTokenId, quantity: "1" }] + : []), + ], + }, + }, + ]; + } + if (address === derivedProxy.proxyAddress) { + return []; + } + throw new Error(`unexpected address ${address}`); + }), + }; +} + +describe("CI proxy orphan adoption", () => { + it("reattaches a valid historical proxy row to the current wallet", async () => { + const { address, current, old } = createWalletRows(); + const proxy = createProxyRow(); + const { db, updates } = createDb({ wallets: [current, old], proxies: [proxy] }); + + const result = await adoptProxyOrphansForWalletType({ + ctx: createContext(address), + walletType: "legacy", + db, + provider: createProvider({ walletAddress: address, includeAuthToken: true }), + }); + + expect(result.historicalWalletIds).toEqual(["old-wallet"]); + expect(result.adopted).toEqual([ + expect.objectContaining({ + proxyId: "proxy-1", + fromWalletId: "old-wallet", + authTokenId: derivedProxy.authTokenId, + }), + ]); + expect(updates).toEqual([ + expect.objectContaining({ + where: { id: "proxy-1" }, + data: { walletId: "current-wallet", isActive: true }, + }), + ]); + }); + + it("reactivates a valid inactive row already attached to the current wallet", async () => { + const { address, current, old } = createWalletRows(); + const proxy = createProxyRow({ walletId: "current-wallet", isActive: false }); + const { db, updates } = createDb({ wallets: [current, old], proxies: [proxy] }); + + const result = await adoptProxyOrphansForWalletType({ + ctx: createContext(address), + walletType: "legacy", + db, + provider: createProvider({ walletAddress: address, includeAuthToken: true }), + }); + + expect(result.adopted[0]).toEqual( + expect.objectContaining({ + proxyId: "proxy-1", + fromWalletId: "current-wallet", + wasActive: false, + }), + ); + expect(updates[0]?.data).toEqual({ walletId: "current-wallet", isActive: true }); + }); + + it("skips rows whose stored metadata does not match derived scripts", async () => { + const { address, current, old } = createWalletRows(); + const { db, updates } = createDb({ + wallets: [current, old], + proxies: [createProxyRow({ authTokenId: "wrong-auth-token" })], + }); + + const result = await adoptProxyOrphansForWalletType({ + ctx: createContext(address), + walletType: "legacy", + db, + provider: createProvider({ walletAddress: address, includeAuthToken: true }), + }); + + expect(result.adopted).toEqual([]); + expect(result.skipped).toEqual([ + expect.objectContaining({ proxyId: "proxy-1", reason: "metadata-mismatch" }), + ]); + expect(updates).toEqual([]); + }); + + it("skips rows when the auth token is not visible at the current wallet address", async () => { + const { address, current, old } = createWalletRows(); + const { db, updates } = createDb({ + wallets: [current, old], + proxies: [createProxyRow()], + }); + + const result = await adoptProxyOrphansForWalletType({ + ctx: createContext(address), + walletType: "legacy", + db, + provider: createProvider({ walletAddress: address, includeAuthToken: false }), + }); + + expect(result.adopted).toEqual([]); + expect(result.skipped).toEqual([ + expect.objectContaining({ proxyId: "proxy-1", reason: "chain-empty" }), + ]); + expect(updates).toEqual([]); + }); +}); diff --git a/src/__tests__/proxyCiPreflight.test.ts b/src/__tests__/proxyCiPreflight.test.ts new file mode 100644 index 00000000..89fc9345 --- /dev/null +++ b/src/__tests__/proxyCiPreflight.test.ts @@ -0,0 +1,471 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import { + analyzeProxyFullLifecycleUtxoShape, + assertProxyFullLifecyclePreflight, + createScenarioProxyFullLifecycle, + createScenarioProxySmoke, + DREP_REGISTER_REQUIRED_LOVELACE, + FULL_LIFECYCLE_FEE_BUFFER_LOVELACE, + getProxyDRepAnchorUrl, + LIFECYCLE_PROXY_LOVELACE, + PROXY_FULL_LIFECYCLE_WALLET_TYPES, + requireSetupTxHash, + runProxyFullLifecycleHygiene, +} from "../../scripts/ci/scenarios/steps/proxyBot"; +import type { CIBootstrapContext, CIWalletType } from "../../scripts/ci/framework/types"; + +type TestUtxo = Parameters[0]["walletUtxos"][number]; + +const mkUtxo = (lovelace: string, txHash = "aa", outputIndex = 0): TestUtxo => ({ + input: { txHash, outputIndex }, + output: { + address: "addr_test_wallet", + amount: [{ unit: "lovelace", quantity: lovelace }], + }, +}); + +const mkCollateralUtxo = (lovelace = "6000000", txHash = "collateral", outputIndex = 0): TestUtxo => ({ + input: { txHash, outputIndex }, + output: { + address: "addr_test_signer_1", + amount: [{ unit: "lovelace", quantity: lovelace }], + }, +}); + +const mkAuthTokenUtxo = (txHash = "auth", outputIndex = 0): TestUtxo => ({ + input: { txHash, outputIndex }, + output: { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "6000000" }, + { unit: "policy.asset", quantity: "10" }, + ], + }, +}); + +const mkContext = (walletTypes: CIWalletType[]): CIBootstrapContext => ({ + schemaVersion: 3, + createdAt: "2026-04-29T00:00:00.000Z", + apiBaseUrl: "http://localhost:3000", + networkId: 0, + walletTypes, + wallets: walletTypes.map((type) => ({ + type, + walletId: `${type}-wallet-id`, + walletAddress: `addr_test_${type}`, + signerAddresses: ["addr_test_signer_1", "addr_test_signer_2", "addr_test_signer_3"], + })), + bots: [ + { + id: "bot-1", + paymentAddress: "addr_test_signer_1", + botKeyId: "bot-key-1", + botId: "bot-user-1", + }, + ], + defaultBotId: "bot-1", + signerAddresses: ["addr_test_signer_1", "addr_test_signer_2", "addr_test_signer_3"], + signerStakeAddresses: ["stake_test_1", "stake_test_2", "stake_test_3"], +}); + +describe("proxy full lifecycle preflight", () => { + it("classifies an already usable UTxO shape as pass", () => { + const analysis = analyzeProxyFullLifecycleUtxoShape({ + walletUtxos: [mkUtxo("540000000", "aa", 0)], + collateralUtxos: [mkCollateralUtxo()], + }); + + expect(analysis.status).toBe("pass"); + }); + + it("classifies one large wallet UTxO without key collateral as needing a self-split", () => { + const analysis = analyzeProxyFullLifecycleUtxoShape({ + walletUtxos: [mkUtxo("600000000", "aa", 0)], + collateralUtxos: [], + }); + + expect(analysis.status).toBe("needs-split"); + }); + + it("classifies insufficient total ADA as a hard funding failure", () => { + const analysis = analyzeProxyFullLifecycleUtxoShape({ + walletUtxos: [mkUtxo("525000000", "aa", 0)], + collateralUtxos: [mkCollateralUtxo()], + }); + + expect(analysis.status).toBe("insufficient-total"); + expect(() => + assertProxyFullLifecyclePreflight({ + walletUtxos: [mkUtxo("525000000", "aa", 0)], + collateralUtxos: [mkCollateralUtxo()], + }), + ).toThrow(/insufficient ADA/); + }); + + it("does not classify insufficient self-split budget as self-healable", () => { + const analysis = analyzeProxyFullLifecycleUtxoShape({ + walletUtxos: [mkUtxo("540000000", "aa", 0)], + collateralUtxos: [], + }); + + expect(analysis.status).toBe("insufficient-shape"); + }); + + it("rejects when no setup UTxO has at least 20 ADA", () => { + expect(() => + assertProxyFullLifecyclePreflight({ + walletUtxos: Array.from({ length: 29 }, (_, index) => + mkUtxo("19000000", `small-${index}`, index), + ), + collateralUtxos: [mkCollateralUtxo()], + }), + ).toThrow(/no wallet UTxO has at least 20 ADA/); + }); + + it("rejects when no key-address collateral UTxO is present", () => { + expect(() => + assertProxyFullLifecyclePreflight({ + walletUtxos: [mkUtxo("540000000", "aa", 0)], + collateralUtxos: [], + }), + ).toThrow(/no bot payment-address UTxO has at least 5 ADA/); + }); + + it("rejects insufficient total ADA with an actionable delta", () => { + expect(() => + assertProxyFullLifecyclePreflight({ + walletUtxos: [mkUtxo("525000000", "aa", 0)], + collateralUtxos: [mkCollateralUtxo()], + }), + ).toThrow(/insufficient ADA/); + }); + + it("passes when setup, key collateral, and wallet budget are available", () => { + const result = assertProxyFullLifecyclePreflight({ + walletUtxos: [mkUtxo("540000000", "aa", 0)], + collateralUtxos: [mkCollateralUtxo()], + }); + + expect(result.totalLovelace).toBe(540_000_000n); + expect(result.setupCandidates).toBe(1); + expect(result.keyCollateralCandidates).toBe(1); + expect(result.drepSelectableLovelace).toBe(540_000_000n); + expect(result.drepRequiredLovelace).toBe(536_000_000n); + expect(result.requiredTotalLovelace).toBe(536_000_000n); + }); + + it("rejects when script-address UTxOs are the only apparent collateral", () => { + expect(() => + assertProxyFullLifecyclePreflight({ + walletUtxos: [mkUtxo("540000000", "aa", 0), mkUtxo("6000000", "bb", 1)], + collateralUtxos: [], + }), + ).toThrow(/no bot payment-address UTxO/); + }); + + it("rejects when wallet inputs cannot fund the DRep budget", () => { + expect(() => + assertProxyFullLifecyclePreflight({ + walletUtxos: [mkUtxo("535999999", "aa", 0)], + collateralUtxos: [mkCollateralUtxo()], + }), + ).toThrow(/insufficient ADA/); + }); + + it("uses hardcoded proxy lifecycle budget constants", () => { + const result = assertProxyFullLifecyclePreflight({ + walletUtxos: [mkUtxo("540000000", "aa", 0)], + collateralUtxos: [mkCollateralUtxo()], + }); + + expect(LIFECYCLE_PROXY_LOVELACE).toBe(10_000_000n); + expect(FULL_LIFECYCLE_FEE_BUFFER_LOVELACE).toBe(20_000_000n); + expect(result.requiredTotalLovelace).toBe( + DREP_REGISTER_REQUIRED_LOVELACE + + LIFECYCLE_PROXY_LOVELACE + + 1_000_000n + + FULL_LIFECYCLE_FEE_BUFFER_LOVELACE, + ); + }); + + it("requires the normal DRep anchor URL for proxy DRep registration", () => { + expect(getProxyDRepAnchorUrl({ CI_DREP_ANCHOR_URL: " https://example.test/drep.json " })).toBe( + "https://example.test/drep.json", + ); + expect(() => getProxyDRepAnchorUrl({})).toThrow(/CI_DREP_ANCHOR_URL is required/); + }); +}); + +describe("proxy scenario composition", () => { + it("includes malformed-body checks for proxy finalize routes", () => { + const scenario = createScenarioProxySmoke(mkContext(["legacy"])); + const stepIds = scenario.steps.map((step) => step.id); + + expect(stepIds).toContain("v1.proxySetupFinalize.malformedBody"); + expect(stepIds).toContain("v1.proxyCleanupFinalize.malformedBody"); + }); + + it("runs full lifecycle for legacy, hierarchical, and SDK wallets", () => { + const scenario = createScenarioProxyFullLifecycle(mkContext(["legacy", "hierarchical", "sdk"])); + const stepIds = scenario.steps.map((step) => step.id); + + expect(PROXY_FULL_LIFECYCLE_WALLET_TYPES).toEqual(["legacy", "hierarchical", "sdk"]); + expect(stepIds).toContain("v1.proxy.full.recoverFromChain.legacy"); + expect(stepIds).toContain("v1.proxy.full.adoptOrphans.legacy"); + expect(stepIds).toContain("v1.proxy.full.hygiene.legacy"); + expect(stepIds).toContain("v1.proxy.full.utxoShape.legacy"); + expect(stepIds).toContain("v1.proxy.full.preflight.legacy"); + expect(stepIds.indexOf("v1.proxy.full.recoverFromChain.legacy")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.adoptOrphans.legacy"), + ); + expect(stepIds.indexOf("v1.proxy.full.adoptOrphans.legacy")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.hygiene.legacy"), + ); + expect(stepIds.indexOf("v1.proxy.full.hygiene.legacy")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.utxoShape.legacy"), + ); + expect(stepIds.indexOf("v1.proxy.full.utxoShape.legacy")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.preflight.legacy"), + ); + expect(stepIds).toContain("v1.proxy.full.recoverFromChain.hierarchical"); + expect(stepIds).toContain("v1.proxy.full.adoptOrphans.hierarchical"); + expect(stepIds).toContain("v1.proxy.full.hygiene.hierarchical"); + expect(stepIds).toContain("v1.proxy.full.utxoShape.hierarchical"); + expect(stepIds).toContain("v1.proxy.full.preflight.hierarchical"); + expect(stepIds.indexOf("v1.proxy.full.recoverFromChain.hierarchical")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.adoptOrphans.hierarchical"), + ); + expect(stepIds.indexOf("v1.proxy.full.adoptOrphans.hierarchical")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.hygiene.hierarchical"), + ); + expect(stepIds.indexOf("v1.proxy.full.hygiene.hierarchical")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.utxoShape.hierarchical"), + ); + expect(stepIds.indexOf("v1.proxy.full.utxoShape.hierarchical")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.preflight.hierarchical"), + ); + expect(stepIds).toContain("v1.proxy.full.recoverFromChain.sdk"); + expect(stepIds).toContain("v1.proxy.full.adoptOrphans.sdk"); + expect(stepIds).toContain("v1.proxy.full.hygiene.sdk"); + expect(stepIds).toContain("v1.proxy.full.utxoShape.sdk"); + expect(stepIds).toContain("v1.proxy.full.preflight.sdk"); + expect(stepIds.indexOf("v1.proxy.full.recoverFromChain.sdk")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.adoptOrphans.sdk"), + ); + expect(stepIds.indexOf("v1.proxy.full.adoptOrphans.sdk")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.hygiene.sdk"), + ); + expect(stepIds.indexOf("v1.proxy.full.hygiene.sdk")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.utxoShape.sdk"), + ); + expect(stepIds.indexOf("v1.proxy.full.utxoShape.sdk")).toBeLessThan( + stepIds.indexOf("v1.proxy.full.preflight.sdk"), + ); + }); + + it("signs proxy lifecycle transactions with signer index 0 before the broadcaster", () => { + const scenario = createScenarioProxyFullLifecycle(mkContext(["legacy"])); + const stepIds = scenario.steps.map((step) => step.id); + + const setupProposeIndex = stepIds.indexOf("v1.proxy.lifecycle.setup.propose.legacy"); + expect(stepIds.slice(setupProposeIndex + 1, setupProposeIndex + 3)).toEqual([ + "v1.proxy.lifecycle.setup.signer0.legacy", + "v1.proxy.lifecycle.setup.signer1.legacy", + ]); + + const spendProposeIndex = stepIds.indexOf("v1.proxy.full.spend.propose.legacy"); + expect(stepIds.slice(spendProposeIndex + 1, spendProposeIndex + 3)).toEqual([ + "v1.proxy.full.spend.legacy.signer0", + "v1.proxy.full.spend.legacy.signer1", + ]); + expect(stepIds).not.toContain("v1.proxy.lifecycle.setup.sign1.legacy"); + expect(stepIds).not.toContain("v1.proxy.full.spend.legacy.sign1"); + }); + + it("fails clearly instead of using a setup transaction id as a txHash", () => { + expect(() => + requireSetupTxHash({ + setupTransactionId: "database-transaction-id", + }), + ).toThrow(/proxy setup was not broadcast; signer step returned submitted=false/); + }); + + it("fails clearly when full lifecycle has no eligible wallet type", async () => { + const ctx = mkContext([]); + const scenario = createScenarioProxyFullLifecycle(ctx); + + expect(scenario.steps).toHaveLength(1); + expect(scenario.steps[0]?.id).toBe("v1.proxy.full.precondition"); + await expect(scenario.steps[0]?.execute(ctx)).rejects.toThrow( + /scenario\.proxy-full-lifecycle requires at least one of legacy, hierarchical, sdk/, + ); + }); +}); + +describe("proxy full lifecycle hygiene", () => { + const proxy = { + id: "proxy-1", + proxyAddress: "addr_test_proxy", + authTokenId: "policy.asset", + isActive: true, + }; + + function createHygieneDeps(requestJsonMock: ReturnType) { + return { + requestJson: requestJsonMock, + authenticateBot: jest.fn(async () => "token"), + getDefaultBot: jest.fn((ctx: CIBootstrapContext) => ctx.bots[0]!), + fetchFreeUtxos: jest.fn(async () => [mkAuthTokenUtxo()]), + fetchKeyAddressUtxos: jest.fn(async () => [mkCollateralUtxo()]), + runSigningFlow: jest.fn(async (args: { signBroadcast?: boolean; preferredTransactionId?: string }) => ({ + walletType: "legacy" as const, + walletId: "legacy-wallet-id", + transactionId: args.preferredTransactionId ?? "tx", + signerAddress: "addr_test_signer_1", + status: 200, + submitted: args.signBroadcast, + txHash: args.signBroadcast ? `${args.preferredTransactionId ?? "tx"}-hash` : undefined, + })), + pollUntilUtxosConsumed: jest.fn(async () => ({ attempts: 1 })), + env: { CI_MNEMONIC_1: "one", CI_MNEMONIC_2: "two" }, + }; + } + + it("no-ops when no active proxies are listed", async () => { + const requestJsonMock = jest.fn(async () => ({ status: 200, data: [] })); + + const result = await runProxyFullLifecycleHygiene({ + ctx: mkContext(["legacy"]), + walletType: "legacy", + deps: createHygieneDeps(requestJsonMock), + }); + + expect(result.artifacts.noOp).toBe(true); + expect(requestJsonMock).toHaveBeenCalledTimes(1); + }); + + it("cleans and finalizes an active proxy that is ready to burn", async () => { + const requestJsonMock = jest + .fn() + .mockResolvedValueOnce({ status: 200, data: [proxy] }) + .mockResolvedValueOnce({ status: 200, data: { active: false, dRepId: "drep1proxy" } }) + .mockResolvedValueOnce({ + status: 201, + data: { transaction: { id: "tx-burn" }, cleanup: { phase: "burn" } }, + }) + .mockResolvedValueOnce({ status: 201, data: { proxy: { ...proxy, isActive: false } } }) + .mockResolvedValueOnce({ status: 200, data: [] }); + const deps = createHygieneDeps(requestJsonMock); + + const result = await runProxyFullLifecycleHygiene({ + ctx: mkContext(["legacy"]), + walletType: "legacy", + deps, + }); + + expect(result.artifacts.noOp).toBe(false); + expect(deps.runSigningFlow).toHaveBeenCalledTimes(2); + expect(deps.pollUntilUtxosConsumed).toHaveBeenCalledTimes(1); + expect(requestJsonMock).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + url: "http://localhost:3000/api/v1/proxyDRepInfo?walletId=legacy-wallet-id&address=addr_test_signer_1&proxyId=proxy-1", + }), + ); + expect(requestJsonMock).toHaveBeenNthCalledWith( + 3, + expect.objectContaining({ + url: "http://localhost:3000/api/v1/proxyCleanup", + body: expect.objectContaining({ + proxyId: proxy.id, + deactivateProxy: true, + utxoRefs: [{ txHash: "auth", outputIndex: 0 }], + collateralRef: { txHash: "collateral", outputIndex: 0 }, + }), + }), + ); + expect(requestJsonMock).toHaveBeenNthCalledWith( + 4, + expect.objectContaining({ + url: "http://localhost:3000/api/v1/proxyCleanupFinalize", + body: expect.objectContaining({ txHash: "tx-burn-hash" }), + }), + ); + }); + + it("runs a sweep pass before the burn pass when proxy UTxOs remain", async () => { + const requestJsonMock = jest + .fn() + .mockResolvedValueOnce({ status: 200, data: [proxy] }) + .mockResolvedValueOnce({ status: 200, data: { active: false, dRepId: "drep1proxy" } }) + .mockResolvedValueOnce({ + status: 201, + data: { transaction: { id: "tx-sweep" }, cleanup: { phase: "sweep" } }, + }) + .mockResolvedValueOnce({ + status: 201, + data: { transaction: { id: "tx-burn" }, cleanup: { phase: "burn" } }, + }) + .mockResolvedValueOnce({ status: 201, data: { proxy: { ...proxy, isActive: false } } }) + .mockResolvedValueOnce({ status: 200, data: [] }); + const deps = createHygieneDeps(requestJsonMock); + + const result = await runProxyFullLifecycleHygiene({ + ctx: mkContext(["legacy"]), + walletType: "legacy", + deps, + }); + + const cleaned = result.artifacts.cleaned as Array<{ cleanupTransactions: unknown[] }>; + expect(cleaned[0]?.cleanupTransactions).toHaveLength(2); + expect(deps.runSigningFlow).toHaveBeenCalledTimes(4); + expect(deps.pollUntilUtxosConsumed).toHaveBeenCalledTimes(2); + }); + + it("deregisters an active proxy DRep before cleanup", async () => { + const requestJsonMock = jest + .fn() + .mockResolvedValueOnce({ status: 200, data: [proxy] }) + .mockResolvedValueOnce({ status: 200, data: { active: true, dRepId: "drep1proxy" } }) + .mockResolvedValueOnce({ status: 201, data: { transaction: { id: "tx-drep" } } }) + .mockResolvedValueOnce({ + status: 201, + data: { transaction: { id: "tx-burn" }, cleanup: { phase: "burn" } }, + }) + .mockResolvedValueOnce({ status: 201, data: { proxy: { ...proxy, isActive: false } } }) + .mockResolvedValueOnce({ status: 200, data: [] }); + const deps = createHygieneDeps(requestJsonMock); + + const result = await runProxyFullLifecycleHygiene({ + ctx: mkContext(["legacy"]), + walletType: "legacy", + deps, + }); + + const cleaned = result.artifacts.cleaned as Array<{ + dRep?: { wasActive?: boolean; deregisterTransaction?: { transactionId?: string } }; + }>; + expect(cleaned[0]?.dRep?.wasActive).toBe(true); + expect(cleaned[0]?.dRep?.deregisterTransaction?.transactionId).toBe("tx-drep"); + expect(deps.runSigningFlow).toHaveBeenCalledTimes(4); + expect(deps.pollUntilUtxosConsumed).toHaveBeenCalledTimes(2); + expect(requestJsonMock).toHaveBeenNthCalledWith( + 3, + expect.objectContaining({ + url: "http://localhost:3000/api/v1/proxyDRepCertificate", + body: expect.objectContaining({ + proxyId: proxy.id, + action: "deregister", + utxoRefs: [{ txHash: "auth", outputIndex: 0 }], + collateralRef: { txHash: "collateral", outputIndex: 0 }, + }), + }), + ); + expect(requestJsonMock).toHaveBeenNthCalledWith( + 4, + expect.objectContaining({ + url: "http://localhost:3000/api/v1/proxyCleanup", + }), + ); + }); +}); diff --git a/src/__tests__/proxyCleanup.bot.test.ts b/src/__tests__/proxyCleanup.bot.test.ts new file mode 100644 index 00000000..bdc8bd40 --- /dev/null +++ b/src/__tests__/proxyCleanup.bot.test.ts @@ -0,0 +1,232 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { UTxO } from "@meshsdk/core"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const enforceBodySizeMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const authorizeWalletSignerForV1TxMock: jest.Mock = jest.fn(); +const loadActiveProxyForWalletMock: jest.Mock = jest.fn(); +const resolveWalletScriptAddressMock: jest.Mock = jest.fn(); +const resolveUtxoRefsFromChainMock: jest.Mock = jest.fn(); +const resolveCollateralRefFromChainMock: jest.Mock = jest.fn(); +const resolveSingleUtxoRefFromChainMock: jest.Mock = jest.fn(); +const requireAuthTokenUtxoMock: jest.Mock = jest.fn(); +const buildProxyCleanupSweepTxMock: jest.Mock = jest.fn(); +const buildProxyCleanupTxMock: jest.Mock = jest.fn(); +const deriveProxyScriptsMock: jest.Mock = jest.fn(); +const createPendingMultisigTransactionMock: jest.Mock = jest.fn(); +const completeTxWithFreshCostModelsMock: jest.Mock = jest.fn(); +const completeMock: jest.Mock = jest.fn(); +const getTxBuilderMock: jest.Mock = jest.fn(); +const fetchAddressUTxOsMock: jest.Mock = jest.fn(); + +const proxy = { + id: "proxy-1", + proxyAddress: "addr_test_proxy", + authTokenId: "policy", + paramUtxo: JSON.stringify({ txHash: "aa", outputIndex: 0 }), +}; + +const proxyUtxo = { + input: { txHash: "cc", outputIndex: 2 }, + output: { address: proxy.proxyAddress, amount: [{ unit: "lovelace", quantity: "2000000" }] }, +} as UTxO; + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, + enforceBodySize: enforceBodySizeMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: {}, +}), { virtual: true }); + +jest.mock("@/lib/server/v1WalletAuth", () => ({ + __esModule: true, + authorizeWalletSignerForV1Tx: authorizeWalletSignerForV1TxMock, +}), { virtual: true }); + +jest.mock("@/lib/server/proxyAccess", () => ({ + __esModule: true, + loadActiveProxyForWallet: loadActiveProxyForWalletMock, +}), { virtual: true }); + +jest.mock("@/lib/server/walletScriptAddress", () => ({ + __esModule: true, + resolveWalletScriptAddress: resolveWalletScriptAddressMock, +}), { virtual: true }); + +jest.mock("@/lib/server/resolveUtxoRefsFromChain", () => ({ + __esModule: true, + resolveUtxoRefsFromChain: resolveUtxoRefsFromChainMock, +}), { virtual: true }); + +jest.mock("@/lib/server/proxyUtxos", () => ({ + __esModule: true, + requireAuthTokenUtxo: requireAuthTokenUtxoMock, + resolveCollateralRefFromChain: resolveCollateralRefFromChainMock, + resolveSingleUtxoRefFromChain: resolveSingleUtxoRefFromChainMock, +}), { virtual: true }); + +jest.mock("@/lib/server/createPendingMultisigTransaction", () => ({ + __esModule: true, + createPendingMultisigTransaction: createPendingMultisigTransactionMock, +}), { virtual: true }); + +jest.mock("@/lib/server/completeTxWithFreshCostModels", () => ({ + __esModule: true, + completeTxWithFreshCostModels: completeTxWithFreshCostModelsMock, +}), { virtual: true }); + +jest.mock("@/utils/get-provider", () => ({ + __esModule: true, + getProvider: () => ({ fetchAddressUTxOs: fetchAddressUTxOsMock }), +}), { virtual: true }); + +jest.mock("@/utils/get-tx-builder", () => ({ + __esModule: true, + getTxBuilder: getTxBuilderMock, +}), { virtual: true }); + +jest.mock("@/lib/server/proxyTxBuilders", () => ({ + __esModule: true, + buildProxyCleanupSweepTx: buildProxyCleanupSweepTxMock, + buildProxyCleanupTx: buildProxyCleanupTxMock, + deriveProxyScripts: deriveProxyScriptsMock, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/proxyCleanup")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + enforceBodySizeMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + (authorizeWalletSignerForV1TxMock as any).mockResolvedValue({ + wallet: { scriptCbor: "script", numRequiredSigners: 2, type: "all" }, + }); + (loadActiveProxyForWalletMock as any).mockResolvedValue(proxy); + resolveWalletScriptAddressMock.mockReturnValue("addr_test_wallet"); + (resolveUtxoRefsFromChainMock as any).mockResolvedValue({ utxos: [{ input: { txHash: "bb", outputIndex: 1 } }] }); + (resolveCollateralRefFromChainMock as any).mockResolvedValue({ collateral: { input: { txHash: "dd", outputIndex: 3 } } }); + requireAuthTokenUtxoMock.mockReturnValue({ input: { txHash: "bb", outputIndex: 1 } }); + deriveProxyScriptsMock.mockReturnValue({ + authTokenId: proxy.authTokenId, + proxyAddress: proxy.proxyAddress, + }); + buildProxyCleanupSweepTxMock.mockReturnValue({ sweptProxyUtxos: "1", preservedAuthTokens: "1" }); + buildProxyCleanupTxMock.mockReturnValue({ burnedAuthTokens: "10" }); + (completeMock as any).mockResolvedValue("tx-cbor"); + getTxBuilderMock.mockReturnValue({ complete: completeMock, meshTxBuilderBody: {} }); + (completeTxWithFreshCostModelsMock as any).mockResolvedValue("fresh-tx-cbor"); + (createPendingMultisigTransactionMock as any).mockResolvedValue({ id: "tx-1" }); +}); + +function cleanupRequest(body: Record): NextApiRequest { + return { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + address: makeBotJwtPayload().address, + proxyId: proxy.id, + utxoRefs: [{ txHash: "bb", outputIndex: 1 }], + collateralRef: { txHash: "dd", outputIndex: 3 }, + ...body, + }, + } as unknown as NextApiRequest; +} + +describe("proxyCleanup bot API", () => { + it("builds a sweep cleanup when proxy UTxOs remain", async () => { + (fetchAddressUTxOsMock as any).mockResolvedValue([proxyUtxo]); + const res = createMockResponse(); + + await handler(cleanupRequest({}), res); + + expect(resolveCollateralRefFromChainMock).toHaveBeenCalledWith( + expect.objectContaining({ + collateralRef: { txHash: "dd", outputIndex: 3 }, + expectedAddress: makeBotJwtPayload().address, + }), + ); + expect(buildProxyCleanupSweepTxMock).toHaveBeenCalledWith( + expect.objectContaining({ proxyUtxos: [proxyUtxo] }), + ); + expect(createPendingMultisigTransactionMock).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + proposerAddress: makeBotJwtPayload().address, + txCbor: "fresh-tx-cbor", + initialSignedAddresses: [], + }), + ); + expect(completeTxWithFreshCostModelsMock).toHaveBeenCalledWith( + getTxBuilderMock.mock.results[0]?.value, + 0, + ); + expect(completeMock).not.toHaveBeenCalled(); + expect(buildProxyCleanupTxMock).not.toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ + transaction: { id: "tx-1" }, + cleanup: { phase: "sweep", sweptProxyUtxos: "1", preservedAuthTokens: "1" }, + }); + }); + + it("builds a burn cleanup when the proxy address is empty", async () => { + (fetchAddressUTxOsMock as any).mockResolvedValue([]); + const res = createMockResponse(); + + await handler(cleanupRequest({}), res); + + expect(buildProxyCleanupTxMock).toHaveBeenCalled(); + expect(buildProxyCleanupSweepTxMock).not.toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ + transaction: { id: "tx-1" }, + cleanup: { phase: "burn", burnedAuthTokens: "10" }, + }); + }); + + it("rejects explicit proxyUtxoRefs that omit visible proxy UTxOs", async () => { + (fetchAddressUTxOsMock as any).mockResolvedValue([proxyUtxo]); + const res = createMockResponse(); + + await handler( + cleanupRequest({ proxyUtxoRefs: [{ txHash: "ee", outputIndex: 4 }] }), + res, + ); + + expect(res.status).toHaveBeenCalledWith(400); + expect(buildProxyCleanupSweepTxMock).not.toHaveBeenCalled(); + }); +}); diff --git a/src/__tests__/proxyCleanupFinalization.test.ts b/src/__tests__/proxyCleanupFinalization.test.ts new file mode 100644 index 00000000..254b533d --- /dev/null +++ b/src/__tests__/proxyCleanupFinalization.test.ts @@ -0,0 +1,172 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import type { Proxy } from "@prisma/client"; +import type { UTxO } from "@meshsdk/core"; + +jest.mock("@/utils/get-provider", () => ({ + __esModule: true, + getProvider: jest.fn(), +}), { virtual: true }); + +const proxy = { + id: "proxy-1", + walletId: "wallet-1", + proxyAddress: "addr_test_proxy", + authTokenId: "policy", + paramUtxo: "{}", + description: null, + isActive: true, + createdAt: new Date(), + updatedAt: new Date(), +} as Proxy; + +const mkUtxo = (amount: UTxO["output"]["amount"]): UTxO => + ({ + input: { txHash: "aa", outputIndex: 0 }, + output: { address: "addr_test_wallet", amount }, + }) as UTxO; + +function createDb() { + return { + proxy: { + update: jest.fn(async ({ data }: { data: Partial }) => ({ + ...proxy, + ...data, + })), + }, + }; +} + +describe("finalizeConfirmedProxyCleanup", () => { + it("deactivates the proxy when auth tokens are gone", async () => { + const { finalizeConfirmedProxyCleanup } = await import("@/lib/server/proxyCleanupFinalization"); + const db = createDb(); + const result = await finalizeConfirmedProxyCleanup({ + db: db as never, + network: 0, + proxy, + walletAddress: "addr_test_wallet", + txHash: "cleanup-burn-tx", + provider: { + fetchAddressUTxOs: jest.fn(async (address: string) => + address === proxy.proxyAddress + ? [] + : [mkUtxo([{ unit: "lovelace", quantity: "2000000" }])], + ), + get: jest.fn(async () => ({ + inputs: [ + { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "2000000" }, + { unit: "policy", quantity: "1" }, + ], + }, + ], + outputs: [{ address: "addr_test_wallet", amount: [{ unit: "lovelace", quantity: "1500000" }] }], + })), + }, + }); + + expect("error" in result).toBe(false); + expect(db.proxy.update).toHaveBeenCalledWith( + expect.objectContaining({ + where: { id: proxy.id }, + data: { isActive: false }, + }), + ); + }); + + it("rejects cleanup finalization while auth tokens are still on-chain", async () => { + const { finalizeConfirmedProxyCleanup } = await import("@/lib/server/proxyCleanupFinalization"); + const result = await finalizeConfirmedProxyCleanup({ + db: createDb() as never, + network: 0, + proxy, + walletAddress: "addr_test_wallet", + txHash: "cleanup-burn-tx", + provider: { + fetchAddressUTxOs: jest.fn(async () => [ + mkUtxo([ + { unit: "lovelace", quantity: "2000000" }, + { unit: "policy", quantity: "1" }, + ]), + ]), + get: jest.fn(async () => ({ + inputs: [ + { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "2000000" }, + { unit: "policy", quantity: "1" }, + ], + }, + ], + outputs: [{ address: "addr_test_wallet", amount: [{ unit: "lovelace", quantity: "1500000" }] }], + })), + }, + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("auth tokens are still visible"); + } + }); + + it("rejects cleanup finalization while proxy UTxOs remain", async () => { + const { finalizeConfirmedProxyCleanup } = await import("@/lib/server/proxyCleanupFinalization"); + const result = await finalizeConfirmedProxyCleanup({ + db: createDb() as never, + network: 0, + proxy, + walletAddress: "addr_test_wallet", + txHash: "cleanup-burn-tx", + provider: { + fetchAddressUTxOs: jest.fn(async (address: string) => + address === proxy.proxyAddress + ? [mkUtxo([{ unit: "lovelace", quantity: "1000000" }])] + : [], + ), + get: jest.fn(async () => ({ + inputs: [ + { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "2000000" }, + { unit: "policy", quantity: "1" }, + ], + }, + ], + outputs: [{ address: "addr_test_wallet", amount: [{ unit: "lovelace", quantity: "1500000" }] }], + })), + }, + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("proxy address still has on-chain UTxOs"); + } + }); + + it("rejects finalization when txHash does not spend the auth token", async () => { + const { finalizeConfirmedProxyCleanup } = await import("@/lib/server/proxyCleanupFinalization"); + const result = await finalizeConfirmedProxyCleanup({ + db: createDb() as never, + network: 0, + proxy, + walletAddress: "addr_test_wallet", + txHash: "wrong-tx", + provider: { + fetchAddressUTxOs: jest.fn(async () => []), + get: jest.fn(async () => ({ + inputs: [{ address: "addr_test_wallet", amount: [{ unit: "lovelace", quantity: "2000000" }] }], + outputs: [{ address: "addr_test_wallet", amount: [{ unit: "lovelace", quantity: "1500000" }] }], + })), + }, + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("txHash does not match confirmed proxy cleanup burn outputs"); + } + }); +}); diff --git a/src/__tests__/proxyCleanupRuntime.test.ts b/src/__tests__/proxyCleanupRuntime.test.ts new file mode 100644 index 00000000..1b1b7c7b --- /dev/null +++ b/src/__tests__/proxyCleanupRuntime.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it } from "@jest/globals"; +import { + shouldSkipActionConfirmation, + shouldSkipCleanupBurnPropose, + shouldSkipCleanupBurnSigning, +} from "../../scripts/ci/scenarios/steps/proxyBot"; + +describe("proxy cleanup runtime state", () => { + it("skips the optional burn proposal when initial cleanup already produced burn", () => { + const runtime = { cleanupPhase: "burn" as const }; + + expect(shouldSkipCleanupBurnPropose(runtime)).toBe(true); + expect( + shouldSkipCleanupBurnSigning({ + cleanupBurnSkipped: true, + cleanupBurnTransactionId: undefined, + }), + ).toBe(true); + }); + + it("runs burn signing after a separate burn transaction is proposed", () => { + const runtime = { + cleanupPhase: "burn" as const, + cleanupBurnSkipped: false, + cleanupBurnTransactionId: "tx-burn", + }; + + expect(shouldSkipCleanupBurnPropose({ cleanupPhase: "sweep" })).toBe(false); + expect(shouldSkipCleanupBurnSigning(runtime)).toBe(false); + }); + + it("skips burn signing when no burn transaction was created", () => { + expect( + shouldSkipCleanupBurnSigning({ + cleanupBurnSkipped: false, + cleanupBurnTransactionId: undefined, + }), + ).toBe(true); + }); + + it("skips action confirmation until a transaction id and spent inputs are recorded", () => { + expect(shouldSkipActionConfirmation({})).toBe(true); + expect(shouldSkipActionConfirmation({ actionTransactionId: "tx-1" })).toBe(true); + expect( + shouldSkipActionConfirmation({ + actionTransactionId: "tx-1", + actionUtxoRefs: [{ txHash: "hash", outputIndex: 0 }], + }), + ).toBe(false); + }); +}); diff --git a/src/__tests__/proxyDRepInfo.test.ts b/src/__tests__/proxyDRepInfo.test.ts new file mode 100644 index 00000000..0bd3619a --- /dev/null +++ b/src/__tests__/proxyDRepInfo.test.ts @@ -0,0 +1,156 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const authorizeProxyReadForV1Mock: jest.Mock = jest.fn(); +const loadActiveProxyForWalletMock: jest.Mock = jest.fn(); +const deriveProxyScriptsMock: jest.Mock = jest.fn(); + +const proxy = { + id: "proxy-1", + walletId: "wallet-1", + proxyAddress: "addr_test_proxy", + authTokenId: "policy", + paramUtxo: JSON.stringify({ txHash: "aa", outputIndex: 0 }), + isActive: true, +}; + +jest.mock("@/env", () => ({ + __esModule: true, + env: { BLOCKFROST_API_KEY_PREPROD: "preprod-key" }, +}), { virtual: true }); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: {}, +}), { virtual: true }); + +jest.mock("@/lib/server/proxyAccess", () => ({ + __esModule: true, + authorizeProxyReadForV1: authorizeProxyReadForV1Mock, + loadActiveProxyForWallet: loadActiveProxyForWalletMock, +}), { virtual: true }); + +jest.mock("@/lib/server/proxyTxBuilders", () => ({ + __esModule: true, + deriveProxyScripts: deriveProxyScriptsMock, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/proxyDRepInfo")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + (authorizeProxyReadForV1Mock as any).mockResolvedValue({ wallet: { id: "wallet-1" } }); + (loadActiveProxyForWalletMock as any).mockResolvedValue(proxy); + deriveProxyScriptsMock.mockReturnValue({ + authTokenId: proxy.authTokenId, + proxyAddress: proxy.proxyAddress, + dRepId: "drep1proxy", + }); + global.fetch = jest.fn(async () => ({ + ok: true, + status: 200, + json: async () => ({ active: true }), + text: async () => "", + })) as never; +}); + +function infoRequest(query: Record = {}): NextApiRequest { + return { + method: "GET", + headers: makeBearerAuth(), + query: { + walletId: "wallet-1", + address: makeBotJwtPayload().address, + proxyId: proxy.id, + ...query, + }, + } as unknown as NextApiRequest; +} + +describe("proxyDRepInfo API", () => { + it("returns active proxy DRep status", async () => { + const res = createMockResponse(); + + await handler(infoRequest(), res); + + expect(global.fetch).toHaveBeenCalledWith( + "https://cardano-preprod.blockfrost.io/api/v0/governance/dreps/drep1proxy", + { headers: { project_id: "preprod-key" } }, + ); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith({ active: true, dRepId: "drep1proxy" }); + }); + + it("returns inactive when Blockfrost reports the DRep is not found", async () => { + global.fetch = jest.fn(async () => ({ + ok: false, + status: 404, + json: async () => ({}), + text: async () => "not found", + })) as never; + const res = createMockResponse(); + + await handler(infoRequest(), res); + + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith({ active: false, dRepId: "drep1proxy" }); + }); + + it("rejects unauthorized proxy reads", async () => { + authorizeProxyReadForV1Mock.mockRejectedValueOnce(Object.assign(new Error("Not authorized for this wallet"), { code: "FORBIDDEN" })); + const res = createMockResponse(); + + await handler(infoRequest(), res); + + expect(res.status).toHaveBeenCalledWith(403); + expect(res.json).toHaveBeenCalledWith({ error: "Not authorized for this wallet" }); + }); + + it("rejects stored proxy metadata mismatches", async () => { + deriveProxyScriptsMock.mockReturnValueOnce({ + authTokenId: "different-policy", + proxyAddress: proxy.proxyAddress, + dRepId: "drep1proxy", + }); + const res = createMockResponse(); + + await handler(infoRequest(), res); + + expect(res.status).toHaveBeenCalledWith(409); + expect(res.json).toHaveBeenCalledWith({ error: "Stored proxy metadata does not match derived scripts" }); + }); +}); diff --git a/src/__tests__/proxySetup.bot.test.ts b/src/__tests__/proxySetup.bot.test.ts new file mode 100644 index 00000000..7ba631c7 --- /dev/null +++ b/src/__tests__/proxySetup.bot.test.ts @@ -0,0 +1,183 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const enforceBodySizeMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const authorizeWalletSignerForV1TxMock: jest.Mock = jest.fn(); +const resolveUtxoRefsFromChainMock: jest.Mock = jest.fn(); +const resolveCollateralRefFromChainMock: jest.Mock = jest.fn(); +const resolveWalletScriptAddressMock: jest.Mock = jest.fn(); +const buildProxySetupTxMock: jest.Mock = jest.fn(); +const createPendingMultisigTransactionMock: jest.Mock = jest.fn(); +const completeTxWithFreshCostModelsMock: jest.Mock = jest.fn(); +const completeMock: jest.Mock = jest.fn(); +const getTxBuilderMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, + enforceBodySize: enforceBodySizeMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: {}, +}), { virtual: true }); + +jest.mock("@/lib/server/v1WalletAuth", () => ({ + __esModule: true, + authorizeWalletSignerForV1Tx: authorizeWalletSignerForV1TxMock, +}), { virtual: true }); + +jest.mock("@/lib/server/walletScriptAddress", () => ({ + __esModule: true, + resolveWalletScriptAddress: resolveWalletScriptAddressMock, +}), { virtual: true }); + +jest.mock("@/lib/server/resolveUtxoRefsFromChain", () => ({ + __esModule: true, + resolveUtxoRefsFromChain: resolveUtxoRefsFromChainMock, +}), { virtual: true }); + +jest.mock("@/lib/server/proxyUtxos", () => ({ + __esModule: true, + resolveCollateralRefFromChain: resolveCollateralRefFromChainMock, +}), { virtual: true }); + +jest.mock("@/lib/server/createPendingMultisigTransaction", () => ({ + __esModule: true, + createPendingMultisigTransaction: createPendingMultisigTransactionMock, +}), { virtual: true }); + +jest.mock("@/lib/server/completeTxWithFreshCostModels", () => ({ + __esModule: true, + completeTxWithFreshCostModels: completeTxWithFreshCostModelsMock, +}), { virtual: true }); + +jest.mock("@/utils/get-tx-builder", () => ({ + __esModule: true, + getTxBuilder: getTxBuilderMock, +}), { virtual: true }); + +jest.mock("@/lib/server/proxyTxBuilders", () => ({ + __esModule: true, + DEFAULT_PROXY_SETUP_LOVELACE: "1000000", + buildProxySetupTx: buildProxySetupTxMock, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/proxySetup")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + enforceBodySizeMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + (authorizeWalletSignerForV1TxMock as any).mockResolvedValue({ + wallet: { scriptCbor: "script", numRequiredSigners: 2, type: "all" }, + }); + resolveWalletScriptAddressMock.mockReturnValue("addr_test_wallet_script"); + (resolveUtxoRefsFromChainMock as any).mockResolvedValue({ utxos: [{ input: { txHash: "aa", outputIndex: 0 } }] }); + (resolveCollateralRefFromChainMock as any).mockResolvedValue({ collateral: { input: { txHash: "bb", outputIndex: 1 } } }); + buildProxySetupTxMock.mockReturnValue({ + proxyAddress: "addr_test_proxy", + authTokenId: "policy", + paramUtxo: { txHash: "aa", outputIndex: 0 }, + }); + (completeMock as any).mockResolvedValue("tx-cbor"); + const txBuilder = { complete: completeMock, meshTxBuilderBody: {} }; + getTxBuilderMock.mockReturnValue(txBuilder); + (completeTxWithFreshCostModelsMock as any).mockResolvedValue("fresh-tx-cbor"); + (createPendingMultisigTransactionMock as any).mockResolvedValue({ id: "tx-1" }); +}); + +describe("proxySetup bot API", () => { + it("rejects invalid initialProxyLovelace before resolving UTxOs", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + address: makeBotJwtPayload().address, + utxoRefs: [{ txHash: "aa", outputIndex: 0 }], + collateralRef: { txHash: "bb", outputIndex: 1 }, + initialProxyLovelace: "0", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(res.status).toHaveBeenCalledWith(400); + expect(resolveUtxoRefsFromChainMock).not.toHaveBeenCalled(); + }); + + it("passes valid initialProxyLovelace to the setup builder", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + address: makeBotJwtPayload().address, + utxoRefs: [{ txHash: "aa", outputIndex: 0 }], + collateralRef: { txHash: "bb", outputIndex: 1 }, + initialProxyLovelace: "5000000", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + + await handler(req, res); + + expect(resolveCollateralRefFromChainMock).toHaveBeenCalledWith( + expect.objectContaining({ + collateralRef: { txHash: "bb", outputIndex: 1 }, + expectedAddress: makeBotJwtPayload().address, + }), + ); + expect(buildProxySetupTxMock).toHaveBeenCalledWith( + expect.objectContaining({ + initialProxyLovelace: "5000000", + multisigScriptCbor: "script", + }), + ); + expect(createPendingMultisigTransactionMock).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + proposerAddress: makeBotJwtPayload().address, + txCbor: "fresh-tx-cbor", + initialSignedAddresses: [], + }), + ); + expect(completeTxWithFreshCostModelsMock).toHaveBeenCalledWith( + getTxBuilderMock.mock.results[0]?.value, + 0, + ); + expect(completeMock).not.toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(201); + }); +}); diff --git a/src/__tests__/proxySetupFinalization.test.ts b/src/__tests__/proxySetupFinalization.test.ts new file mode 100644 index 00000000..a5697392 --- /dev/null +++ b/src/__tests__/proxySetupFinalization.test.ts @@ -0,0 +1,205 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import type { UTxO } from "@meshsdk/core"; + +jest.mock("@/utils/get-provider", () => ({ + __esModule: true, + getProvider: jest.fn(), +}), { virtual: true }); + +const setup = { + proxyAddress: "addr_test_proxy", + authTokenId: "policy", + paramUtxo: { txHash: "aa", outputIndex: 0 }, + description: "CI proxy setup", +}; +const validTxHash = "a".repeat(64); + +const mkUtxo = ( + address: string, + amount: UTxO["output"]["amount"], + txHash = "aa", + outputIndex = 0, +): UTxO => + ({ + input: { txHash, outputIndex }, + output: { address, amount }, + }) as UTxO; + +function createDb(existingProxy?: unknown) { + return { + proxy: { + findFirst: jest.fn(async () => existingProxy ?? null), + create: jest.fn(async ({ data }: { data: Record }) => ({ + id: "proxy-1", + ...data, + })), + update: jest.fn(async ({ data }: { data: Record }) => ({ + id: "proxy-1", + ...data, + })), + }, + }; +} + +function createProvider(args: { walletUtxos: UTxO[]; proxyUtxos: UTxO[] }) { + return { + fetchAddressUTxOs: jest.fn(async (address: string) => + address === setup.proxyAddress ? args.proxyUtxos : args.walletUtxos, + ), + get: jest.fn(async () => ({ + outputs: [ + { + address: setup.proxyAddress, + amount: [{ unit: "lovelace", quantity: "10000000" }], + }, + { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "2000000" }, + { unit: setup.authTokenId, quantity: "1" }, + ], + }, + ], + })), + }; +} + +describe("finalizeConfirmedProxySetup", () => { + it("creates a proxy row when confirmed chain state is present", async () => { + const { finalizeConfirmedProxySetup } = await import("@/lib/server/proxySetupFinalization"); + const db = createDb(); + const provider = createProvider({ + walletUtxos: [ + mkUtxo("addr_test_wallet", [ + { unit: "lovelace", quantity: "2000000" }, + { unit: "policy", quantity: "1" }, + ]), + ], + proxyUtxos: [ + mkUtxo("addr_test_proxy", [{ unit: "lovelace", quantity: "1000000" }]), + ], + }); + + const result = await finalizeConfirmedProxySetup({ + db: db as never, + network: 0, + walletId: "wallet-1", + walletAddress: "addr_test_wallet", + txHash: validTxHash, + setup, + provider, + }); + + expect("error" in result).toBe(false); + expect(db.proxy.create).toHaveBeenCalledWith({ + data: { + walletId: "wallet-1", + proxyAddress: setup.proxyAddress, + authTokenId: setup.authTokenId, + paramUtxo: JSON.stringify(setup.paramUtxo), + description: setup.description, + isActive: true, + }, + }); + }); + + it("rejects confirmed setup when the auth token is missing at the wallet", async () => { + const { finalizeConfirmedProxySetup } = await import("@/lib/server/proxySetupFinalization"); + const result = await finalizeConfirmedProxySetup({ + db: createDb() as never, + network: 0, + walletId: "wallet-1", + walletAddress: "addr_test_wallet", + txHash: validTxHash, + setup, + provider: createProvider({ + walletUtxos: [ + mkUtxo("addr_test_wallet", [{ unit: "lovelace", quantity: "2000000" }]), + ], + proxyUtxos: [ + mkUtxo("addr_test_proxy", [{ unit: "lovelace", quantity: "1000000" }]), + ], + }), + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("auth token is not present"); + } + }); + + it("is idempotent when an active proxy row already exists", async () => { + const { finalizeConfirmedProxySetup } = await import("@/lib/server/proxySetupFinalization"); + const existingProxy = { id: "proxy-existing", isActive: true }; + const db = createDb(existingProxy); + const result = await finalizeConfirmedProxySetup({ + db: db as never, + network: 0, + walletId: "wallet-1", + walletAddress: "addr_test_wallet", + txHash: validTxHash, + setup, + provider: createProvider({ + walletUtxos: [ + mkUtxo("addr_test_wallet", [ + { unit: "lovelace", quantity: "2000000" }, + { unit: "policy", quantity: "1" }, + ]), + ], + proxyUtxos: [ + mkUtxo("addr_test_proxy", [{ unit: "lovelace", quantity: "1000000" }]), + ], + }), + }); + + expect(result).toBe(existingProxy); + expect(db.proxy.create).not.toHaveBeenCalled(); + }); + + it("rejects finalization when txHash does not match setup outputs", async () => { + const { finalizeConfirmedProxySetup } = await import("@/lib/server/proxySetupFinalization"); + const result = await finalizeConfirmedProxySetup({ + db: createDb() as never, + network: 0, + walletId: "wallet-1", + walletAddress: "addr_test_wallet", + txHash: validTxHash, + setup, + provider: { + fetchAddressUTxOs: jest.fn(async () => []), + get: jest.fn(async () => ({ + outputs: [{ address: "addr_test_other", amount: [{ unit: "lovelace", quantity: "1000000" }] }], + })), + }, + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("txHash does not match confirmed proxy setup outputs"); + } + }); + + it("rejects malformed txHash before provider lookup", async () => { + const { finalizeConfirmedProxySetup } = await import("@/lib/server/proxySetupFinalization"); + const provider = createProvider({ + walletUtxos: [], + proxyUtxos: [], + }); + + const result = await finalizeConfirmedProxySetup({ + db: createDb() as never, + network: 0, + walletId: "wallet-1", + walletAddress: "addr_test_wallet", + txHash: "transaction-row-id", + setup, + provider, + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("txHash must be a 64-character hex string"); + } + expect(provider.get).not.toHaveBeenCalled(); + }); +}); diff --git a/src/__tests__/proxyTxBuilders.test.ts b/src/__tests__/proxyTxBuilders.test.ts new file mode 100644 index 00000000..1cca2d4b --- /dev/null +++ b/src/__tests__/proxyTxBuilders.test.ts @@ -0,0 +1,273 @@ +import { describe, expect, it } from "@jest/globals"; +import type { UTxO } from "@meshsdk/core"; +import { + buildProxyDRepCertificateTx, + buildProxyCleanupTx, + buildProxyCleanupSweepTx, + buildProxyVoteTx, + buildProxySetupTx, + DEFAULT_PROXY_SETUP_LOVELACE, +} from "@/lib/server/proxyTxBuilders"; + +const mkUtxo = ( + address: string, + lovelace: string, + txHash = "a".repeat(64), + outputIndex = 0, +): UTxO => + ({ + input: { txHash, outputIndex }, + output: { + address, + amount: [{ unit: "lovelace", quantity: lovelace }], + }, + }) as UTxO; + +function createTxBuilderMock() { + const txOuts: Array<{ address: string; amount: UTxO["output"]["amount"] }> = []; + const mints: Array<{ quantity: string; policyId: string; tokenName: string }> = []; + const txIns: Array<{ txHash: string; outputIndex: number; address: string }> = []; + const builder = { + spendingPlutusScriptV3: () => builder, + txIn: ( + txHash: string, + outputIndex: number, + _amount: UTxO["output"]["amount"], + address: string, + ) => { + txIns.push({ txHash, outputIndex, address }); + return builder; + }, + txInScript: () => builder, + txInInlineDatumPresent: () => builder, + txInRedeemerValue: () => builder, + mintPlutusScriptV3: () => builder, + mint: (quantity: string, policyId: string, tokenName: string) => { + mints.push({ quantity, policyId, tokenName }); + return builder; + }, + mintingScript: () => builder, + mintRedeemerValue: () => builder, + txOut: (address: string, amount: UTxO["output"]["amount"]) => { + txOuts.push({ address, amount }); + return builder; + }, + txInCollateral: () => builder, + changeAddress: () => builder, + drepRegistrationCertificate: () => builder, + drepUpdateCertificate: () => builder, + drepDeregistrationCertificate: () => builder, + certificateScript: () => builder, + certificateRedeemerValue: () => builder, + votePlutusScriptV3: () => builder, + vote: () => builder, + voteScript: () => builder, + voteRedeemerValue: () => builder, + }; + + return { builder, txOuts, mints, txIns }; +} + +describe("buildProxySetupTx", () => { + it("defaults the proxy output to the minimal setup lovelace", () => { + const { builder, txOuts } = createTxBuilderMock(); + const setup = buildProxySetupTx({ + txBuilder: builder as never, + network: 0, + walletUtxos: [mkUtxo("addr_test_wallet", "20000000")], + walletAddress: "addr_test_wallet", + collateral: mkUtxo("addr_test_collateral", "5000000", "b".repeat(64), 1), + }); + + expect(txOuts).toContainEqual({ + address: setup.proxyAddress, + amount: [{ unit: "lovelace", quantity: DEFAULT_PROXY_SETUP_LOVELACE }], + }); + }); + + it("uses initialProxyLovelace for the proxy setup output", () => { + const { builder, txOuts } = createTxBuilderMock(); + const setup = buildProxySetupTx({ + txBuilder: builder as never, + network: 0, + walletUtxos: [mkUtxo("addr_test_wallet", "20000000")], + walletAddress: "addr_test_wallet", + collateral: mkUtxo("addr_test_collateral", "5000000", "b".repeat(64), 1), + initialProxyLovelace: "5000000", + }); + + expect(txOuts).toContainEqual({ + address: setup.proxyAddress, + amount: [{ unit: "lovelace", quantity: "5000000" }], + }); + }); + + it("burns all 10 auth tokens for proxy cleanup", () => { + const setupBuilder = createTxBuilderMock(); + const setup = buildProxySetupTx({ + txBuilder: setupBuilder.builder as never, + network: 0, + walletUtxos: [mkUtxo("addr_test_wallet", "20000000")], + walletAddress: "addr_test_wallet", + collateral: mkUtxo("addr_test_collateral", "5000000", "b".repeat(64), 1), + }); + + const cleanupBuilder = createTxBuilderMock(); + const result = buildProxyCleanupTx({ + txBuilder: cleanupBuilder.builder as never, + network: 0, + paramUtxo: setup.paramUtxo, + walletUtxos: [ + ({ + ...mkUtxo("addr_test_wallet", "3000000", "c".repeat(64), 2), + output: { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "3000000" }, + { unit: setup.authTokenId, quantity: "10" }, + ], + }, + }) as UTxO, + ], + collateral: mkUtxo("addr_test_collateral", "5000000", "d".repeat(64), 3), + walletAddress: "addr_test_wallet", + authTokenId: setup.authTokenId, + }); + + expect(result).toEqual({ burnedAuthTokens: "10" }); + expect(cleanupBuilder.mints).toContainEqual({ + quantity: "-10", + policyId: setup.authTokenId, + tokenName: "", + }); + }); + + it("sweeps proxy UTxOs back to the wallet while preserving an auth token", () => { + const setupBuilder = createTxBuilderMock(); + const setup = buildProxySetupTx({ + txBuilder: setupBuilder.builder as never, + network: 0, + walletUtxos: [mkUtxo("addr_test_wallet", "20000000")], + walletAddress: "addr_test_wallet", + collateral: mkUtxo("addr_test_collateral", "5000000", "b".repeat(64), 1), + }); + + const sweepBuilder = createTxBuilderMock(); + const result = buildProxyCleanupSweepTx({ + txBuilder: sweepBuilder.builder as never, + network: 0, + paramUtxo: setup.paramUtxo, + proxyAddress: setup.proxyAddress, + proxyUtxos: [mkUtxo(setup.proxyAddress, "2500000", "c".repeat(64), 2)], + walletUtxos: [ + ({ + ...mkUtxo("addr_test_wallet", "3000000", "d".repeat(64), 3), + output: { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "3000000" }, + { unit: setup.authTokenId, quantity: "1" }, + ], + }, + }) as UTxO, + ], + authTokenUtxo: ({ + ...mkUtxo("addr_test_wallet", "3000000", "d".repeat(64), 3), + output: { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "3000000" }, + { unit: setup.authTokenId, quantity: "1" }, + ], + }, + }) as UTxO, + collateral: mkUtxo("addr_test_collateral", "5000000", "e".repeat(64), 4), + walletAddress: "addr_test_wallet", + }); + + expect(result).toEqual({ sweptProxyUtxos: "1", preservedAuthTokens: "1" }); + expect(sweepBuilder.txIns).toContainEqual({ + txHash: "c".repeat(64), + outputIndex: 2, + address: setup.proxyAddress, + }); + expect(sweepBuilder.txOuts).toContainEqual({ + address: "addr_test_wallet", + amount: expect.arrayContaining([ + { unit: "lovelace", quantity: "2500000" }, + { unit: setup.authTokenId, quantity: "1" }, + ]), + }); + expect(sweepBuilder.mints).toEqual([]); + }); +}); + +describe("proxy action funding validation", () => { + it("rejects proxy vote inputs that cannot preserve the auth token output", () => { + const setupBuilder = createTxBuilderMock(); + const setup = buildProxySetupTx({ + txBuilder: setupBuilder.builder as never, + network: 0, + walletUtxos: [mkUtxo("addr_test_wallet", "20000000")], + walletAddress: "addr_test_wallet", + collateral: mkUtxo("addr_test_collateral", "5000000", "b".repeat(64), 1), + }); + const authTokenUtxo = { + ...mkUtxo("addr_test_wallet", "1200000", "c".repeat(64), 2), + output: { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "1200000" }, + { unit: setup.authTokenId, quantity: "1" }, + ], + }, + } as UTxO; + + expect(() => + buildProxyVoteTx({ + txBuilder: createTxBuilderMock().builder as never, + network: 0, + paramUtxo: setup.paramUtxo, + walletUtxos: [authTokenUtxo], + authTokenUtxo, + collateral: mkUtxo("addr_test_collateral", "5000000", "d".repeat(64), 3), + walletAddress: "addr_test_wallet", + votes: [{ proposalId: `${"e".repeat(64)}#0`, voteKind: "Abstain" }], + }), + ).toThrow(/proxy vote requires at least 2 ADA in selected wallet inputs, but only 1.2 ADA was selected/); + }); + + it("rejects proxy DRep deregister inputs that cannot preserve the auth token output", () => { + const setupBuilder = createTxBuilderMock(); + const setup = buildProxySetupTx({ + txBuilder: setupBuilder.builder as never, + network: 0, + walletUtxos: [mkUtxo("addr_test_wallet", "20000000")], + walletAddress: "addr_test_wallet", + collateral: mkUtxo("addr_test_collateral", "5000000", "b".repeat(64), 1), + }); + const authTokenUtxo = { + ...mkUtxo("addr_test_wallet", "1200000", "c".repeat(64), 2), + output: { + address: "addr_test_wallet", + amount: [ + { unit: "lovelace", quantity: "1200000" }, + { unit: setup.authTokenId, quantity: "1" }, + ], + }, + } as UTxO; + + expect(() => + buildProxyDRepCertificateTx({ + txBuilder: createTxBuilderMock().builder as never, + network: 0, + paramUtxo: setup.paramUtxo, + walletUtxos: [authTokenUtxo], + authTokenUtxo, + collateral: mkUtxo("addr_test_collateral", "5000000", "d".repeat(64), 3), + walletAddress: "addr_test_wallet", + action: "deregister", + }), + ).toThrow(/proxy DRep deregister requires at least 2 ADA in selected wallet inputs, but only 1.2 ADA was selected/); + }); +}); diff --git a/src/__tests__/proxyUtxos.test.ts b/src/__tests__/proxyUtxos.test.ts new file mode 100644 index 00000000..1d9aeb97 --- /dev/null +++ b/src/__tests__/proxyUtxos.test.ts @@ -0,0 +1,115 @@ +import { describe, expect, it } from "@jest/globals"; +import type { UTxO } from "@meshsdk/core"; +import { + requireAuthTokenUtxo, + resolveCollateralRefFromChain, + selectProxyUtxosForOutputs, +} from "@/lib/server/proxyUtxos"; + +const mkUtxo = ( + address: string, + amount: UTxO["output"]["amount"], + txHash = "aa", + outputIndex = 0, +): UTxO => + ({ + input: { txHash, outputIndex }, + output: { address, amount }, + }) as UTxO; + +describe("proxyUtxos", () => { + it("rejects collateral below 5 ADA", async () => { + const result = await resolveCollateralRefFromChain({ + network: 0, + collateralRef: { txHash: "aa", outputIndex: 0 }, + provider: { + fetchUTxOs: async () => [ + mkUtxo("addr_test", [{ unit: "lovelace", quantity: "4999999" }]), + ], + }, + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("at least 5 ADA"); + } + }); + + it("rejects collateral at an unexpected address", async () => { + const result = await resolveCollateralRefFromChain({ + network: 0, + collateralRef: { txHash: "aa", outputIndex: 0 }, + expectedAddress: "addr_test_signer", + provider: { + fetchUTxOs: async () => [ + mkUtxo("addr_test_wallet_script", [{ unit: "lovelace", quantity: "6000000" }]), + ], + }, + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("expected address"); + } + }); + + it("rejects collateral with native assets", async () => { + const result = await resolveCollateralRefFromChain({ + network: 0, + collateralRef: { txHash: "aa", outputIndex: 0 }, + expectedAddress: "addr_test_signer", + provider: { + fetchUTxOs: async () => [ + mkUtxo("addr_test_signer", [ + { unit: "lovelace", quantity: "6000000" }, + { unit: "policy.asset", quantity: "1" }, + ]), + ], + }, + }); + + expect("error" in result).toBe(true); + if ("error" in result) { + expect(result.error).toContain("ADA-only"); + } + }); + + it("finds the proxy auth-token UTxO", () => { + const result = requireAuthTokenUtxo( + [ + mkUtxo("addr_wallet", [{ unit: "lovelace", quantity: "3000000" }]), + mkUtxo( + "addr_wallet", + [ + { unit: "lovelace", quantity: "2000000" }, + { unit: "policyid", quantity: "1" }, + ], + "bb", + 1, + ), + ], + "policyid", + ); + + expect("error" in result).toBe(false); + if (!("error" in result)) { + expect(result.input.txHash).toBe("bb"); + } + }); + + it("selects proxy UTxOs that cover requested outputs plus fee buffer", () => { + const result = selectProxyUtxosForOutputs({ + proxyUtxos: [ + mkUtxo("addr_proxy", [{ unit: "lovelace", quantity: "1000000" }], "aa", 0), + mkUtxo("addr_proxy", [{ unit: "lovelace", quantity: "2500000" }], "bb", 1), + ], + outputs: [{ address: "addr_target", unit: "lovelace", amount: "1500000" }], + feeBufferLovelace: BigInt(500000), + }); + + expect(Array.isArray(result)).toBe(true); + if (Array.isArray(result)) { + expect(result.map((utxo) => utxo.input.txHash)).toEqual(["bb"]); + } + }); +}); diff --git a/src/__tests__/resolveDRepAnchorFromUrl.test.ts b/src/__tests__/resolveDRepAnchorFromUrl.test.ts new file mode 100644 index 00000000..7baf3ee5 --- /dev/null +++ b/src/__tests__/resolveDRepAnchorFromUrl.test.ts @@ -0,0 +1,53 @@ +import { afterEach, describe, expect, it, jest } from "@jest/globals"; +import { Readable } from "stream"; +import { hashDrepAnchor } from "@meshsdk/core"; + +jest.mock("node:dns/promises", () => ({ + lookup: jest.fn(() => + Promise.resolve([{ address: "8.8.8.8", family: 4 }] as { address: string; family: number }[]), + ), +})); + +// undici.request is the transport used by resolveDRepAnchorFromUrl — the +// previous test mocked global.fetch, but the implementation now pins the +// resolved IP via undici's buildConnector to close the DNS-rebinding TOCTOU. +const requestMock = jest.fn<(...args: unknown[]) => unknown>(); +jest.mock("undici", () => ({ + request: (...args: unknown[]) => requestMock(...args), + Agent: jest.fn(), + buildConnector: jest.fn(() => () => undefined), +})); + +import { resolveDRepAnchorFromUrl } from "@/lib/server/resolveDRepAnchorFromUrl"; + +function makeResponse(body: string, statusCode = 200) { + return { + statusCode, + headers: { "content-type": "application/json" }, + body: Readable.from(Buffer.from(body, "utf8")), + }; +} + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe("resolveDRepAnchorFromUrl", () => { + it("computes hash from JSON body", async () => { + const doc = { "@context": "https://example.com", name: "Test" }; + requestMock.mockResolvedValueOnce(makeResponse(JSON.stringify(doc))); + + const r = await resolveDRepAnchorFromUrl("https://example.test/drep.json"); + expect(r.anchorUrl).toBe("https://example.test/drep.json"); + expect(r.anchorDataHash).toBe(hashDrepAnchor(doc as object)); + }); + + it("rejects when optional anchorDataHash mismatches", async () => { + const doc = { x: 1 }; + requestMock.mockResolvedValueOnce(makeResponse(JSON.stringify(doc))); + + await expect( + resolveDRepAnchorFromUrl("https://example.test/a.json", "deadbeef"), + ).rejects.toThrow(/anchorDataHash does not match/); + }); +}); diff --git a/src/__tests__/resolveUtxoRefsFromChain.test.ts b/src/__tests__/resolveUtxoRefsFromChain.test.ts new file mode 100644 index 00000000..7c753c0b --- /dev/null +++ b/src/__tests__/resolveUtxoRefsFromChain.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, it } from "@jest/globals"; +import type { UTxO } from "@meshsdk/core"; +import { resolveUtxoRefsFromChain } from "@/lib/server/resolveUtxoRefsFromChain"; + +const mkUtxo = (addr: string, txHash = "ab", idx = 0): UTxO => + ({ + input: { txHash, outputIndex: idx }, + output: { address: addr, amount: [{ unit: "lovelace", quantity: "3000000" }] }, + }) as UTxO; + +describe("resolveUtxoRefsFromChain", () => { + it("rejects empty utxoRefs", async () => { + const r = await resolveUtxoRefsFromChain({ + network: 0, + utxoRefs: [], + expectedSpendAddress: "addr1test", + provider: { fetchUTxOs: async () => [] }, + }); + expect("error" in r && r.status === 400).toBe(true); + }); + + it("rejects when output address does not match spend address", async () => { + const r = await resolveUtxoRefsFromChain({ + network: 0, + utxoRefs: [{ txHash: "aa", outputIndex: 0 }], + expectedSpendAddress: "addr_expected", + provider: { + fetchUTxOs: async () => [mkUtxo("addr_other", "aa", 0)], + }, + }); + expect("error" in r).toBe(true); + if ("error" in r) { + expect(r.error).toContain("multisig spend address"); + } + }); + + it("returns utxos when address matches", async () => { + const addr = "addr1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; + const r = await resolveUtxoRefsFromChain({ + network: 0, + utxoRefs: [{ txHash: "aa", outputIndex: 1 }], + expectedSpendAddress: addr, + provider: { + fetchUTxOs: async (hash, index) => { + expect(hash).toBe("aa"); + expect(index).toBe(1); + return [mkUtxo(addr, "aa", 1)]; + }, + }, + }); + expect("utxos" in r && r.utxos.length === 1).toBe(true); + }); +}); diff --git a/src/__tests__/reviewSignersCardKey.test.ts b/src/__tests__/reviewSignersCardKey.test.ts new file mode 100644 index 00000000..c55c5f9c --- /dev/null +++ b/src/__tests__/reviewSignersCardKey.test.ts @@ -0,0 +1,289 @@ +/** + * Regression test for Finding 1.1 (rocksolid/harden-pr-233): + * React key collision when multiple empty signer rows exist. + * + * The fix introduced a parallel `signerIds: string[]` array in + * useWalletFlowState / useMigrationWalletFlowState that is used as the + * React `key` on each signer row, instead of the (possibly empty, + * possibly duplicated) address string. + * + * This test pins the invariant on two layers: + * 1. The data-shape invariants of the React-key fix — exercised here + * by inline simulation of the hook's add/remove array logic. We + * cannot drive the hook itself in a node-environment jest run + * (the hook depends on next/router, zustand, tRPC, and toast + * providers), so this layer pins the *shape* the hook is + * contracted to maintain: synthetic ids stay distinct across + * empty-row collisions, and removal preserves index alignment + * across all five parallel arrays. + * 2. A source-level tripwire (separate describe block below) that + * catches anyone reverting the JSX back to address-as-key, or + * removing the parallel signerIds array from either hook. The + * React-key behavior itself — that the JSX consumes signerIds + * and that the hook exposes it — is pinned by that tripwire. + * + * Why no `renderHook`: `useWalletFlowState` depends on next/router, + * zustand, tRPC, and toast providers, none of which exist in jest's + * `node` test environment. Adding `@testing-library/react` + jsdom + * would be substantial scaffolding and out of scope for this change. + */ + +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +import { makeSignerId } from "@/components/pages/homepage/wallets/new-wallet-flow/shared/signerRows"; + +// ESM equivalent of CJS __dirname. Tests run under +// node --experimental-vm-modules so CJS globals are unavailable. +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +// Mirror the splice-based array logic that addSigner / removeSigner +// implement inside the two flow-state hooks. We cannot import the hooks +// directly because they pull in next/router, zustand, tRPC, and toast +// providers — none of which exist in jest's node test environment. So +// we replicate the data flow at the same level of abstraction the hook +// uses, and pin the invariant: after add/remove cycles, each parallel +// array stays index-aligned with the others. +type SignerRow = { + address: string; + description: string; + stakeKey: string; + drepKey: string; + id: string; +}; + +function applyAdd(rows: SignerRow[], newId: string): SignerRow[] { + // Mirrors addSigner: pushes empty fields with a fresh synthetic id. + return [ + ...rows, + { address: "", description: "", stakeKey: "", drepKey: "", id: newId }, + ]; +} + +function applyRemove(rows: SignerRow[], index: number): SignerRow[] { + // Mirrors removeSigner: splices the same index out of every parallel + // array. With address-as-key, two empty rows would collide on key="" + // and React could splice the wrong one — synthetic ids prevent that. + const next = rows.slice(); + next.splice(index, 1); + return next; +} + +describe("ReviewSignersCard signer-row key invariant", () => { + test("removing the middle of three signers keeps remaining rows aligned", () => { + const initial: SignerRow[] = [ + { + address: "addr1qx_creator", + description: "Alice", + stakeKey: "stake1_alice", + drepKey: "drep_alice", + id: "id-creator", + }, + ]; + + // User clicks "Add Signer" twice. Both new rows have address "" — + // the bug case. Synthetic ids must still differ. + const afterAdd1 = applyAdd(initial, "id-bob"); + const afterAdd2 = applyAdd(afterAdd1, "id-carol"); + + expect(afterAdd2).toHaveLength(3); + // Two empty addresses, but ids are distinct. + expect(afterAdd2[1]!.address).toBe(""); + expect(afterAdd2[2]!.address).toBe(""); + expect(afterAdd2[1]!.id).not.toBe(afterAdd2[2]!.id); + + // Fill them in so we can tell which row is which. + afterAdd2[1] = { ...afterAdd2[1]!, address: "addr1_bob", description: "Bob", stakeKey: "stake1_bob" }; + afterAdd2[2] = { ...afterAdd2[2]!, address: "addr1_carol", description: "Carol", stakeKey: "stake1_carol" }; + + // Remove Bob (index 1). + const afterRemove = applyRemove(afterAdd2, 1); + + expect(afterRemove).toHaveLength(2); + // Alice still at index 0, Carol now at index 1 — descriptions and + // stake keys must follow the same row, NOT slip out of alignment. + expect(afterRemove[0]!.description).toBe("Alice"); + expect(afterRemove[0]!.stakeKey).toBe("stake1_alice"); + expect(afterRemove[1]!.description).toBe("Carol"); + expect(afterRemove[1]!.stakeKey).toBe("stake1_carol"); + expect(afterRemove[1]!.address).toBe("addr1_carol"); + }); + + test("two consecutive Add Signer clicks produce distinct synthetic ids", () => { + // The exact bug case: with key={signer} (address) two empty rows + // would collide. Synthetic ids must differ regardless of address. + let rows: SignerRow[] = []; + rows = applyAdd(rows, "id-1"); + rows = applyAdd(rows, "id-2"); + + const ids = rows.map((r) => r.id); + expect(new Set(ids).size).toBe(rows.length); + }); + + test( + "addSigner-then-removeSigner: surviving row keeps its synthetic id, " + + "data-shape invariant pinned via inline simulation", + () => { + // Mirrors the array-manipulation contract the hook's `addSigner` + // / `removeSigner` setters apply, inline. `makeSignerId` runs + // unmocked so we exercise real id minting (crypto.randomUUID + // under Node >= 14.17, fallback otherwise). + // + // Scenario: start with one creator-seeded row (the first-user + // effect), append two empty rows, capture the id of the third + // row (the survivor), then splice index 1 — a mid-array empty + // remove. Assert that ids[1] is the survivor's *original* id + // (not a re-issued one) and that every parallel array stays + // index-aligned with ids. + + type Arrays = { + addresses: string[]; + descriptions: string[]; + stakeKeys: string[]; + drepKeys: string[]; + ids: string[]; + }; + + // Seed three rows. Index 0 is the creator (Alice). Index 1 is an + // empty row (Bob, never filled in) — preserves the empty-row + // collision scenario this test was originally written for. Index + // 2 (Carol, the survivor) carries distinct, non-empty values in + // every parallel array. After removing index 1, index 1 must + // hold Carol's distinct values; an off-by-one that mis-spliced + // any single non-id array would leave "" in that array's slot + // and fail the assertion. + let state: Arrays = { + addresses: ["addr1_creator", "", "addr1_carol"], + descriptions: ["Alice", "", "Carol"], + stakeKeys: ["stake1_creator", "", "stake1_carol"], + drepKeys: ["", "", "drep1_carol"], + ids: [makeSignerId(), makeSignerId(), makeSignerId()], + }; + + expect(state.ids).toHaveLength(3); + // Three distinct synthetic ids — the bug case (two empty rows + // sharing key="") cannot reproduce when ids are minted per-row. + expect(new Set(state.ids).size).toBe(3); + + // Survivor: the row currently at index 2. Its id must follow the + // row, not the index, after we remove index 1. + const survivorOriginalId = state.ids[2]!; + + // Splice index 1 out of every parallel array, mirroring + // removeSigner. + const spliceOut = (arr: T[], i: number): T[] => { + const next = arr.slice(); + next.splice(i, 1); + return next; + }; + state = { + addresses: spliceOut(state.addresses, 1), + descriptions: spliceOut(state.descriptions, 1), + stakeKeys: spliceOut(state.stakeKeys, 1), + drepKeys: spliceOut(state.drepKeys, 1), + ids: spliceOut(state.ids, 1), + }; + + expect(state.ids).toHaveLength(2); + // The id now at index 1 must be the survivor's original id — + // proving identity follows the row, not the position. If the hook + // re-minted ids on remove (the broken pattern), this would fail. + expect(state.ids[1]).toBe(survivorOriginalId); + // Every parallel array stays index-aligned with ids AND the + // survivor's distinct values land at index 1. An off-by-one that + // spliced index 2 instead of index 1 would leave "" here in any + // single array — making the splice direction directly testable. + expect(state.addresses[1]).toBe("addr1_carol"); + expect(state.descriptions[1]).toBe("Carol"); + expect(state.stakeKeys[1]).toBe("stake1_carol"); + expect(state.drepKeys[1]).toBe("drep1_carol"); + // Creator row at index 0 untouched. + expect(state.ids[0]).not.toBe(survivorOriginalId); + expect(state.addresses[0]).toBe("addr1_creator"); + expect(state.descriptions[0]).toBe("Alice"); + expect(state.stakeKeys[0]).toBe("stake1_creator"); + }, + ); +}); + +describe("ReviewSignersCard tripwire on source", () => { + // Pin the source-level fix: anyone reverting back to address-as-key + // (or removing the parallel signerIds) will see this test fail. + const SOURCE_PATH = path.resolve( + __dirname, + "../components/pages/homepage/wallets/new-wallet-flow/create/ReviewSignersCard.tsx", + ); + const HOOK_PATH = path.resolve( + __dirname, + "../components/pages/homepage/wallets/new-wallet-flow/shared/useWalletFlowState.tsx", + ); + const MIGRATION_HOOK_PATH = path.resolve( + __dirname, + "../components/pages/wallet/info/migration/useMigrationWalletFlowState.tsx", + ); + + test("ReviewSignersCard never uses the raw address as a React key", () => { + const src = fs.readFileSync(SOURCE_PATH, "utf8"); + + // ---- Negative tripwire ---- + // + // Nothing within `key={ ... }` may start with the bare identifier + // `signer` (the per-iteration address). The boundary class + // `(\s|\}|[^a-zA-Z_0-9])` after `signer` rejects the entire + // address-as-key family: + // - `key={signer}` (the original bug) + // - `key={ signer }` (whitespace variant) + // - `key={signer ?? ""}` (nullish-coalescing fallback) + // - `key={signer.address}` (member-access — different revert) + // - `key={String(signer)}` ('(' is non-alphanumeric) + // + // It deliberately does NOT trip on the synthetic forms + // `key={signerIds[index]}` or `key={signerIds[index] ?? "..."}` + // because the `I` in `Ids` is a-zA-Z and falls outside the + // boundary class — `signer` followed by a word char is fine. + expect(src).not.toMatch(/key=\{\s*signer(\s|\}|[^a-zA-Z_0-9])/); + + // ---- Positive tripwire ---- + // + // Within 200 chars of an opening ` + // without breaking this test (the synthetic-id behavior survives). + // It still fails if anyone reverts to the bare address or to a + // bare index-as-key. + expect(src).toMatch( + //g) ?? []; + const mobileCardBlock = divMobileBlocks.find( + (block) => + /rounded-lg border/.test(block) && + /key=\{[\s\S]{0,80}(signerIds|rowKey\()/.test(block), + ); + expect(mobileCardBlock).toBeDefined(); + }); + + test("useWalletFlowState exposes signerIds parallel to signersAddresses", () => { + const src = fs.readFileSync(HOOK_PATH, "utf8"); + expect(src).toMatch(/signerIds/); + expect(src).toMatch(/setSignerIds/); + }); + + test("useMigrationWalletFlowState exposes signerIds parallel to signersAddresses", () => { + const src = fs.readFileSync(MIGRATION_HOOK_PATH, "utf8"); + expect(src).toMatch(/signerIds/); + expect(src).toMatch(/setSignerIds/); + }); +}); diff --git a/src/__tests__/setupEnv.cjs b/src/__tests__/setupEnv.cjs new file mode 100644 index 00000000..1314d88b --- /dev/null +++ b/src/__tests__/setupEnv.cjs @@ -0,0 +1,21 @@ +// @ts-nocheck — env bootstrap; checkJs flags `NODE_ENV` as read-only +// because @types/node narrows it to a literal union, but writing it here +// is intentional and safe (runs before any test module is imported). +// +// Sets dummy env vars so that `src/env.js` (t3-oss validate) does not throw +// when test files import server modules transitively. +// Tests that need real values can override per-test with `process.env.X = ...` +// inside `beforeEach`. + +process.env['NODE_ENV'] = process.env['NODE_ENV'] || 'test'; +process.env.SKIP_ENV_VALIDATION = '1'; + +process.env.DATABASE_URL = process.env.DATABASE_URL || 'postgresql://test:test@localhost:5432/test'; +process.env.JWT_SECRET = process.env.JWT_SECRET || 'a'.repeat(48); +process.env.PINATA_JWT = process.env.PINATA_JWT || 'test-pinata-jwt'; + +process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY_MAINNET = + process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY_MAINNET || 'test-blockfrost-mainnet'; +process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY_PREPROD = + process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY_PREPROD || 'test-blockfrost-preprod'; +process.env.NEXT_PUBLIC_NETWORK_ID = process.env.NEXT_PUBLIC_NETWORK_ID || '0'; diff --git a/src/__tests__/signTransaction.bot.test.ts b/src/__tests__/signTransaction.bot.test.ts new file mode 100644 index 00000000..fa0ffe91 --- /dev/null +++ b/src/__tests__/signTransaction.bot.test.ts @@ -0,0 +1,210 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { BOT_TEST_ADDRESS, createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const enforceBodySizeMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const getBotWalletAccessMock: jest.Mock = jest.fn(); +const resolvePaymentKeyHashMock: jest.Mock = jest.fn(); +const calculateTxHashMock: jest.Mock = jest.fn(); +const createVkeyWitnessFromHexMock: jest.Mock = jest.fn(); +const addUniqueVkeyWitnessToTxMock: jest.Mock = jest.fn(); +const shouldSubmitMultisigTxMock: jest.Mock = jest.fn(); +const submitTxWithScriptRecoveryMock: jest.Mock = jest.fn(); +const findWalletMock: jest.Mock = jest.fn(); +const findTransactionMock: jest.Mock = jest.fn(); +const updateManyTransactionMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, + enforceBodySize: enforceBodySizeMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/lib/auth/botAccess", () => ({ + __esModule: true, + getBotWalletAccess: getBotWalletAccessMock, +}), { virtual: true }); + +jest.mock("@meshsdk/core", () => ({ + __esModule: true, + resolvePaymentKeyHash: resolvePaymentKeyHashMock, +}), { virtual: true }); + +jest.mock("@meshsdk/core-csl", () => ({ + __esModule: true, + calculateTxHash: calculateTxHashMock, +}), { virtual: true }); + +jest.mock("@/utils/txSignUtils", () => ({ + __esModule: true, + createVkeyWitnessFromHex: createVkeyWitnessFromHexMock, + addUniqueVkeyWitnessToTx: addUniqueVkeyWitnessToTxMock, + shouldSubmitMultisigTx: shouldSubmitMultisigTxMock, + submitTxWithScriptRecovery: submitTxWithScriptRecoveryMock, +}), { virtual: true }); + +jest.mock("@/utils/get-provider", () => ({ + __esModule: true, + getProvider: () => ({ submitTx: jest.fn() }), +}), { virtual: true }); + +jest.mock("@/utils/multisigSDK", () => ({ + __esModule: true, + addressToNetwork: () => 0, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: { + wallet: { findUnique: findWalletMock }, + transaction: { + findUnique: findTransactionMock, + updateMany: updateManyTransactionMock, + }, + }, +}), { virtual: true }); + +jest.mock("@/server/api/root", () => ({ + __esModule: true, + createCaller: () => ({ wallet: { getWallet: jest.fn() } }), +}), { virtual: true }); + +jest.mock("@/lib/security/rateLimit", () => ({ + __esModule: true, + getClientIP: () => "127.0.0.1", +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +function makeWitnessRecord() { + return { + vkey: () => ({ + public_key: () => ({ + hash: () => ({ to_bytes: () => Buffer.from("a1b2c3d4", "hex") }), + to_bech32: () => "bech32", + }), + }), + signature: () => ({ to_bytes: () => Buffer.from("ff", "hex") }), + }; +} + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/signTransaction")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + enforceBodySizeMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + (getBotWalletAccessMock as any).mockResolvedValue({ allowed: true, role: "cosigner" }); + (findWalletMock as any).mockResolvedValue({ + id: "wallet-1", + signersAddresses: [BOT_TEST_ADDRESS], + numRequiredSigners: 2, + type: "atLeast", + }); + (findTransactionMock as any) + .mockResolvedValueOnce({ + id: "tx-1", + walletId: "wallet-1", + state: 0, + signedAddresses: [], + rejectedAddresses: [], + txCbor: "deadbeef", + txJson: "{}", + txHash: null, + }) + .mockResolvedValueOnce({ + id: "tx-1", + state: 0, + signedAddresses: [BOT_TEST_ADDRESS], + rejectedAddresses: [], + txCbor: "deadbeef-merged", + txJson: "{\"multisig\":{\"state\":0}}", + txHash: null, + }); + resolvePaymentKeyHashMock.mockReturnValue("a1b2c3d4"); + calculateTxHashMock.mockReturnValue("ff".repeat(32)); + createVkeyWitnessFromHexMock.mockReturnValue({ + publicKey: { verify: () => true }, + signature: {}, + witness: {}, + keyHashHex: "a1b2c3d4", + }); + addUniqueVkeyWitnessToTxMock.mockReturnValue({ + txHex: "deadbeef-merged", + witnessAdded: true, + vkeyWitnesses: { len: () => 1, get: () => makeWitnessRecord() }, + }); + shouldSubmitMultisigTxMock.mockReturnValue(false); + (submitTxWithScriptRecoveryMock as any).mockResolvedValue({ + txHash: "hash", + txHex: "deadbeef-merged", + }); + (updateManyTransactionMock as any).mockResolvedValue({ count: 1 }); +}); + +describe("signTransaction bot API", () => { + it("returns 403 when bot is not cosigner", async () => { + (getBotWalletAccessMock as any).mockResolvedValue({ allowed: true, role: "observer" }); + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + transactionId: "tx-1", + address: BOT_TEST_ADDRESS, + signature: "aa".repeat(64), + key: "bb".repeat(64), + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(403); + }); + + it("records bot witness on happy path", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + transactionId: "tx-1", + address: BOT_TEST_ADDRESS, + signature: "aa".repeat(64), + key: "bb".repeat(64), + broadcast: false, + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(updateManyTransactionMock).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ + submitted: false, + })); + }); +}); diff --git a/src/__tests__/signTransaction.test.ts b/src/__tests__/signTransaction.test.ts index f4b2e873..b80006d2 100644 --- a/src/__tests__/signTransaction.test.ts +++ b/src/__tests__/signTransaction.test.ts @@ -14,13 +14,15 @@ jest.mock( { virtual: true }, ); -const verifyJwtMock = jest.fn<(token: string | undefined) => { address: string } | null>(); +const verifyJwtMock = jest.fn<(token: string | undefined) => { address: string; botId?: string; type?: string } | null>(); +const isBotJwtMock = jest.fn<(payload: unknown) => boolean>(); jest.mock( '@/lib/verifyJwt', () => ({ __esModule: true, verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, }), { virtual: true }, ); @@ -28,6 +30,9 @@ jest.mock( const applyRateLimitMock = jest.fn< (req: NextApiRequest, res: NextApiResponse, options?: unknown) => boolean >(); +const applyBotRateLimitMock = jest.fn< + (req: NextApiRequest, res: NextApiResponse, botId: string) => boolean +>(); const enforceBodySizeMock = jest.fn< (req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean >(); @@ -37,6 +42,7 @@ jest.mock( () => ({ __esModule: true, applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, enforceBodySize: enforceBodySizeMock, }), { virtual: true }, @@ -420,7 +426,9 @@ beforeEach(() => { addCorsCacheBustingHeadersMock.mockReset(); createCallerMock.mockReset(); verifyJwtMock.mockReset(); + isBotJwtMock.mockReset(); applyRateLimitMock.mockReset(); + applyBotRateLimitMock.mockReset(); enforceBodySizeMock.mockReset(); getClientIPMock.mockReset(); @@ -432,6 +440,8 @@ beforeEach(() => { resolvePaymentKeyHashMock.mockReturnValue(witnessKeyHashHex); addressToNetworkMock.mockReturnValue(0); applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + isBotJwtMock.mockReturnValue(false); enforceBodySizeMock.mockReturnValue(true); getClientIPMock.mockReturnValue('127.0.0.1'); shouldSubmitMultisigTxMock.mockReturnValue(true); @@ -455,6 +465,9 @@ beforeEach(() => { const existingWitnessCount = mergedWitnesses.len(); for (let i = 0; i < existingWitnessCount; i++) { const existingWitness = mergedWitnesses.get(i); + if (!existingWitness) { + continue; + } const existingKeyHash = Buffer.from( existingWitness.vkey().public_key().hash().to_bytes(), ).toString('hex').toLowerCase(); @@ -609,6 +622,98 @@ describe('signTransaction API route', () => { }); }); + it('records witness and returns 502 when signed transaction has PPView hash mismatch', async () => { + const address = 'addr_test1qpl3w9v4l5qhxk778exampleaddress'; + const walletId = 'wallet-id-ppview'; + const transactionId = 'transaction-id-ppview'; + const signatureHex = 'aa'.repeat(64); + const keyHex = 'bb'.repeat(64); + const submissionError = + 'Transaction rejected: scriptIntegrityHash mismatch (PPViewHashesDontMatch). This transaction cannot be repaired'; + + verifyJwtMock.mockReturnValue({ address }); + + walletGetWalletMock.mockResolvedValue({ + id: walletId, + type: 'atLeast', + numRequiredSigners: 1, + signersAddresses: [address], + }); + + const transactionRecord = { + id: transactionId, + walletId, + state: 0, + signedAddresses: [] as string[], + rejectedAddresses: [] as string[], + txCbor: 'stored-tx-hex', + txHash: null as string | null, + txJson: '{}', + }; + + const updatedTransaction = { + ...transactionRecord, + signedAddresses: [address], + txCbor: 'updated-tx-hex', + state: 0, + txJson: JSON.stringify({ + multisig: { + state: 0, + submitted: false, + submissionError, + }, + }), + }; + + dbTransactionFindUniqueMock + .mockResolvedValueOnce(transactionRecord) + .mockResolvedValueOnce(updatedTransaction); + + dbTransactionUpdateManyMock.mockResolvedValue({ count: 1 }); + getProviderMock.mockReturnValue({ submitTx: jest.fn() }); + submitTxWithScriptRecoveryMock.mockRejectedValueOnce(new Error(submissionError)); + + const req = { + method: 'POST', + headers: { authorization: 'Bearer valid-token' }, + body: { + walletId, + transactionId, + address, + signature: signatureHex, + key: keyHex, + }, + } as unknown as NextApiRequest; + + const res = createMockResponse(); + + await handler(req, res); + + expect(submitTxWithScriptRecoveryMock).toHaveBeenCalledWith( + expect.objectContaining({ + txHex: 'updated-tx-hex', + }), + ); + expect(dbTransactionUpdateManyMock).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + signedAddresses: { set: [address] }, + txCbor: 'updated-tx-hex', + state: 0, + txJson: expect.stringContaining('PPViewHashesDontMatch'), + }), + }), + ); + expect(res.status).toHaveBeenCalledWith(502); + expect(res.json).toHaveBeenCalledWith({ + error: 'Transaction witness recorded, but submission to network failed', + transaction: updatedTransaction, + submitted: false, + txHash: undefined, + submissionError, + }); + }); + it('returns 403 when JWT address mismatches request address', async () => { verifyJwtMock.mockReturnValue({ address: 'addr_test1qpotheraddress' }); diff --git a/src/__tests__/signing.test.ts b/src/__tests__/signing.test.ts new file mode 100644 index 00000000..81d46b3d --- /dev/null +++ b/src/__tests__/signing.test.ts @@ -0,0 +1,107 @@ +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +import { describe, expect, it, jest } from "@jest/globals"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +// --------------------------------------------------------------------------- +// Tripwire: the "broken" pattern — `return true ? signature : undefined;` +// must never reappear in `src/utils/signing.ts`. It both throws away the +// `checkSignature` result and obscures the actual signing contract. The +// regression we fixed here was that a failed signature verification still +// returned a (forged-looking) signature to the caller because the ternary +// was always truthy. +// --------------------------------------------------------------------------- +describe("signing.ts source contract", () => { + it("never returns the always-true ternary on the verification result", () => { + const src = fs.readFileSync( + path.resolve(__dirname, "../utils/signing.ts"), + "utf8", + ); + expect(src).not.toMatch(/return\s+true\s*\?/); + // Positive: the verified result must drive an explicit `if (!verified)` + // throw. The exact identifier we use is `verified` — accept either name + // so a future rename doesn't trip the tripwire. + expect(src).toMatch(/if\s*\(\s*!\s*(verified|result)\b/); + }); +}); + +// --------------------------------------------------------------------------- +// Behavioural: import the real `sign` and exercise every role plus the +// failure path. We mock the @meshsdk/core helpers because they pull in +// CSL/serialization which is heavyweight for a unit test. +// --------------------------------------------------------------------------- +const checkSignatureMock = jest.fn< + (nonce: string, signature: { signature: string; key: string }, address?: string) => Promise +>(); +const generateNonceMock = jest.fn<(payload: string) => string>(); + +jest.unstable_mockModule("@meshsdk/core", () => ({ + __esModule: true, + checkSignature: checkSignatureMock, + generateNonce: generateNonceMock, +})); + +const { sign } = await import("../utils/signing"); + +type MockWallet = { + signData: jest.Mock<(payload: string, address?: string) => Promise<{ signature: string; key: string }>>; + getRewardAddresses: jest.Mock<() => Promise>; +}; + +function createWallet(overrides?: Partial): MockWallet { + return { + signData: jest.fn<(payload: string, address?: string) => Promise<{ signature: string; key: string }>>( + async () => ({ signature: "deadbeef", key: "cafe" }), + ), + getRewardAddresses: jest.fn<() => Promise>(async () => ["stake_addr"]), + ...overrides, + } as MockWallet; +} + +describe("sign", () => { + beforeEach(() => { + checkSignatureMock.mockReset(); + generateNonceMock.mockReset(); + generateNonceMock.mockReturnValue("nonce-payload"); + }); + + it("role=0 signs with the user payment address and returns the signature", async () => { + checkSignatureMock.mockResolvedValueOnce(true); + const wallet = createWallet(); + const sig = await sign("payload", wallet as never, 0, "addr_test_user"); + expect(sig).toEqual({ signature: "deadbeef", key: "cafe" }); + expect(wallet.signData).toHaveBeenCalledWith("payload", "addr_test_user"); + }); + + it("role=2 signs with the wallet's reward (stake) address", async () => { + checkSignatureMock.mockResolvedValueOnce(true); + const wallet = createWallet(); + await sign("payload", wallet as never, 2); + expect(wallet.getRewardAddresses).toHaveBeenCalled(); + expect(wallet.signData).toHaveBeenCalledWith("payload", "stake_addr"); + }); + + it("role=3 requires an explicit dRepAddress and uses it", async () => { + checkSignatureMock.mockResolvedValueOnce(true); + const wallet = createWallet(); + await sign("payload", wallet as never, 3, undefined, "drep_xxx"); + expect(wallet.signData).toHaveBeenCalledWith("payload", "drep_xxx"); + }); + + it("throws when the chosen role has no resolved address", async () => { + const wallet = createWallet(); + await expect(sign("payload", wallet as never, 0, undefined)).rejects.toThrow( + /missing address/i, + ); + }); + + it("throws when checkSignature returns false (no silent ternary fallback)", async () => { + checkSignatureMock.mockResolvedValueOnce(false); + const wallet = createWallet(); + await expect(sign("payload", wallet as never, 0, "addr_test_user")).rejects.toThrow( + /Signature failed verification/i, + ); + }); +}); diff --git a/src/__tests__/submitDatum.bot.test.ts b/src/__tests__/submitDatum.bot.test.ts new file mode 100644 index 00000000..601905a0 --- /dev/null +++ b/src/__tests__/submitDatum.bot.test.ts @@ -0,0 +1,111 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { BOT_TEST_ADDRESS, createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const enforceBodySizeMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, maxBytes: number) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const assertBotWalletAccessMock: jest.Mock = jest.fn(); +const checkSignatureMock: jest.Mock = jest.fn(); +const createSignableMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, + enforceBodySize: enforceBodySizeMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/lib/auth/botAccess", () => ({ + __esModule: true, + assertBotWalletAccess: assertBotWalletAccessMock, +}), { virtual: true }); + +jest.mock("@meshsdk/core-cst", () => ({ + __esModule: true, + checkSignature: checkSignatureMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: { + signable: { create: createSignableMock }, + wallet: { findUnique: jest.fn() }, + }, +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/submitDatum")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + enforceBodySizeMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + (assertBotWalletAccessMock as any).mockResolvedValue({ wallet: { id: "wallet-1" } }); + (checkSignatureMock as any).mockResolvedValue(true); + (createSignableMock as any).mockResolvedValue({ id: "sig-1" }); +}); + +describe("submitDatum bot API", () => { + it("returns 401 for invalid datum signature", async () => { + (checkSignatureMock as any).mockResolvedValue(false); + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + signature: "sig", + key: "key", + address: BOT_TEST_ADDRESS, + datum: "payload", + callbackUrl: "https://example.com/callback", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(401); + }); + + it("creates signable datum for authorized bot", async () => { + const req = { + method: "POST", + headers: makeBearerAuth(), + body: { + walletId: "wallet-1", + signature: "sig", + key: "key", + address: BOT_TEST_ADDRESS, + datum: "payload", + callbackUrl: "https://example.com/callback", + }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(createSignableMock).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ id: "sig-1" }); + }); +}); diff --git a/src/__tests__/txScriptRecovery.test.ts b/src/__tests__/txScriptRecovery.test.ts new file mode 100644 index 00000000..e90fb0ac --- /dev/null +++ b/src/__tests__/txScriptRecovery.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from "@jest/globals"; +import type { MultisigSubmissionWallet } from "@/types/txSign"; +import { shouldSubmitMultisigTx } from "@/utils/txScriptRecovery"; + +const signersAddresses = ["addr_test_1", "addr_test_2", "addr_test_3"]; + +function wallet(overrides: Partial): MultisigSubmissionWallet { + return { + type: "all", + numRequiredSigners: null, + signersAddresses, + ...overrides, + }; +} + +describe("shouldSubmitMultisigTx", () => { + it("honors an explicit threshold stored on all wallets", () => { + const appWallet = wallet({ type: "all", numRequiredSigners: 2 }); + + expect(shouldSubmitMultisigTx(appWallet, 1)).toBe(false); + expect(shouldSubmitMultisigTx(appWallet, 2)).toBe(true); + }); + + it("keeps flat all wallets as all-of-N when no threshold is stored", () => { + const appWallet = wallet({ type: "all", numRequiredSigners: null }); + + expect(shouldSubmitMultisigTx(appWallet, 2)).toBe(false); + expect(shouldSubmitMultisigTx(appWallet, 3)).toBe(true); + }); + + it("keeps existing any and atLeast behavior", () => { + expect(shouldSubmitMultisigTx(wallet({ type: "any", numRequiredSigners: null }), 1)).toBe(true); + expect(shouldSubmitMultisigTx(wallet({ type: "atLeast", numRequiredSigners: 2 }), 1)).toBe(false); + expect(shouldSubmitMultisigTx(wallet({ type: "atLeast", numRequiredSigners: 2 }), 2)).toBe(true); + }); +}); diff --git a/src/__tests__/walletIds.bot.test.ts b/src/__tests__/walletIds.bot.test.ts new file mode 100644 index 00000000..bc035357 --- /dev/null +++ b/src/__tests__/walletIds.bot.test.ts @@ -0,0 +1,93 @@ +import { beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { BOT_TEST_ADDRESS, createMockResponse, makeBearerAuth, makeBotJwtPayload } from "./apiTestUtils"; + +const addCorsHeadersMock = jest.fn<(res: NextApiResponse) => void>(); +const corsMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => Promise>(); +const applyRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse) => boolean>(); +const applyBotRateLimitMock = jest.fn<(req: NextApiRequest, res: NextApiResponse, botId: string) => boolean>(); +const verifyJwtMock: jest.Mock = jest.fn(); +const isBotJwtMock: jest.Mock = jest.fn(); +const createCallerMock: jest.Mock = jest.fn(); +const getWalletIdsForBotMock: jest.Mock = jest.fn(); + +jest.mock("@/lib/cors", () => ({ + __esModule: true, + addCorsCacheBustingHeaders: addCorsHeadersMock, + cors: corsMock, +}), { virtual: true }); + +jest.mock("@/lib/security/requestGuards", () => ({ + __esModule: true, + applyRateLimit: applyRateLimitMock, + applyBotRateLimit: applyBotRateLimitMock, +}), { virtual: true }); + +jest.mock("@/lib/verifyJwt", () => ({ + __esModule: true, + verifyJwt: verifyJwtMock, + isBotJwt: isBotJwtMock, +}), { virtual: true }); + +jest.mock("@/server/api/root", () => ({ + __esModule: true, + createCaller: createCallerMock, +}), { virtual: true }); + +jest.mock("@/server/db", () => ({ + __esModule: true, + db: {}, +}), { virtual: true }); + +jest.mock("@/lib/auth/botAccess", () => ({ + __esModule: true, + getWalletIdsForBot: getWalletIdsForBotMock, +}), { virtual: true }); + +jest.mock("@/lib/security/rateLimit", () => ({ + __esModule: true, + getClientIP: () => "127.0.0.1", +}), { virtual: true }); + +let handler: (req: NextApiRequest, res: NextApiResponse) => Promise; + +beforeAll(async () => { + ({ default: handler } = await import("../pages/api/v1/walletIds")); +}); + +beforeEach(() => { + jest.clearAllMocks(); + applyRateLimitMock.mockReturnValue(true); + applyBotRateLimitMock.mockReturnValue(true); + corsMock.mockResolvedValue(undefined); + verifyJwtMock.mockReturnValue(makeBotJwtPayload()); + isBotJwtMock.mockReturnValue(true); + createCallerMock.mockReturnValue({ wallet: { getUserWallets: jest.fn() } }); + (getWalletIdsForBotMock as any).mockResolvedValue([{ walletId: "w1", walletName: "Wallet 1" }]); +}); + +describe("walletIds bot API", () => { + it("returns 403 for address mismatch", async () => { + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { address: "addr_test1wrong" }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(res.status).toHaveBeenCalledWith(403); + }); + + it("returns wallet ids for authorized bot", async () => { + const req = { + method: "GET", + headers: makeBearerAuth(), + query: { address: BOT_TEST_ADDRESS }, + } as unknown as NextApiRequest; + const res = createMockResponse(); + await handler(req, res); + expect(getWalletIdsForBotMock).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith([{ walletId: "w1", walletName: "Wallet 1" }]); + }); +}); diff --git a/src/components/common/overall-layout/layout.tsx b/src/components/common/overall-layout/layout.tsx index 2f2da2f8..78dc6e36 100644 --- a/src/components/common/overall-layout/layout.tsx +++ b/src/components/common/overall-layout/layout.tsx @@ -1,7 +1,6 @@ import React, { useEffect, Component, ReactNode, useMemo, useCallback, useState, useRef } from "react"; import { useRouter } from "next/router"; import Link from "next/link"; -import { useNostrChat } from "@jinglescode/nostr-chat-plugin"; import { useWallet, useAddress } from "@meshsdk/react"; import { publicRoutes } from "@/data/public-routes"; import { api } from "@/utils/api"; @@ -156,7 +155,6 @@ export default function RootLayout({ const router = useRouter(); const { appWallet } = useAppWallet(); const { multisigWallet } = useMultisigWallet(); - const { generateNsec } = useNostrChat(); const { isEnabled: isUtxosEnabled } = useUTXOS(); const userAddress = useUserStore((state) => state.userAddress); @@ -229,7 +227,6 @@ export default function RootLayout({ address: variables.address, stakeAddress: variables.stakeAddress, drepKeyHash: variables.drepKeyHash ?? "", - nostrKey: variables.nostrKey, } ); } @@ -361,12 +358,10 @@ export default function RootLayout({ } // Create or update user - const nostrKey = generateNsec(); createUser({ address: walletAddress, stakeAddress, drepKeyHash, - nostrKey: JSON.stringify(nostrKey), }); } catch (error) { if (error instanceof Error && error.message.includes("account changed")) { @@ -374,9 +369,9 @@ export default function RootLayout({ } } } - + initializeWallet(); - }, [connected, activeWallet, user, userAddress, address, createUser, generateNsec]); + }, [connected, activeWallet, user, userAddress, address, createUser]); // Check wallet session and show authorization modal for first-time connections // Check session as soon as wallet is connected and address is available (don't wait for user) diff --git a/src/components/common/overall-layout/menus/multisig-wallet.tsx b/src/components/common/overall-layout/menus/multisig-wallet.tsx index 4a29fdbc..24148ff5 100644 --- a/src/components/common/overall-layout/menus/multisig-wallet.tsx +++ b/src/components/common/overall-layout/menus/multisig-wallet.tsx @@ -3,7 +3,6 @@ import { useRouter } from "next/router"; import MenuLink from "./menu-link"; import usePendingTransactions from "@/hooks/usePendingTransactions"; import { Badge } from "@/components/ui/badge"; -import { ChatBubbleIcon } from "@radix-ui/react-icons"; import usePendingSignables from "@/hooks/usePendingSignables"; import useMultisigWallet from "@/hooks/useMultisigWallet"; @@ -101,15 +100,6 @@ export default function MenuWallet({ walletId, stakingEnabled }: MenuWalletProps Assets - - - Chat - -
+
+
diff --git a/src/components/pages/homepage/wallets/import-wallet-flow/index.tsx b/src/components/pages/homepage/wallets/import-wallet-flow/index.tsx new file mode 100644 index 00000000..94fe6ef0 --- /dev/null +++ b/src/components/pages/homepage/wallets/import-wallet-flow/index.tsx @@ -0,0 +1,50 @@ +/** + * Import Wallet wizard — single-page, three internal steps. + * + * Mirrors the visual shell of new-wallet-flow but skips the NewWallet + * draft round trip: the import sources arrive with a fully-resolved + * wallet config (or, for CBOR paste, enough to reconstruct one), so we + * collect, review, then write straight to Wallet via importWallet. + */ + +import WalletFlowPageLayout from "@/components/pages/homepage/wallets/new-wallet-flow/shared/WalletFlowPageLayout"; +import ProgressIndicator from "@/components/pages/homepage/wallets/new-wallet-flow/shared/ProgressIndicator"; + +import { useWalletImportFlowState } from "./shared/useWalletImportFlowState"; +import SourceStep from "./source"; +import ReviewStep from "./review"; +import ReadyStep from "./ready"; + +const STEPS = [ + { label: "Source", description: "Choose where the wallet comes from" }, + { label: "Review", description: "Confirm signers and policy" }, + { label: "Ready", description: "Wallet appears in your sidebar" }, +] as const; + +export default function PageImportWallet() { + const flow = useWalletImportFlowState(); + const currentStep = flow.step === "source" ? 1 : flow.step === "review" ? 2 : 3; + + return ( +
+
+
+

+ Import Wallet +

+
+
+ +
+
+ {flow.step === "source" && } + {flow.step === "review" && } + {flow.step === "ready" && } +
+
+
+ ); +} + +// Re-export the layout in case future steps want to drop into it directly. +export { WalletFlowPageLayout }; diff --git a/src/components/pages/homepage/wallets/import-wallet-flow/ready/index.tsx b/src/components/pages/homepage/wallets/import-wallet-flow/ready/index.tsx new file mode 100644 index 00000000..48bc0c1b --- /dev/null +++ b/src/components/pages/homepage/wallets/import-wallet-flow/ready/index.tsx @@ -0,0 +1,52 @@ +import Link from "next/link"; +import { CheckCircle2 } from "lucide-react"; + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; + +import type { WalletImportFlowState } from "../shared/useWalletImportFlowState"; + +interface Props { + flow: WalletImportFlowState; +} + +export default function ReadyStep({ flow }: Props) { + const walletId = flow.createdWalletId; + return ( + <> + + + + Wallet imported + + + +
+ +
+

+ Your imported wallet is ready to use. +

+

+ It resolves to the same on-chain address as the source — + balances, transactions, and governance state are derived + from chain on demand. +

+
+
+
+
+ +
+ + {walletId && ( + + )} +
+ + ); +} diff --git a/src/components/pages/homepage/wallets/import-wallet-flow/review/index.tsx b/src/components/pages/homepage/wallets/import-wallet-flow/review/index.tsx new file mode 100644 index 00000000..307e0e86 --- /dev/null +++ b/src/components/pages/homepage/wallets/import-wallet-flow/review/index.tsx @@ -0,0 +1,213 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { getFirstAndLast } from "@/utils/strings"; + +import type { WalletImportFlowState } from "../shared/useWalletImportFlowState"; + +interface Props { + flow: WalletImportFlowState; +} + +export default function ReviewStep({ flow }: Props) { + const { resolvedPayload, cborInput, sourceMeta } = flow; + + const config = resolvedPayload + ? { + name: resolvedPayload.name, + description: resolvedPayload.description, + signersAddresses: resolvedPayload.signersAddresses, + signersStakeKeys: resolvedPayload.signersStakeKeys, + signersDescriptions: resolvedPayload.signersDescriptions, + numRequiredSigners: resolvedPayload.numRequiredSigners, + scriptCbor: resolvedPayload.scriptCbor, + type: resolvedPayload.type, + } + : cborInput + ? { + name: cborInput.name, + description: cborInput.description, + signersAddresses: cborInput.signersAddresses, + signersStakeKeys: cborInput.signersStakeKeys, + signersDescriptions: cborInput.signersDescriptions, + numRequiredSigners: cborInput.numRequiredSigners, + scriptCbor: cborInput.scriptCbor, + type: cborInput.scriptType, + } + : null; + + if (!config || !sourceMeta) { + return ( + + + Nothing to review + + + Start over from the source step. +
+ +
+
+
+ ); + } + + return ( + <> + + + + + Wallet info + + + + + + + + + + + + Signers ({config.signersAddresses.length}) + + + + {config.signersAddresses.map((addr, i) => ( +
+
+ {config.signersDescriptions[i] || `Signer ${i + 1}`} +
+
+ {addr || "—"} +
+ {config.signersStakeKeys[i] && ( +
+ stake: {config.signersStakeKeys[i]} +
+ )} +
+ ))} +
+
+ + + + Script + + +

+ Importing this wallet will create a new local record that + resolves to the same on-chain address as the source. No funds + move and no transaction is signed. +

+

+ scriptCbor: {getFirstAndLast(config.scriptCbor, 24, 24)} +

+
+
+ +
+ + +
+ + ); +} + +function OriginPanel({ + sourceMeta, +}: { + sourceMeta: NonNullable; +}) { + return ( + + + Origin + + + {sourceMeta.source === "instance" && ( + <> + + + + + + )} + {sourceMeta.source === "json" && ( + <> + + + + + )} + {sourceMeta.source === "cbor" && ( + <> + + + + )} + + + ); +} + +function Row({ + label, + value, + mono = false, +}: { + label: string; + value: string; + mono?: boolean; +}) { + // Stack on mobile (label above value) — long stake/script values mangle + // a side-by-side layout below ~480px. Side-by-side returns on sm+. + return ( +
+ + {label} + + + {value} + +
+ ); +} + +function shortenAddr(a: string) { + if (a.length <= 30) return a; + return `${a.slice(0, 16)}…${a.slice(-10)}`; +} diff --git a/src/components/pages/homepage/wallets/import-wallet-flow/shared/useWalletImportFlowState.tsx b/src/components/pages/homepage/wallets/import-wallet-flow/shared/useWalletImportFlowState.tsx new file mode 100644 index 00000000..7588a5a4 --- /dev/null +++ b/src/components/pages/homepage/wallets/import-wallet-flow/shared/useWalletImportFlowState.tsx @@ -0,0 +1,248 @@ +/** + * useWalletImportFlowState + * + * Cross-step state for the import-wallet wizard. The wizard is intentionally + * single-page (source/review/ready as internal steps) because the import + * flow has no NewWallet draft round trip and we want state to survive + * step transitions without serializing megabyte-scale payloads through + * sessionStorage or URL params. + */ + +import { useCallback, useMemo, useState } from "react"; +import { useRouter } from "next/router"; + +import { useToast } from "@/hooks/use-toast"; +import { useUserStore } from "@/lib/zustand/user"; +import { api } from "@/utils/api"; + +export type ImportSource = "summon" | "instance" | "cbor" | "json"; + +export type ImportStep = "source" | "review" | "ready"; + +export type InstanceSourceMeta = { + source: "instance"; + originUrl: string; + originalWalletId: string; + verifiedSigner: string; +}; + +export type JsonSourceMeta = { + source: "json"; + sourceInstance: string; + payloadHash: string; +}; + +export type CborSourceMeta = { + source: "cbor"; + verifiedSigner: string; +}; + +export type SourceMeta = InstanceSourceMeta | JsonSourceMeta | CborSourceMeta; + +export type ResolvedWalletPayload = { + schemaVersion: 1; + id: string; + name: string; + description: string; + signersAddresses: string[]; + signersStakeKeys: string[]; + signersDRepKeys: string[]; + signersDescriptions: string[]; + numRequiredSigners: number | null; + scriptCbor: string; + stakeCredentialHash: string | null; + type: string; + rawImportBodies: unknown; +}; + +export type CborImportInput = { + name: string; + description: string; + signersAddresses: string[]; + signersStakeKeys: string[]; + signersDRepKeys: string[]; + signersDescriptions: string[]; + scriptCbor: string; + numRequiredSigners: number; + scriptType: "all" | "any" | "atLeast"; + stakeCredentialHash?: string | null; +}; + +export interface WalletImportFlowState { + router: ReturnType; + userAddress: string | undefined; + loading: boolean; + step: ImportStep; + createdWalletId: string | null; + + resolvedPayload: ResolvedWalletPayload | null; + cborInput: CborImportInput | null; + sourceMeta: SourceMeta | null; + + setInstanceResult: (payload: ResolvedWalletPayload, meta: InstanceSourceMeta) => void; + setJsonResult: (payload: ResolvedWalletPayload, meta: JsonSourceMeta) => void; + setCborResult: (input: CborImportInput, meta: CborSourceMeta) => void; + backToSource: () => void; + reset: () => void; + + submitImport: () => Promise; +} + +export function useWalletImportFlowState(): WalletImportFlowState { + const router = useRouter(); + const { toast } = useToast(); + const userAddress = useUserStore((s) => s.userAddress); + const [loading, setLoading] = useState(false); + const [step, setStep] = useState("source"); + const [createdWalletId, setCreatedWalletId] = useState(null); + + const [resolvedPayload, setResolvedPayload] = useState(null); + const [cborInput, setCborInput] = useState(null); + const [sourceMeta, setSourceMeta] = useState(null); + + const { mutateAsync: importWallet } = api.wallet.importWallet.useMutation(); + + const setInstanceResult = useCallback( + (payload: ResolvedWalletPayload, meta: InstanceSourceMeta) => { + setResolvedPayload(payload); + setCborInput(null); + setSourceMeta(meta); + setStep("review"); + }, + [], + ); + + const setJsonResult = useCallback( + (payload: ResolvedWalletPayload, meta: JsonSourceMeta) => { + setResolvedPayload(payload); + setCborInput(null); + setSourceMeta(meta); + setStep("review"); + }, + [], + ); + + const setCborResult = useCallback( + (input: CborImportInput, meta: CborSourceMeta) => { + setResolvedPayload(null); + setCborInput(input); + setSourceMeta(meta); + setStep("review"); + }, + [], + ); + + const backToSource = useCallback(() => { + setStep("source"); + }, []); + + const reset = useCallback(() => { + setResolvedPayload(null); + setCborInput(null); + setSourceMeta(null); + setLoading(false); + setCreatedWalletId(null); + setStep("source"); + }, []); + + const submitImport = useCallback(async () => { + if (!sourceMeta) { + toast({ + title: "Nothing to import", + description: "Start over from the source step.", + variant: "destructive", + }); + return; + } + setLoading(true); + try { + let wallet; + if (sourceMeta.source === "instance" && resolvedPayload) { + wallet = await importWallet({ + source: "instance", + originUrl: sourceMeta.originUrl, + originalWalletId: sourceMeta.originalWalletId, + verifiedSigner: sourceMeta.verifiedSigner, + payload: resolvedPayload, + }); + } else if (sourceMeta.source === "json" && resolvedPayload) { + wallet = await importWallet({ + source: "json", + sourceInstance: sourceMeta.sourceInstance, + payload: resolvedPayload, + payloadHash: sourceMeta.payloadHash, + }); + } else if (sourceMeta.source === "cbor" && cborInput) { + wallet = await importWallet({ + source: "cbor", + name: cborInput.name, + description: cborInput.description, + signersAddresses: cborInput.signersAddresses, + signersStakeKeys: cborInput.signersStakeKeys, + signersDRepKeys: cborInput.signersDRepKeys, + signersDescriptions: cborInput.signersDescriptions, + scriptCbor: cborInput.scriptCbor, + numRequiredSigners: cborInput.numRequiredSigners, + scriptType: cborInput.scriptType, + stakeCredentialHash: cborInput.stakeCredentialHash ?? null, + verifiedSigner: sourceMeta.verifiedSigner, + }); + } else { + throw new Error("Inconsistent import state"); + } + toast({ + title: "Wallet imported", + description: "The wallet now appears in your sidebar.", + duration: 3000, + }); + setCreatedWalletId(wallet.id); + setStep("ready"); + } catch (err) { + const message = err instanceof Error ? err.message : "Import failed"; + toast({ + title: "Import failed", + description: message, + variant: "destructive", + }); + } finally { + setLoading(false); + } + }, [sourceMeta, resolvedPayload, cborInput, importWallet, toast]); + + const state = useMemo( + () => ({ + router, + userAddress, + loading, + step, + createdWalletId, + resolvedPayload, + cborInput, + sourceMeta, + setInstanceResult, + setJsonResult, + setCborResult, + backToSource, + reset, + submitImport, + }), + [ + router, + userAddress, + loading, + step, + createdWalletId, + resolvedPayload, + cborInput, + sourceMeta, + setInstanceResult, + setJsonResult, + setCborResult, + backToSource, + reset, + submitImport, + ], + ); + + return state; +} diff --git a/src/components/pages/homepage/wallets/import-wallet-flow/source/cbor-tab.tsx b/src/components/pages/homepage/wallets/import-wallet-flow/source/cbor-tab.tsx new file mode 100644 index 00000000..71e2b7ed --- /dev/null +++ b/src/components/pages/homepage/wallets/import-wallet-flow/source/cbor-tab.tsx @@ -0,0 +1,294 @@ +import { useMemo, useState } from "react"; +import { useWallet } from "@meshsdk/react"; +import { resolveNativeScriptHash } from "@meshsdk/core"; + +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { useToast } from "@/hooks/use-toast"; + +import { + collectSigKeyHashes, + computeRequiredSigners, + decodeNativeScriptFromCbor, + decodedToNativeScript, + detectTypeFromSigParents, + normalizeCborHex, + scriptHashFromCbor, +} from "@/utils/nativeScriptUtils"; +import { tryResolveKeyHash } from "@/utils/addressCompatibility"; +import type { WalletImportFlowState } from "../shared/useWalletImportFlowState"; + +interface Props { + flow: WalletImportFlowState; +} + +/** + * Manual reconstruction tab. + * + * No origin to verify against — instead we sanity-check that the pasted + * CBOR's script hash matches the keys derived from the supplied signer + * list, and require the importer's own stake address to appear so we + * don't accept anonymous garbage rows. + */ +export default function CborTab({ flow }: Props) { + const { wallet, connected } = useWallet(); + const { toast } = useToast(); + + const [name, setName] = useState(""); + const [description, setDescription] = useState(""); + const [scriptCbor, setScriptCbor] = useState(""); + const [signersRaw, setSignersRaw] = useState(""); + const [busy, setBusy] = useState(false); + + const decoded = useMemo(() => { + if (!scriptCbor.trim()) return null; + try { + const dec = decodeNativeScriptFromCbor(scriptCbor); + const sigKeys = collectSigKeyHashes(dec); + return { + type: detectTypeFromSigParents(dec), + required: computeRequiredSigners(dec), + keyHashes: sigKeys, + hash: scriptHashFromCbor(scriptCbor) ?? null, + }; + } catch { + return null; + } + }, [scriptCbor]); + + const signers = useMemo(() => { + return signersRaw + .split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line.length > 0); + }, [signersRaw]); + + const handleContinue = async () => { + if (!name.trim()) { + toast({ title: "Name required", variant: "destructive" }); + return; + } + if (!connected || !wallet) { + toast({ + title: "Connect a wallet first", + description: "We pin imports to the connected signer to keep the table clean.", + variant: "destructive", + }); + return; + } + if (!scriptCbor.trim() || !decoded) { + toast({ + title: "Invalid script CBOR", + description: "We couldn't decode the pasted hex as a native script.", + variant: "destructive", + }); + return; + } + + setBusy(true); + try { + const stakeAddress = await ( + wallet as { getRewardAddresses: () => Promise } + ).getRewardAddresses(); + const verifiedSigner = stakeAddress[0]; + if (!verifiedSigner) { + throw new Error("Wallet did not return a reward (stake) address"); + } + + const resolved = signers + .map((addr) => ({ addr, hash: tryResolveKeyHash(addr) })) + .filter((r) => r.hash !== null) as { + addr: string; + hash: { keyHash: string; type: "payment" | "staking" }; + }[]; + + if (resolved.length < signers.length) { + toast({ + title: "One or more signers couldn't be decoded", + description: "Each line must be a Cardano address or stake address.", + variant: "destructive", + }); + return; + } + + const declaredHashes = new Set( + resolved.map((r) => r.hash.keyHash.toLowerCase()), + ); + const scriptHashes = new Set( + decoded.keyHashes.map((h) => h.toLowerCase()), + ); + const missing = [...scriptHashes].filter((h) => !declaredHashes.has(h)); + if (missing.length > 0) { + toast({ + title: "Script references signers you didn't list", + description: `${missing.length} keyhash(es) in the CBOR are not represented in the signer list.`, + variant: "destructive", + }); + return; + } + + // Re-derive the script hash from the declared signers + policy and + // confirm it matches the pasted CBOR's hash. This catches the case + // where the signer list looks superficially valid but doesn't + // reconstruct the same script. + const sigScripts = resolved.map((r) => ({ + type: "sig" as const, + keyHash: r.hash.keyHash, + })); + const reconstructed = + decoded.type === "atLeast" + ? ({ + type: "atLeast", + required: decoded.required, + scripts: sigScripts, + } as const) + : ({ type: decoded.type, scripts: sigScripts } as const); + const reconstructedHash = resolveNativeScriptHash( + decodedToNativeScript(reconstructed as never), + ).toLowerCase(); + if (decoded.hash && reconstructedHash !== decoded.hash.toLowerCase()) { + toast({ + title: "Signer order doesn't match the script", + description: + "The same keys are present but the script's structure or signer order differs. Use the JSON or instance tab if you can.", + variant: "destructive", + }); + return; + } + + const verifiedKey = tryResolveKeyHash(verifiedSigner); + if ( + !verifiedKey || + !declaredHashes.has(verifiedKey.keyHash.toLowerCase()) + ) { + toast({ + title: "Your wallet isn't in the signer list", + description: + "Add the stake address of your connected wallet to the signers, then try again.", + variant: "destructive", + }); + return; + } + + flow.setCborResult( + { + name: name.trim(), + description: description.trim(), + signersAddresses: resolved.map((r) => r.addr), + signersStakeKeys: resolved.map((r) => + r.hash.type === "staking" ? r.addr : "", + ), + signersDRepKeys: resolved.map(() => ""), + signersDescriptions: resolved.map(() => ""), + scriptCbor: normalizeCborHex(scriptCbor), + numRequiredSigners: + decoded.type === "atLeast" ? decoded.required : resolved.length, + scriptType: decoded.type, + }, + { source: "cbor", verifiedSigner }, + ); + } catch (err) { + const message = err instanceof Error ? err.message : "Validation failed"; + toast({ + title: "Couldn't build wallet", + description: message, + variant: "destructive", + }); + } finally { + setBusy(false); + } + }; + + return ( +
+
+

Reconstruct from native-script CBOR

+

+ Use this when you have the wallet's script CBOR (e.g. from a + chain explorer) and the full signer list, but no origin + instance to verify against. Your connected stake address must + appear in the signer list. +

+
+ +
+ + setName(e.target.value)} + /> +
+
+ + setDescription(e.target.value)} + /> +
+
+ +