diff --git a/.agents/skills/caveman/SKILL.md b/.agents/skills/caveman/SKILL.md new file mode 100644 index 0000000..80cdea3 --- /dev/null +++ b/.agents/skills/caveman/SKILL.md @@ -0,0 +1,84 @@ +--- +name: caveman +description: > + Ultra-compressed communication mode. Cuts output tokens 65% (measured) by speaking like caveman + while keeping full technical accuracy. Supports intensity levels: lite, full (default), ultra, + wenyan-lite, wenyan-full, wenyan-ultra. + Use when user says "caveman mode", "talk like caveman", "use caveman", "less tokens", + "be brief", or invokes /caveman. Also auto-triggers when token efficiency is requested. +--- + +Respond terse like smart caveman. All technical substance stay. Only fluff die. + +## Persistence + +ACTIVE EVERY RESPONSE. No revert after many turns. No filler drift. Still active if unsure. Off only: "stop caveman" / "normal mode". + +Default: **full**. Switch: `/caveman lite|full|ultra`. + +## Rules + +Drop: articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), hedging. Fragments OK. Short synonyms (big not extensive, fix not "implement a solution for"). No tool-call narration, no decorative tables/emoji, no dumping long raw error logs unless asked — quote shortest decisive line. Standard well-known tech acronyms OK (DB/API/HTTP); never invent new abbreviations (cfg/impl/req/res/fn) — tokenizer split them same as full word: zero token saved, reader still decode. Full word cheaper AND clearer. No causal arrows (→) either — own token, save nothing. Technical terms exact. Code blocks unchanged. Errors quoted exact. + +Preserve user's dominant language. User write Portuguese → reply Portuguese caveman. User write Spanish → reply Spanish caveman. Compress the style, not the language. No forced English openings or status phrases. ALWAYS keep technical terms, code, API names, CLI commands, commit-type keywords (feat/fix/...), and exact error strings verbatim — unless user explicitly ask for translation. + +No self-reference. Never name or announce the style. No "caveman mode on", "me caveman think", no third-person caveman tags. Output caveman-only — never normal answer plus "Caveman:" recap. Exception: user explicitly ask what the mode is. + +Pattern: `[thing] [action] [reason]. [next step].` + +Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..." +Yes: "Bug in auth middleware. Token expiry check use `<` not `<=`. Fix:" + +## Intensity + +| Level | What change | +| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **lite** | No filler/hedging. Keep articles + full sentences. Professional but tight | +| **full** | Drop articles, fragments OK, short synonyms. Classic caveman. No tool-call narration, no decorative tables/emoji, no long raw error-log dumps unless asked. Standard acronyms OK; no invented abbreviations | +| **ultra** | Strip conjunctions when cause-then-effect stay unambiguous. One word when one word enough. State each fact once. NO prose abbreviations (cfg/impl/req/res/fn/auth), NO arrows (X → Y) — measured zero token saving under tokenizer, cost decode clarity. Code symbols, function names, API names, error strings: never touch | +| **wenyan-lite** | Semi-classical. Drop filler/hedging but keep grammar structure, classical register | +| **wenyan-full** | Maximum classical terseness. Fully 文言文. 80-90% character reduction. Classical sentence patterns, verbs precede objects, subjects often omitted, classical particles (之/乃/為/其) | +| **wenyan-ultra** | Extreme abbreviation while keeping classical Chinese feel. Maximum compression, ultra terse | + +Example — "Why React component re-render?" + +- lite: "Your component re-renders because you create a new object reference each render. Wrap it in `useMemo`." +- full: "New object ref each render. Inline object prop = new ref = re-render. Wrap in `useMemo`." +- ultra: "Inline obj prop, new ref, re-render. `useMemo`." +- wenyan-lite: "組件頻重繪,以每繪新生對象參照故。以 useMemo 包之。" +- wenyan-full: "每繪新生對象參照,故重繪;以 useMemo 包之則免。" +- wenyan-ultra: "新參照則重繪。useMemo 包之。" + +Example — "Explain database connection pooling." + +- lite: "Connection pooling reuses open connections instead of creating new ones per request. Avoids repeated handshake overhead." +- full: "Pool reuse open DB connections. No new connection per request. Skip handshake overhead." +- ultra: "Pool reuse open DB connections. No per-request handshake." +- wenyan-full: "池蓄已開之連,不逐請而新開,省握手之費。" +- wenyan-ultra: "池蓄連,免逐請新開,省握手。" + +## Auto-Clarity + +Drop caveman when: + +- Security warnings +- Irreversible action confirmations +- Multi-step sequences where fragment order or omitted conjunctions risk misread +- Compression itself creates technical ambiguity (e.g., `"migrate table drop column backup first"` — order unclear without articles/conjunctions) +- User asks to clarify or repeats question + +Resume caveman after clear part done. + +Example — destructive op: + +> **Warning:** This will permanently delete all rows in the `users` table and cannot be undone. +> +> ```sql +> DROP TABLE users; +> ``` +> +> Caveman resume. Verify backup exist first. + +## Boundaries + +Code/commits/PRs: write normal. "stop caveman" or "normal mode": revert. Level persist until changed or session end. diff --git a/.agents/skills/code-review-skill/SKILL.md b/.agents/skills/code-review-skill/SKILL.md new file mode 100644 index 0000000..9906a27 --- /dev/null +++ b/.agents/skills/code-review-skill/SKILL.md @@ -0,0 +1,229 @@ +--- +name: code-review-skill +description: | + Provides comprehensive code review guidance for React 19, Vue 3, Angular 17+, Svelte 5, + Rust, TypeScript, Java, PHP, Python, Django, FastAPI, Go, C#/.NET, Kotlin, Swift, + NestJS, C/C++, Zig, CSS/Less/Sass, Qt, and more. + Covers architecture review, performance review, security audit, code quality anti-patterns, + and common bugs across all ecosystems. + Use when: reviewing pull requests, conducting PR reviews, code review, reviewing code changes, + establishing review standards, mentoring developers, architecture reviews, security audits, + performance reviews, checking code quality, finding bugs, giving feedback on code. +allowed-tools: + - Read + - Grep + - Glob + - Bash # Run lint/test/build commands to verify code quality + - WebFetch # Look up the latest documentation and best practices +--- + +# Code Review Skill + +Transform code reviews from gatekeeping to knowledge sharing through constructive feedback, systematic analysis, and collaborative improvement. + +## When to Use This Skill + +- Reviewing pull requests and code changes +- Establishing code review standards for teams +- Mentoring junior developers through reviews +- Conducting architecture reviews +- Creating review checklists and guidelines +- Improving team collaboration +- Reducing code review cycle time +- Maintaining code quality standards + +## Core Principles + +### 1. The Review Mindset + +**Goals of Code Review:** +- Catch bugs and edge cases +- Ensure code maintainability +- Share knowledge across team +- Enforce coding standards +- Improve design and architecture +- Build team culture + +**Not the Goals:** +- Show off knowledge +- Nitpick formatting (use linters) +- Block progress unnecessarily +- Rewrite to your preference + +### 2. Effective Feedback + +**Good Feedback is:** +- Specific and actionable +- Educational, not judgmental +- Focused on the code, not the person +- Balanced (praise good work too) +- Prioritized (critical vs nice-to-have) + +```markdown +❌ Bad: "This is wrong." +✅ Good: "This could cause a race condition when multiple users + access simultaneously. Consider using a mutex here." + +❌ Bad: "Why didn't you use X pattern?" +✅ Good: "Have you considered the Repository pattern? It would + make this easier to test. Here's an example: [link]" + +❌ Bad: "Rename this variable." +✅ Good: "[nit] Consider `userCount` instead of `uc` for + clarity. Not blocking if you prefer to keep it." +``` + +### 3. Review Scope + +**What to Review:** +- Logic correctness and edge cases +- Security vulnerabilities +- Performance implications +- Test coverage and quality +- Error handling +- Documentation and comments +- API design and naming +- Architectural fit + +**What Not to Review Manually:** +- Code formatting (use Prettier, Black, etc.) +- Import organization +- Linting violations +- Simple typos + +## Review Process + +### Phase 1: Context Gathering (2-3 minutes) + +Before diving into code, understand: +1. Read PR description and linked issue +2. Check PR size (>400 lines? Ask to split) +3. Review CI/CD status (tests passing?) +4. Understand the business requirement +5. Note any relevant architectural decisions + +> For large diffs, pipe the diff through [`scripts/pr-analyzer.py`](scripts/pr-analyzer.py) (`git diff main...HEAD | python scripts/pr-analyzer.py`) to triage complexity and get a suggested review approach before reading. + +### Phase 2: High-Level Review (5-10 minutes) + +1. **Architecture & Design** - Does the solution fit the problem? + - For significant changes, consult [Architecture Review Guide](reference/architecture-review-guide.md) + - Check: SOLID principles, coupling/cohesion, anti-patterns +2. **Performance Assessment** - Are there performance concerns? + - For performance-critical code, consult [Performance Review Guide](reference/performance-review-guide.md) + - Check: Algorithm complexity, N+1 queries, memory usage +3. **File Organization** - Are new files in the right places? +4. **Testing Strategy** - Are there tests covering edge cases? + +### Phase 3: Line-by-Line Review (10-20 minutes) + +For each file, check: +- **Logic & Correctness** - Edge cases, off-by-one, null checks, race conditions +- **Security** - Input validation, injection risks, XSS, sensitive data +- **Performance** - N+1 queries, unnecessary loops, memory leaks +- **Maintainability** - Clear names, single responsibility, comments +- **Reuse** - Before accepting new code, search for existing utilities/helpers that could replace it. Check adjacent files and shared modules for similar patterns. See [Universal Quality Guide](reference/code-quality-universal.md) for anti-patterns like parameter sprawl, leaky abstractions, nested conditionals, stringly-typed code, TOCTOU, and no-op updates. + +### Phase 4: Summary & Decision (2-3 minutes) + +1. Summarize key concerns +2. Highlight what you liked +3. Make clear decision: + - ✅ Approve + - 💬 Comment (minor suggestions) + - 🔄 Request Changes (must address) +4. Offer to pair if complex + +## Review Techniques + +### Technique 1: The Checklist Method + +Use checklists for consistent reviews. See [Security Review Guide](reference/security-review-guide.md) for comprehensive security checklist. + +### Technique 2: The Question Approach + +Instead of stating problems, ask questions: + +```markdown +❌ "This will fail if the list is empty." +✅ "What happens if `items` is an empty array?" + +❌ "You need error handling here." +✅ "How should this behave if the API call fails?" +``` + +### Technique 3: Suggest, Don't Command + +Use collaborative language: + +```markdown +❌ "You must change this to use async/await" +✅ "Suggestion: async/await might make this more readable. What do you think?" + +❌ "Extract this into a function" +✅ "This logic appears in 3 places. Would it make sense to extract it?" +``` + +### Technique 4: Differentiate Severity + +Use labels to indicate priority: + +- 🔴 `[blocking]` - Must fix before merge +- 🟡 `[important]` - Should fix, discuss if disagree +- 🟢 `[nit]` - Nice to have, not blocking +- 💡 `[suggestion]` - Alternative approach to consider +- 📚 `[learning]` - Educational comment, no action needed +- 🎉 `[praise]` - Good work, keep it up! + +**Severity levels:** 🔴 / 🟡 / 🟢 are the three severity tiers used as the standard across all guides in this skill — 🔴 blocks the merge, 🟡 should be addressed, 🟢 is optional. The remaining markers (💡 / 📚 / 🎉) are non-blocking annotations. + +## Language-Specific Guides + +Consult the corresponding detailed guide based on the language being reviewed: + +| Language/Framework | Reference File | Key Topics | +|-------------------|----------------|------------| +| **React** | [React Guide](reference/react.md) | Hooks, useEffect, React 19 Actions, RSC, Suspense, TanStack Query v5 | +| **Vue 3** | [Vue Guide](reference/vue.md) | Composition API, Reactivity System, Props/Emits, Watchers, Composables | +| **Angular 17+** | [Angular Guide](reference/angular.md) | Signals, Standalone, RxJS, Zoneless, Template Optimization, Testing, Route Guards, HttpInterceptor | +| **Rust** | [Rust Guide](reference/rust.md) | Ownership/Borrowing, Unsafe Review, Async Code, Cancellation Safety, Error Handling | +| **TypeScript** | [TypeScript Guide](reference/typescript.md) | Type Safety, async/await, Immutability, Testing, Module Resolution, TS 5.x | +| **Python** | [Python Guide](reference/python.md) | Mutable Default Arguments, Exception Handling, Class Attributes | +| **Django / DRF** | [Django Guide](reference/django.md) | Security Review, N+1 Queries, Serializer Anti-patterns, ViewSet, Async Views | +| **FastAPI** | [FastAPI Guide](reference/fastapi.md) | Depends, Pydantic v2 validation, async correctness, sessions/N+1, auth vs authorization, test-driven verification | +| **Java** | [Java Guide](reference/java.md) | Java 17/21 New Features, Spring Boot 3, Virtual Threads, Stream/Optional | +| **PHP** | [PHP Guide](reference/php.md) | PHP 8.x type system, PDO, security review, Composer, PHPUnit/PHPStan | +| **C# / .NET** | [C# Guide](reference/csharp.md) | C# 12 Features, Async Programming, EF Core Performance, ASP.NET Core, LINQ | +| **Go** | [Go Guide](reference/go.md) | Error Handling, goroutine/channel, context, Interface Design | +| **Kotlin / Android** | [Kotlin Guide](reference/kotlin.md) | Coroutines, Flow, Jetpack Compose, Null Safety, Memory Leaks, Architecture Patterns | +| **Swift / SwiftUI** | [Swift Guide](reference/swift.md) | Optionals, Swift Concurrency, Sendable/actors, SwiftUI property wrappers, value vs reference types, API design | +| **NestJS** | [NestJS Guide](reference/nestjs.md) | Dependency Injection, Layered Architecture, DTO Validation, Guard/Interceptor, Circular Dependencies | +| **Svelte / SvelteKit** | [Svelte Guide](reference/svelte.md) | Runes, Load Functions, Form Actions, Store Migration, SSR/CSR Boundaries | +| **C** | [C Guide](reference/c.md) | Pointers/Buffers, Memory Safety, UB, Secure Coding, Portability, Testing | +| **C++** | [C++ Guide](reference/cpp.md) | RAII, Smart Pointers, C++20/23, constexpr, Testing | +| **Zig** | [Zig Guide](reference/zig.md) | Allocators, error unions, defer/errdefer, comptime, C interop | +| **CSS/Less/Sass** | [CSS Guide](reference/css-less-sass.md) | Variable Conventions, !important, Performance Optimization, Responsive Design, Compatibility | +| **Qt** | [Qt Guide](reference/qt.md) | Object Model, Signals/Slots, Model/View, QML, Qt6 Migration, Testing | + +## Cross-Cutting Guides + +Language-agnostic patterns applicable to all code reviews: + +| Topic | Reference File | Key Topics | +|-------|----------------|------------| +| **Architecture Review** | [Architecture Review Guide](reference/architecture-review-guide.md) | SOLID, anti-patterns, coupling/cohesion, dependency direction | +| **Performance Review** | [Performance Review Guide](reference/performance-review-guide.md) | Web Vitals, N+1, algorithm complexity, memory leaks, caching | +| **Security Review** | [Security Review Guide](reference/security-review-guide.md) | SQLi, XSS, CSRF, SSRF, IDOR, Command Injection, Cross-language Examples | +| **Universal Quality** | [Universal Quality Guide](reference/code-quality-universal.md) | Reuse audit, parameter sprawl, leaky abstractions, nested conditionals, stringly-typed code, TOCTOU, no-op updates, redundant state | +| **Common Bugs** | [Common Bugs Checklist](reference/common-bugs-checklist.md) | Language-specific bug patterns, common pitfalls | +| **SQL Injection Prevention** | [SQL Injection Guide](reference/cross-cutting/sql-injection-prevention.md) | Parameterized queries, ORM safety, 6 languages, dynamic identifiers, detection | +| **XSS Prevention** | [XSS Prevention Guide](reference/cross-cutting/xss-prevention.md) | Output encoding, CSP, 5 frameworks, input validation vs encoding, detection | +| **N+1 Queries** | [N+1 Queries Guide](reference/cross-cutting/n-plus-one-queries.md) | Eager loading, batch fetching, DataLoader, 5 languages, detection | +| **Error Handling** | [Error Handling Guide](reference/cross-cutting/error-handling-principles.md) | Fail fast, error hierarchy, 7 languages, anti-patterns, logging | +| **Async & Concurrency** | [Concurrency Guide](reference/cross-cutting/async-concurrency-patterns.md) | Goroutines, async/await, actors, structured concurrency, 7 languages | +| **Review Best Practices** | [Code Review Best Practices](reference/code-review-best-practices.md) | Communication, reviewer mindset, giving feedback, severity labels | + +## Additional Resources + +- [PR Review Template](assets/pr-review-template.md) - PR review comment template +- [Review Checklist](assets/review-checklist.md) - Quick reference checklist diff --git a/.agents/skills/code-review-skill/assets/pr-review-template.md b/.agents/skills/code-review-skill/assets/pr-review-template.md new file mode 100644 index 0000000..9efd227 --- /dev/null +++ b/.agents/skills/code-review-skill/assets/pr-review-template.md @@ -0,0 +1,137 @@ +# PR Review Template + +Copy and use this template for your code reviews. + +--- + +## Summary + +[Brief overview of what was reviewed - 1-2 sentences] + +**PR Size:** [Small/Medium/Large] (~X lines) +**Review Time:** [X minutes] + +## Strengths + +- [What was done well] +- [Good patterns or approaches used] +- [Improvements from previous code] + +## Architecture & Performance + +**Architecture Assessment** +- [ ] Separation of concerns — are responsibilities clearly divided? +- [ ] Module responsibilities — does each module have a single purpose? +- [ ] Dependency direction — do dependencies flow toward stability? +- [ ] Consistent with existing patterns and conventions + +> See [Architecture Review Guide](../reference/architecture-review-guide.md) for detailed SOLID, anti-pattern, and coupling analysis. + +**Performance Assessment** +- [ ] Algorithm complexity — any O(n²) or worse on large inputs? +- [ ] Memory impact — large allocations, leaks, unbounded growth? +- [ ] I/O impact — excessive API calls, unbatched writes, missing caching? +- [ ] Database queries — N+1 risks, missing indexes, unoptimized joins? + +> See [Performance Review Guide](../reference/performance-review-guide.md) for comprehensive Web Vitals, N+1, and caching guidance. + +## Required Changes + +🔴 **[blocking]** [Issue description] +> [Code location or example] +> [Suggested fix or explanation] + +🔴 **[blocking]** [Issue description] +> [Details] + +## Important Suggestions + +🟡 **[important]** [Issue description] +> [Why this matters] +> [Suggested approach] + +## Minor Suggestions + +🟢 **[nit]** [Minor improvement suggestion] + +💡 **[suggestion]** [Alternative approach to consider] + +## Learning Notes + +📚 [Educational context worth sharing about X] + +📚 [Background behind design decision Y] + +## Security Considerations + +- [ ] No hardcoded secrets +- [ ] Input validation present +- [ ] Authorization checks in place +- [ ] No SQL/XSS injection risks +- [ ] CSRF protection for state-changing operations +- [ ] Sensitive data not leaked in logs/errors +- [ ] Dependency vulnerabilities checked (npm audit / pip audit / cargo audit) + +> See [Security Review Guide](../reference/security-review-guide.md) for comprehensive injection, XSS, CSRF, secrets, and auth checklist. + +## Test Coverage + +- [ ] Unit tests added/updated +- [ ] Edge cases covered +- [ ] Error cases tested + +## Verdict + +**[ ] ✅ Approve** - Ready to merge +**[ ] 💬 Comment** - Minor suggestions, can merge +**[ ] 🔄 Request Changes** - Must address blocking issues + +--- + +## Quick Copy Templates + +### Blocking Issue +``` +🔴 **[blocking]** [Title] + +[Description of the issue] + +**Location:** `file.ts:123` + +**Suggested fix:** +\`\`\`typescript +// Your suggested code +\`\`\` +``` + +### Important Suggestion +``` +🟡 **[important]** [Title] + +[Why this is important] + +**Consider:** +- Option A: [description] +- Option B: [description] +``` + +### Minor Suggestion +``` +🟢 **[nit]** [Suggestion] + +Not blocking, but consider [improvement]. +``` + +### Praise +``` +🎉 **[praise]** Great work on [specific thing]! + +[Why this is good] +``` + +### Learning +``` +📚 **[learning]** [Educational note] + +For context, [X] works this way because [Y]. No action needed — just sharing. +``` diff --git a/.agents/skills/code-review-skill/assets/review-checklist.md b/.agents/skills/code-review-skill/assets/review-checklist.md new file mode 100644 index 0000000..c796333 --- /dev/null +++ b/.agents/skills/code-review-skill/assets/review-checklist.md @@ -0,0 +1,123 @@ +# Code Review Quick Checklist + +Quick reference checklist for code reviews. + +## Pre-Review (2 min) + +- [ ] Read PR description and linked issue +- [ ] Check PR size (<400 lines ideal) +- [ ] Verify CI/CD status (tests passing?) +- [ ] Understand the business requirement + +## Architecture & Design (5 min) + +- [ ] Solution fits the problem +- [ ] Consistent with existing patterns +- [ ] No simpler approach exists +- [ ] Will it scale? +- [ ] Changes in right location + +## Logic & Correctness (10 min) + +- [ ] Edge cases handled +- [ ] Null/undefined checks present +- [ ] Off-by-one errors checked +- [ ] Race conditions considered +- [ ] Error handling complete +- [ ] Correct data types used + +## Security (5 min) + +- [ ] No hardcoded secrets +- [ ] Input validated/sanitized +- [ ] SQL injection prevented +- [ ] XSS prevented +- [ ] Authorization checks present +- [ ] Sensitive data protected + +## Performance (3 min) + +- [ ] No N+1 queries +- [ ] Expensive operations optimized +- [ ] Large lists paginated +- [ ] No memory leaks +- [ ] Caching considered where appropriate + +## Testing (5 min) + +- [ ] Tests exist for new code +- [ ] Edge cases tested +- [ ] Error cases tested +- [ ] Tests are readable +- [ ] Tests are deterministic + +## Code Quality (3 min) + +- [ ] Clear variable/function names +- [ ] No code duplication +- [ ] Functions do one thing +- [ ] Complex code commented +- [ ] No magic numbers + +## Documentation (2 min) + +- [ ] Public APIs documented +- [ ] README updated if needed +- [ ] Breaking changes noted +- [ ] Complex logic explained + +--- + +## Severity Labels + +| Label | Meaning | Action | +|-------|---------|--------| +| 🔴 `[blocking]` | Must fix | Block merge | +| 🟡 `[important]` | Should fix | Discuss if disagree | +| 🟢 `[nit]` | Nice to have | Non-blocking | +| 💡 `[suggestion]` | Alternative | Consider | +| 📚 `[learning]` | Educational comment | No action needed | +| 🎉 `[praise]` | Good work | Celebrate! | + +--- + +## Decision Matrix + +| Situation | Decision | +|-----------|----------| +| Critical security issue | 🔴 Block, fix immediately | +| Breaking change without migration | 🔴 Block | +| Missing error handling | 🟡 Should fix | +| No tests for new code | 🟡 Should fix | +| Style preference | 🟢 Non-blocking | +| Minor naming improvement | 🟢 Non-blocking | +| Clever but working code | 💡 Suggest simpler | + +--- + +## Time Budget + +This checklist is designed for a **lightweight quick review**. For comprehensive reviews covering architecture and performance analysis, use the full four-phase process in [SKILL.md](../SKILL.md) (19–36 minutes). Smaller PRs trend toward the lower end of each phase; larger PRs toward the upper end. + +| PR Size | Quick Review | Full Review (4-phase) | +|---------|-------------|----------------------| +| < 100 lines | 10–15 min | ~19–28 min | +| 100–400 lines | 20–40 min | ~28–36 min | +| > 400 lines | Ask to split | Ask to split | + +--- + +## Red Flags + +Watch for these patterns: + +- `// TODO` in production code +- `console.log` left in code +- Commented out code +- `any` type in TypeScript +- Empty catch blocks +- `unwrap()` in Rust production code +- Magic numbers/strings +- Copy-pasted code blocks +- Missing null checks +- Hardcoded URLs/credentials diff --git a/.agents/skills/code-review-skill/reference/architecture-review-guide.md b/.agents/skills/code-review-skill/reference/architecture-review-guide.md new file mode 100644 index 0000000..799fd32 --- /dev/null +++ b/.agents/skills/code-review-skill/reference/architecture-review-guide.md @@ -0,0 +1,498 @@ +# Architecture Review Guide + +Architecture design review guide to help evaluate whether code architecture is sound and design is appropriate. + +## SOLID Principles Checklist + +### S - Single Responsibility Principle (SRP) + +**Key checks:** + +- Does this class/module have only one reason to change? +- Do all methods in the class serve the same purpose? +- If you had to describe this class to a non-technical person, could you do it in one sentence? + +**Identification signals in code review:** + +``` +⚠️ Class name contains "And", "Manager", "Handler", "Processor" or other generic words +⚠️ A class exceeds 200-300 lines of code +⚠️ Class has more than 5-7 public methods +⚠️ Different methods operate on completely different data +``` + +**Review questions:** + +- "What responsibilities does this class have? Can it be split?" +- "If requirement X changes, which methods need to change? What about Y?" + +### O - Open/Closed Principle (OCP) + +**Key checks:** + +- Does adding new features require modifying existing code? +- Can new behavior be added through extension (inheritance, composition)? +- Are there large if/else or switch statements for handling different types? + +**Identification signals in code review:** + +``` +⚠️ switch/if-else chains handling different types +⚠️ Adding new features requires modifying core classes +⚠️ Type checks (instanceof, typeof) scattered throughout code +``` + +**Review questions:** + +- "To add a new type X, which files need to be modified?" +- "Will this switch statement grow as new types are added?" + +### L - Liskov Substitution Principle (LSP) + +**Key checks:** + +- Can subclasses fully replace parent classes? +- Do subclasses change the expected behavior of parent class methods? +- Do subclasses throw exceptions not declared by the parent class? + +**Identification signals in code review:** + +``` +⚠️ Explicit type casting +⚠️ Subclass methods throw NotImplementedException +⚠️ Subclass methods are empty or only return +⚠️ Code using base class needs to check specific types +``` + +**Review questions:** + +- "If a subclass replaces the parent class, does the caller code need to change?" +- "Does this method's behavior in the subclass conform to the parent class contract?" + +### I - Interface Segregation Principle (ISP) + +**Key checks:** + +- Are interfaces small and focused enough? +- Are implementing classes forced to implement methods they don't need? +- Do clients depend on methods they don't use? + +**Identification signals in code review:** + +``` +⚠️ Interface has more than 5-7 methods +⚠️ Implementing classes have empty methods or throw NotImplementedException +⚠️ Interface names are too generic (IManager, IService) +⚠️ Different clients only use parts of the interface +``` + +**Review questions:** + +- "Are all methods of this interface used by every implementing class?" +- "Can this large interface be split into smaller, specialized interfaces?" + +### D - Dependency Inversion Principle (DIP) + +**Key checks:** + +- Do high-level modules depend on abstractions rather than concrete implementations? +- Is dependency injection used instead of direct `new` object creation? +- Are abstractions defined by high-level modules rather than low-level modules? + +**Identification signals in code review:** + +``` +⚠️ High-level modules directly `new` low-level module concrete classes +⚠️ Importing concrete implementation classes instead of interfaces/abstract classes +⚠️ Configuration and connection strings hardcoded in business logic +⚠️ Hard to write unit tests for a class +``` + +**Review questions:** + +- "Can this class's dependencies be mocked in tests?" +- "If you need to switch the database/API implementation, how many places need changes?" + +--- + +## Architecture Anti-Pattern Identification + +### Fatal Anti-Patterns + +| Anti-Pattern | Identification Signal | Impact | +| ------------------- | ------------------------------------------------------------------------------ | ------------------------------------- | +| **Big Ball of Mud** | No clear module boundaries, any code can call any other code | Hard to understand, modify, and test | +| **God Object** | Single class takes on too many responsibilities, knows too much, does too much | High coupling, hard to reuse and test | +| **Spaghetti Code** | Chaotic control flow, goto or deep nesting, hard to trace execution path | Hard to understand and maintain | +| **Lava Flow** | Old code nobody dares to touch, lacks documentation and tests | Technical debt accumulation | + +### Design Anti-Patterns + +| Anti-Pattern | Identification Signal | Suggestion | +| ---------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------- | +| **Golden Hammer** | Using the same technology/pattern for all problems | Choose appropriate solutions based on the problem | +| **Gas Factory (Over-engineering)** | Simple problems solved with complex solutions, abusing design patterns | YAGNI principle, simple first then complex | +| **Boat Anchor** | Unused code written for "might need it in the future" | Delete unused code, write it when needed | +| **Copy-Paste Programming** | Same logic appears in multiple places | Extract common methods or modules | + +### Review Questions + +```markdown +🔴 [blocking] "This class has 2000 lines of code, consider splitting into multiple focused classes" +🟡 [important] "This logic is duplicated in 3 places, consider extracting a common method?" +💡 [suggestion] "This switch statement could be replaced with the strategy pattern for easier extension" +``` + +--- + +## Coupling and Cohesion Assessment + +### Coupling Types (from good to bad) + +| Type | Description | Example | +| ----------------------- | ---------------------------------------------- | -------------------------------------------------------- | +| **Message Coupling** ✅ | Pass data through parameters | `calculate(price, quantity)` | +| **Data Coupling** ✅ | Share simple data structures | `processOrder(orderDTO)` | +| **Stamp Coupling** ⚠️ | Share complex data structure but use only part | Pass entire User object but only use name | +| **Control Coupling** ⚠️ | Pass control flags affecting behavior | `process(data, isAdmin=true)` | +| **Common Coupling** ❌ | Share global variables | Multiple modules read/write the same global state | +| **Content Coupling** ❌ | Directly access another module's internals | Directly manipulating another class's private attributes | + +### Cohesion Types (from good to bad) + +| Type | Description | Quality | +| ---------------------------- | -------------------------------------------- | ------------- | +| **Functional Cohesion** | All elements perform a single task | ✅ Best | +| **Sequential Cohesion** | Output serves as input for next step | ✅ Good | +| **Communicational Cohesion** | Operate on same data | ⚠️ Acceptable | +| **Temporal Cohesion** | Tasks executed at the same time | ⚠️ Poor | +| **Logical Cohesion** | Logically related but functionally different | ❌ Bad | +| **Coincidental Cohesion** | No obvious relationship | ❌ Worst | + +### Metric Reference + +```yaml +Coupling Metrics: + CBO (Coupling Between Objects): + Good: < 5 + Warning: 5-10 + Dangerous: > 10 + + Ce (Efferent Coupling): + Description: How many external classes it depends on + Good: < 7 + + Ca (Afferent Coupling): + Description: How many classes depend on it + High value means: Changes have wide impact, needs to be stable + +Cohesion Metrics: + LCOM4 (Lack of Cohesion in Methods): + 1: Single responsibility ✅ + 2-3: May need splitting ⚠️ + >3: Should be split ❌ +``` + +### Review Questions + +- "How many other modules does this module depend on? Can it be reduced?" +- "How many other places are affected by modifying this class?" +- "Do all methods of this class operate on the same data?" + +--- + +## Layered Architecture Review + +### Clean Architecture Layer Check + +``` +┌─────────────────────────────────────┐ +│ Frameworks & Drivers │ ← Outermost: Web, DB, UI +├─────────────────────────────────────┤ +│ Interface Adapters │ ← Controllers, Gateways, Presenters +├─────────────────────────────────────┤ +│ Application Layer │ ← Use Cases, Application Services +├─────────────────────────────────────┤ +│ Domain Layer │ ← Entities, Domain Services +└─────────────────────────────────────┘ + ↑ Dependencies can only point inward ↑ +``` + +### Dependency Rule Check + +**Core rule: Source code dependencies can only point inward** + +```typescript +// ❌ Violates dependency rule: Domain layer depends on Infrastructure +// domain/User.ts +import { MySQLConnection } from '../infrastructure/database' + +// ✅ Correct: Domain layer defines interface, Infrastructure implements +// domain/UserRepository.ts (interface) +interface UserRepository { + findById(id: string): Promise +} + +// infrastructure/MySQLUserRepository.ts (implementation) +class MySQLUserRepository implements UserRepository { + findById(id: string): Promise { + /* ... */ + } +} +``` + +### Review Checklist + +**Layer boundary checks:** + +- [ ] Does the Domain layer have external dependencies (database, HTTP, file system)? +- [ ] Does the Application layer directly operate the database or call external APIs? +- [ ] Does the Controller contain business logic? +- [ ] Are there cross-layer calls (UI directly calling Repository)? + +**Separation of concerns checks:** + +- [ ] Is business logic separated from presentation logic? +- [ ] Is data access encapsulated in a dedicated layer? +- [ ] Are configuration and environment-related code centrally managed? + +### Review Questions + +```markdown +🔴 [blocking] "Domain entity directly imports database connection, violating dependency rule" +🟡 [important] "Controller contains business calculation logic, suggest moving to Service layer" +💡 [suggestion] "Consider using dependency injection to decouple these components" +``` + +--- + +## Design Pattern Usage Evaluation + +### When to Use Design Patterns + +| Pattern | Suitable Scenario | Unsuitable Scenario | +| ------------- | ------------------------------------------------------------------------ | --------------------------------------------------------- | +| **Factory** | Need to create different types of objects, type determined at runtime | Only one type, or type is fixed | +| **Strategy** | Algorithm needs to switch at runtime, multiple interchangeable behaviors | Only one algorithm, or algorithm won't change | +| **Observer** | One-to-many dependency, state changes need to notify multiple objects | Simple direct calls suffice | +| **Singleton** | Genuinely need a globally unique instance, like config management | Objects that can be passed via dependency injection | +| **Decorator** | Need to dynamically add responsibilities, avoid inheritance explosion | Responsibilities are fixed, no dynamic composition needed | + +### Over-engineering Warning Signs + +``` +⚠️ Patternitis identification signals: + +1. Simple if/else replaced with strategy pattern + factory + registry +2. Interface with only one implementation +3. Abstraction layers added for "might need it in the future" +4. Code line count increases significantly due to pattern application +5. Newcomers need a long time to understand the code structure +``` + +### Review Principles + +```markdown +✅ Correct pattern usage: + +- Solves a real extensibility problem +- Code is easier to understand and test +- Adding new features becomes simpler + +❌ Overuse of patterns: + +- Using patterns for the sake of using patterns +- Adds unnecessary complexity +- Violates YAGNI principle +``` + +### Review Questions + +- "What specific problem does using this pattern solve?" +- "What problems would the code have without this pattern?" +- "Is the value of this abstraction layer greater than its complexity?" + +--- + +## Scalability Assessment + +### Scalability Checklist + +**Functional scalability:** + +- [ ] Does adding new features require modifying core code? +- [ ] Are extension points provided (hooks, plugins, events)? +- [ ] Is configuration externalized (config files, environment variables)? + +**Data scalability:** + +- [ ] Does the data model support adding new fields? +- [ ] Are data volume growth scenarios considered? +- [ ] Do queries have appropriate indexes? + +**Load scalability:** + +- [ ] Can it scale horizontally (add more instances)? +- [ ] Are there state dependencies (session, local cache)? +- [ ] Are database connections using a connection pool? + +### Extension Point Design Check + +```typescript +// ✅ Good extension design: using events/hooks +class OrderService { + private hooks: OrderHooks + + async createOrder(order: Order) { + await this.hooks.beforeCreate?.(order) + const result = await this.save(order) + await this.hooks.afterCreate?.(result) + return result + } +} + +// ❌ Poor extension design: hardcoding all behavior +class OrderService { + async createOrder(order: Order) { + await this.sendEmail(order) // hardcoded + await this.updateInventory(order) // hardcoded + await this.notifyWarehouse(order) // hardcoded + return await this.save(order) + } +} +``` + +### Review Questions + +```markdown +💡 [suggestion] "If new payment methods need to be supported in the future, is this design easy to extend?" +🟡 [important] "This logic is hardcoded, consider using configuration or strategy pattern?" +📚 [learning] "Event-driven architecture can make this feature easier to extend" +``` + +--- + +## Code Structure Best Practices + +### Directory Organization + +**Organize by feature/domain (recommended):** + +``` +src/ +├── user/ +│ ├── User.ts (entity) +│ ├── UserService.ts (service) +│ ├── UserRepository.ts (data access) +│ └── UserController.ts (API) +├── order/ +│ ├── Order.ts +│ ├── OrderService.ts +│ └── ... +└── shared/ + ├── utils/ + └── types/ +``` + +**Organize by technical layer (not recommended):** + +``` +src/ +├── controllers/ ← Different domains mixed together +│ ├── UserController.ts +│ └── OrderController.ts +├── services/ +├── repositories/ +└── models/ +``` + +### Naming Convention Check + +| Type | Convention | Example | +| ------------------ | ------------------------- | -------------------------------- | +| Class name | PascalCase, noun | `UserService`, `OrderRepository` | +| Method name | camelCase, verb | `createUser`, `findOrderById` | +| Interface name | I prefix or no prefix | `IUserService` or `UserService` | +| Constants | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT` | +| Private attributes | Underscore prefix or none | `_cache` or `#cache` | + +### File Size Guidelines + +```yaml +Recommended limits: + Single file: < 300 lines + Single function: < 50 lines + Single class: < 200 lines + Function parameters: < 4 + Nesting depth: < 4 levels + +When exceeding limits: + - Consider splitting into smaller units + - Use composition over inheritance + - Extract helper functions or classes +``` + +### Review Questions + +```markdown +🟢 [nit] "This 500-line file could be split by responsibility" +🟡 [important] "Recommend organizing directory structure by feature domain rather than technical layer" +💡 [suggestion] "Function name `process` is not clear enough, consider `calculateOrderTotal`?" +``` + +--- + +## Quick Reference Checklist + +### 5-Minute Architecture Review + +```markdown +□ Are dependency directions correct? (outer depends on inner) +□ Are there circular dependencies? +□ Is core business logic decoupled from framework/UI/database? +□ Are SOLID principles followed? +□ Are there obvious anti-patterns? +``` + +### Red Flags (Must Address) + +```markdown +🔴 God Object - single class exceeds 1000 lines +🔴 Circular dependency - A → B → C → A +🔴 Domain layer contains framework dependencies +🔴 Hardcoded configuration and secrets +🔴 External service calls without interfaces +``` + +### Yellow Flags (Should Address) + +```markdown +🟡 Coupling Between Objects (CBO) > 10 +🟡 Method parameters exceed 5 +🟡 Nesting depth exceeds 4 levels +🟡 Duplicate code blocks > 10 lines +🟡 Interface with only one implementation +``` + +--- + +## Tool Recommendations + +| Tool | Purpose | Language Support | +| ------------- | --------------------------------------- | --------------------- | +| **SonarQube** | Code quality, coupling analysis | Multi-language | +| **NDepend** | Dependency analysis, architecture rules | .NET | +| **JDepend** | Package dependency analysis | Java | +| **Madge** | Module dependency graph | JavaScript/TypeScript | +| **ESLint** | Code standards, complexity checks | JavaScript/TypeScript | +| **CodeScene** | Technical debt, hotspot analysis | Multi-language | + +--- + +## Reference Resources + +- [Clean Architecture - Uncle Bob](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) +- [SOLID Principles in Code Review - JetBrains](https://blog.jetbrains.com/upsource/2015/08/31/what-to-look-for-in-a-code-review-solid-principles-2/) +- [Software Architecture Anti-Patterns](https://medium.com/@christophnissle/anti-patterns-in-software-architecture-3c8970c9c4f5) +- [Coupling and Cohesion in System Design](https://www.geeksforgeeks.org/system-design/coupling-and-cohesion-in-system-design/) +- [Design Patterns - Refactoring Guru](https://refactoring.guru/design-patterns) diff --git a/.agents/skills/code-review-skill/reference/code-quality-universal.md b/.agents/skills/code-review-skill/reference/code-quality-universal.md new file mode 100644 index 0000000..4e69c9c --- /dev/null +++ b/.agents/skills/code-review-skill/reference/code-quality-universal.md @@ -0,0 +1,505 @@ +# Universal Code Quality Anti-Patterns + +> Language-agnostic code quality anti-pattern guide, covering code reuse, abstraction leaks, parameter bloat, nested conditionals, stringly typing, TOCTOU, no-op updates, and other core topics. Applicable to PR reviews across all languages. + +## Table of Contents + +- [Code Reuse Review](#code-reuse-review) +- [Parameter Bloat](#parameter-bloat) +- [Abstraction Leaks](#abstraction-leaks) +- [Stringly Typing](#stringly-typing) +- [Nested Conditional Expressions](#nested-conditional-expressions) +- [Copy-Paste Variants](#copy-paste-variants) +- [No-Op Updates](#no-op-updates) +- [TOCTOU Race Conditions](#toctou-race-conditions) +- [Overly Broad Operations](#overly-broad-operations) +- [Redundant State](#redundant-state) +- [Universal Quality Checklist](#universal-quality-checklist) + +--- + +## Code Reuse Review + +Before accepting new code, search the existing codebase for reusable utilities. + +### Search for Existing Utility Functions + +```python +# ❌ Newly written path joining logic — project already has PathBuilder +def get_config_path(name): + base = os.environ.get("APP_ROOT", ".") + return os.path.join(base, "config", name + ".json") + +# ✅ Use existing PathBuilder +def get_config_path(name): + return PathBuilder.config(f"{name}.json") +``` + +```javascript +// ❌ Hand-written debounce — project already has lodash or utils/debounce.ts +function debounce(fn, ms) { + let timer + return (...args) => { + clearTimeout(timer) + timer = setTimeout(() => fn(...args), ms) + } +} + +// ✅ Use existing utility function +import { debounce } from '@/utils/debounce' +``` + +**Review points:** + +- Does the new function overlap in name or functionality with existing utilities? +- Can inline logic be extracted as a call to an existing module? +- Check adjacent files and shared/utils directories + +--- + +## Parameter Bloat + +### Growing Function Parameters + +```python +# ❌ Adding a parameter for every new requirement +def create_user(name, email, role, team, active, avatar_url, timezone): + ... + +# ✅ Use config object / dataclass +@dataclass +class CreateUserParams: + name: str + email: str + role: Role = Role.MEMBER + team: str | None = None + active: bool = True + avatar_url: str | None = None + timezone: str = "UTC" + +def create_user(params: CreateUserParams) -> User: + ... +``` + +```typescript +// ❌ 6+ positional parameters +function renderWidget( + title: string, width: number, height: number, + theme: string, collapsible: boolean, icon: string +) { ... } + +// ✅ Options object pattern +interface WidgetOptions { + title: string; + width?: number; + height?: number; + theme?: "light" | "dark"; + collapsible?: boolean; + icon?: string; +} +function renderWidget(options: WidgetOptions) { ... } +``` + +**Review points:** + +- Does the function have ≥ 4 parameters? Consider options object / dataclass +- Is the new parameter just a boolean flag? Consider enum or strategy pattern +- Are there mutually exclusive parameters like `enable_x`, `disable_y`? + +--- + +## Abstraction Leaks + +### Exposing Internal Implementation Details + +```python +# ❌ Returning internal ORM object — caller is forced to know SQLAlchemy +def get_users(): + return session.query(User).filter(User.active == True).all() + +# ✅ Return domain object, hide persistence layer +def get_active_users() -> list[UserDTO]: + rows = user_repo.find_active() + return [UserDTO.from_row(r) for r in rows] +``` + +```typescript +// ❌ Component receives raw API response structure + + +// ✅ Component receives domain type, adapter handles mapping +interface UserSummary { + displayName: string; + avatarUrl: string; +} + +``` + +**Review points:** + +- Does the return type leak the underlying implementation (ORM, HTTP client, file format)? +- Do components/functions depend on external system data structures? +- Are existing abstraction boundaries being broken? + +--- + +## Stringly Typing + +### Using Raw Strings Instead of Constants/Enums + +```python +# ❌ Magic strings scattered everywhere +if status == "active": + ... +if role == "admin": + ... + +# ✅ Use enum +class Status(StrEnum): + ACTIVE = "active" + SUSPENDED = "suspended" + ARCHIVED = "archived" + +if user.status == Status.ACTIVE: + ... +``` + +```typescript +// ❌ Raw string event names — typos won't be caught +emitter.emit('userCreated', data) +emitter.on('usercreated', handler) // bug: typo + +// ✅ Constants or branded type +const Events = { + USER_CREATED: 'userCreated', + USER_SUSPENDED: 'userSuspended', +} as const +emitter.emit(Events.USER_CREATED, data) +``` + +**Review points:** + +- Are strings used instead of existing enum/union types? +- Are event names, action types, status values scattered across multiple files? +- Is string comparison case-sensitive but unvalidated? + +--- + +## Nested Conditional Expressions + +### Ternary Chains and Nested if/else + +```python +# ❌ Ternary chain is hard to read +label = ( + "Admin" if role == "admin" else + "Manager" if role == "manager" else + "Viewer" if role == "viewer" else + "Unknown" +) + +# ✅ Lookup table or match +ROLE_LABELS = { + "admin": "Admin", + "manager": "Manager", + "viewer": "Viewer", +} +label = ROLE_LABELS.get(role, "Unknown") +``` + +```typescript +// ❌ Nested ternary +const bg = isHovered + ? isSelected + ? 'blue' + : 'gray' + : isSelected + ? 'navy' + : 'white' + +// ✅ Lookup map +const bgMap: Record = { + 'true-true': 'blue', + 'true-false': 'gray', + 'false-true': 'navy', + 'false-false': 'white', +} +const bg = bgMap[`${isHovered}-${isSelected}`] +``` + +```python +# ❌ Nested if 3+ levels +def process(order): + if order is not None: + if order.items: + for item in order.items: + if item.price > 0: + ... + +# ✅ Early return + guard clauses +def process(order): + if not order or not order.items: + return + for item in order.items: + if item.price <= 0: + continue + ... +``` + +**Review points:** + +- Are ternary expressions nested ≥ 2 levels? +- Is if/else nesting ≥ 3 levels? +- Can it be replaced with a lookup table, early return, or match? + +--- + +## Copy-Paste Variants + +### Near-Duplicate Code Blocks + +```python +# ❌ Two functions nearly identical, only field names differ +def format_user(user): + return f"{user.first_name} {user.last_name} ({user.email})" + +def format_employee(emp): + return f"{emp.first_name} {emp.last_name} ({emp.work_email})" + +# ✅ Unified abstraction +def format_person(first: str, last: str, email: str) -> str: + return f"{first} {last} ({email})" +``` + +```typescript +// ❌ Copy-paste handler only changed URL +async function deletePost(id: string) { + await fetch(`/api/posts/${id}`, { method: 'DELETE' }) + router.push('/posts') +} +async function deleteComment(id: string) { + await fetch(`/api/comments/${id}`, { method: 'DELETE' }) + router.push('/comments') +} + +// ✅ Parameterized +async function deleteResource(resource: string, id: string) { + await fetch(`/api/${resource}/${id}`, { method: 'DELETE' }) + router.push(`/${resource}`) +} +``` + +**Review points:** + +- Are there ≥ 2 code blocks that differ only in variable names/URLs/strings? +- Can a parameterized shared function be extracted? +- Can template method or strategy eliminate the variants? + +--- + +## No-Op Updates + +### Unconditionally Triggering State Updates + +```typescript +// ❌ Every poll triggers update — even when data hasn't changed +useEffect(() => { + const interval = setInterval(() => { + fetch('/api/status') + .then((r) => r.json()) + .then(setStatus) + }, 5000) + return () => clearInterval(interval) +}, []) + +// ✅ Only update when value changes +useEffect(() => { + const interval = setInterval(() => { + fetch('/api/status') + .then((r) => r.json()) + .then((data) => { + setStatus((prev) => (isEqual(prev, data) ? prev : data)) + }) + }, 5000) + return () => clearInterval(interval) +}, []) +``` + +```python +# ❌ Writing to DB every loop — even when value hasn't changed +for item in items: + item.status = compute_status(item) + session.commit() + +# ✅ Only write when changed +for item in items: + new_status = compute_status(item) + if item.status != new_status: + item.status = new_status + session.commit() +``` + +**Review points:** + +- Does polling / interval / event handler update unconditionally? +- Does the wrapper function respect same-reference return? +- Does the DB write check for actual changes? + +--- + +## TOCTOU Race Conditions + +### Time-of-Check-to-Time-of-Use + +```python +# ❌ Check then operate — file may be deleted/created in between +if os.path.exists(path): + with open(path) as f: + data = f.read() + +# ✅ Operate directly + handle exception +try: + with open(path) as f: + data = f.read() +except FileNotFoundError: + data = None +``` + +```python +# ❌ Check balance → deduct two-step operation is not atomic +if account.balance >= amount: + account.balance -= amount + +# ✅ Atomic operation or lock +with account.lock: + if account.balance < amount: + raise InsufficientFundsError() + account.balance -= amount +``` + +```typescript +// ❌ Check-then-act is unsafe in async environments +if (!fileExists(path)) { + await writeFile(path, content) +} + +// ✅ Operate directly + catch +try { + await writeFile(path, content, { flag: 'wx' }) +} catch (e) { + if (e.code === 'EEXIST') { + /* handle */ + } else throw e +} +``` + +**Review points:** + +- Can `if exists → operate` pattern be replaced with `try operate → catch`? +- Are multi-step state changes within a transaction/lock? +- Is there an `await` between check and act in async operations? + +--- + +## Overly Broad Operations + +### Reading Too Much Data + +```python +# ❌ Read entire file to get first line +content = Path("log.txt").read_text() +first_line = content.split("\n")[0] + +# ✅ Only read first line, don't load entire file +with open("log.txt") as f: + first_line = f.readline() +``` + +```typescript +// ❌ Load all items then filter +const allItems = await db.query('SELECT * FROM orders') +const pending = allItems.filter((o) => o.status === 'pending') + +// ✅ Filter at database level +const pending = await db.query('SELECT * FROM orders WHERE status = ?', [ + 'pending', +]) +``` + +```python +# ❌ Read entire list to find one record +users = list(User.objects.all()) +user = next(u for u in users if u.id == user_id) + +# ✅ Precise query +user = User.objects.get(id=user_id) +``` + +**Review points:** + +- Is the entire collection/file read only to use a small subset? +- Can filtering be pushed to the database/storage layer? +- Does the API call support pagination/limit parameters? + +--- + +## Redundant State + +### State That Can Be Derived + +```typescript +// ❌ Storing fullName alongside firstName + lastName +interface User { + firstName: string + lastName: string + fullName: string // redundant +} + +// ✅ fullName is a derived value +interface User { + firstName: string + lastName: string +} +const fullName = `${user.firstName} ${user.lastName}` +``` + +```python +# ❌ Cached value may be stale when source data changes +class Order: + total: float + item_count: int # redundant if len(items) gives the same + items: list[Item] + +# ✅ Derive or use property +class Order: + items: list[Item] + + @property + def total(self) -> float: + return sum(item.price for item in self.items) + + @property + def item_count(self) -> int: + return len(self.items) +``` + +**Review points:** + +- Are there fields that can be derived from other fields? +- Do cached values have an invalidation mechanism? +- Can observer/effect be replaced with a direct call? + +--- + +## Universal Quality Checklist + +- [ ] **Reuse review**: Searched for existing utilities/helpers, no reinventing the wheel? +- [ ] **Parameter count**: Function parameters ≤ 3? Use options object / dataclass if more? +- [ ] **Abstraction boundaries**: Return types don't expose internal implementation details (ORM, HTTP client, file format)? +- [ ] **Type safety**: No magic strings instead of existing enum/constant/union type? +- [ ] **Conditional depth**: Ternary nesting ≤ 1 level? if/else nesting ≤ 2 levels? +- [ ] **DRY**: No copy-paste-with-variation (≥ 2 near-duplicate code blocks)? +- [ ] **No-op guard**: Polling / interval / event handler has change-detection guard? +- [ ] **TOCTOU**: `if exists → operate` replaced with `try operate → catch`? +- [ ] **Data precision**: Not reading entire collection/file just to get a subset? +- [ ] **Redundant state**: No stored fields that can be derived from other fields? diff --git a/.agents/skills/code-review-skill/reference/code-review-best-practices.md b/.agents/skills/code-review-skill/reference/code-review-best-practices.md new file mode 100644 index 0000000..8c6b9cd --- /dev/null +++ b/.agents/skills/code-review-skill/reference/code-review-best-practices.md @@ -0,0 +1,136 @@ +# Code Review Best Practices + +Comprehensive guidelines for conducting effective code reviews. + +## Review Philosophy + +### Goals of Code Review + +**Primary Goals:** +- Catch bugs and edge cases before production +- Ensure code maintainability and readability +- Share knowledge across the team +- Enforce coding standards consistently +- Improve design and architecture decisions + +**Secondary Goals:** +- Mentor junior developers +- Build team culture and trust +- Document design decisions through discussions + +### What Code Review is NOT + +- A gatekeeping mechanism to block progress +- An opportunity to show off knowledge +- A place to nitpick formatting (use linters) +- A way to rewrite code to personal preference + +## Review Timing + +### When to Review + +| Trigger | Action | +|---------|--------| +| PR opened | Review within 24 hours, ideally same day | +| Changes requested | Re-review within 4 hours | +| Blocking issue found | Communicate immediately | + +### Time Allocation + +- **Small PR (<100 lines)**: 10-15 minutes +- **Medium PR (100-400 lines)**: 20-40 minutes +- **Large PR (>400 lines)**: Request to split, or 60+ minutes + +## Review Depth Levels + +### Level 1: Skim Review (5 minutes) +- Check PR description and linked issues +- Verify CI/CD status +- Look at file changes overview +- Identify if deeper review needed + +### Level 2: Standard Review (20-30 minutes) +- Full code walkthrough +- Logic verification +- Test coverage check +- Security scan + +### Level 3: Deep Review (60+ minutes) +- Architecture evaluation +- Performance analysis +- Security audit +- Edge case exploration + +## Communication Guidelines + +### Tone and Language + +**Use collaborative language:** +- "What do you think about..." instead of "You should..." +- "Could we consider..." instead of "This is wrong" +- "I'm curious about..." instead of "Why didn't you..." + +**Be specific and actionable:** +- Include code examples when suggesting changes +- Link to documentation or past discussions +- Explain the "why" behind suggestions + +### Handling Disagreements + +1. **Seek to understand**: Ask clarifying questions +2. **Acknowledge valid points**: Show you've considered their perspective +3. **Provide data**: Use benchmarks, docs, or examples +4. **Escalate if needed**: Involve senior dev or architect +5. **Know when to let go**: Not every hill is worth dying on + +## Review Prioritization + +### Must Fix (Blocking) +- Security vulnerabilities +- Data corruption risks +- Breaking changes without migration +- Critical performance issues +- Missing error handling for user-facing features + +### Should Fix (Important) +- Test coverage gaps +- Moderate performance concerns +- Code duplication +- Unclear naming or structure +- Missing documentation for complex logic + +### Nice to Have (Non-blocking) +- Style preferences beyond linting +- Minor optimizations +- Additional test cases +- Documentation improvements + +## Anti-Patterns to Avoid + +### Reviewer Anti-Patterns +- **Rubber stamping**: Approving without actually reviewing +- **Bike shedding**: Debating trivial details extensively +- **Scope creep**: "While you're at it, can you also..." +- **Ghosting**: Requesting changes then disappearing +- **Perfectionism**: Blocking for minor style preferences + +### Author Anti-Patterns +- **Mega PRs**: Submitting 1000+ line changes +- **No context**: Missing PR description or linked issues +- **Defensive responses**: Arguing every suggestion +- **Silent updates**: Making changes without responding to comments + +## Metrics and Improvement + +### Track These Metrics +- Time to first review +- Review cycle time +- Number of review rounds +- Defect escape rate +- Review coverage percentage + +### Continuous Improvement +- Hold retrospectives on review process +- Share learnings from escaped bugs +- Update checklists based on common issues +- Celebrate good reviews and catches diff --git a/.agents/skills/code-review-skill/reference/common-bugs-checklist.md b/.agents/skills/code-review-skill/reference/common-bugs-checklist.md new file mode 100644 index 0000000..d266f57 --- /dev/null +++ b/.agents/skills/code-review-skill/reference/common-bugs-checklist.md @@ -0,0 +1,248 @@ +# Common Bugs Checklist + +Quick-reference bug patterns organized by category. For detailed code examples, explanations, and comprehensive review checklists, see the dedicated language guides linked below. + +## Universal Issues + +### Logic Errors +- [ ] Off-by-one errors in loops and array access +- [ ] Incorrect boolean logic (De Morgan's law violations) +- [ ] Missing null/undefined checks +- [ ] Race conditions in concurrent code +- [ ] Incorrect comparison operators (`==` vs `===`, `=` vs `==`) +- [ ] Integer overflow/underflow +- [ ] Floating point comparison issues + +### Resource Management +- [ ] Memory leaks (unclosed connections, listeners) +- [ ] File handles not closed +- [ ] Database connections not released +- [ ] Event listeners not removed +- [ ] Timers/intervals not cleared + +### Error Handling +- [ ] Swallowed exceptions (empty catch blocks) +- [ ] Generic exception handling hiding specific errors +- [ ] Missing error propagation +- [ ] Incorrect error types thrown +- [ ] Missing finally/cleanup blocks + +## TypeScript/JavaScript + +- [ ] `==` instead of `===` +- [ ] Using `any` — prefer proper types or `unknown` with type guards +- [ ] Missing `await` on async calls +- [ ] Unhandled promise rejections (no try-catch around await) +- [ ] `this` context lost in callbacks +- [ ] Missing `key` prop in lists +- [ ] Closure capturing stale loop variable +- [ ] `parseInt` without radix parameter +- [ ] Modifying array/object during iteration + +**Full guide:** [TypeScript Review Guide](typescript.md) + +## React / React 19 + +- [ ] Hooks called conditionally or in loops (violates Rules of Hooks) +- [ ] `useEffect` dependency array incomplete or incorrect +- [ ] `useEffect` missing cleanup function (subscriptions, timers, fetches) +- [ ] `useEffect` used for derived state (use `useMemo` instead) +- [ ] `useMemo`/`useCallback` over-used or used without `React.memo` +- [ ] Component defined inside another component (re-mounts every render) +- [ ] Unstable props (inline objects/functions passed to memo components) +- [ ] Direct mutation of props +- [ ] List missing `key` or using array index as key (reorderable lists) +- [ ] Server Component using client APIs (`useState`, `useEffect`, `onClick`) +- [ ] `'use client'` on parent making entire subtree client-side +- [ ] `useActionState` calling `setState` instead of returning new state +- [ ] `useFormStatus` called in same component as `
` (must be in child) +- [ ] `useOptimistic` used for critical operations (payments, deletions) +- [ ] Single Suspense boundary for entire page (slow blocks fast) +- [ ] Missing Error Boundary wrapping Suspense +- [ ] `use()` Hook receiving a new Promise each render + +**TanStack Query v5:** +- [ ] `queryKey` missing parameters that affect data +- [ ] Default `staleTime: 0` causing excessive refetches +- [ ] `useSuspenseQuery` with `enabled` option (not supported) +- [ ] Mutation not invalidating related queries on success +- [ ] Optimistic update missing rollback in `onError` +- [ ] Using v4 array syntax (`useQuery(['key'], fn)`) instead of v5 object syntax + +**Testing:** +- [ ] Using `container.querySelector` instead of `screen.getByRole` +- [ ] Using `fireEvent` instead of `userEvent` +- [ ] Testing implementation details instead of user-visible behavior +- [ ] Using `getBy*` for async content (use `findBy*`) + +**Full guide:** [React Review Guide](react.md) + +## Vue 3 + +- [ ] Destructuring `reactive()` object loses reactivity (use `toRefs`) +- [ ] Passing `props.x` to composable instead of `() => props.x` or `toRef(props, 'x')` +- [ ] `watch` with async callback missing `onCleanup` (race condition) +- [ ] `computed` with side effects (mutations, API calls) +- [ ] `v-for` using index as `:key` when list can reorder +- [ ] `v-if` and `v-for` on the same element +- [ ] `defineProps` without TypeScript type declaration +- [ ] `withDefaults` object default values not using factory functions +- [ ] Directly mutating props instead of emitting events +- [ ] `watchEffect` with unclear dependencies causing over-triggering + +**Full guide:** [Vue 3 Review Guide](vue.md) + +## Python + +- [ ] Mutable default arguments (`def f(x=[])`) +- [ ] Bare `except:` catching `KeyboardInterrupt` and `SystemExit` +- [ ] Shared mutable class attributes (`class C: items = []`) +- [ ] Using `is` instead of `==` for value comparison +- [ ] Forgetting `self` parameter in methods +- [ ] Modifying list while iterating +- [ ] String concatenation in loops (use `"".join()`) +- [ ] Not closing files (use `with` statement) +- [ ] Missing type annotations on public functions + +**Full guide:** [Python Review Guide](python.md) + +## Rust + +**Ownership & Borrowing:** +- [ ] Unnecessary `clone()` to work around borrow checker +- [ ] `Arc>` when single-owner would suffice +- [ ] Storing borrows in structs when owned data is simpler +- [ ] Unnecessary `RefCell` (runtime checks vs compile-time) + +**Unsafe Code:** +- [ ] `unsafe` block without `SAFETY:` comment explaining invariants +- [ ] `unsafe fn` without `# Safety` doc section +- [ ] Unsafe invariants split across modules + +**Async & Concurrency:** +- [ ] Blocking in async context (`std::fs`, `std::thread::sleep`) +- [ ] Holding `std::sync::Mutex` across `.await` +- [ ] Spawned task missing `'static` lifetime bound +- [ ] Dropping a Future without awaiting (forgotten work) + +**Error Handling:** +- [ ] `unwrap()`/`expect()` in production code +- [ ] Library using `anyhow` instead of `thiserror` (callers can't match) +- [ ] Swallowing error context (`map_err(|_| ...)`) +- [ ] Ignoring `must_use` return values + +**Performance:** +- [ ] Unnecessary `.collect()` — prefer lazy iterators +- [ ] String concatenation in loops without `with_capacity` +- [ ] `Box` when `impl Trait` would work + +**Full guide:** [Rust Review Guide](rust.md) + +## Go + +- [ ] Ignoring errors (`result, _ := SomeFunction()`) +- [ ] Goroutine with no exit mechanism (leak) +- [ ] Missing or incorrect `context.Context` propagation +- [ ] Loop variable capture issue (Go < 1.22) +- [ ] `defer` in loops (deferred until function, not loop iteration) +- [ ] Variable shadowing +- [ ] Map used before initialization +- [ ] Error wrapping with `%v` instead of `%w` (breaks `errors.Is`/`errors.As`) + +**Full guide:** [Go Review Guide](go.md) + +## Java / Spring Boot + +- [ ] POJO/DTO with manual boilerplate instead of `record` +- [ ] Traditional switch missing `break` (use switch expressions) +- [ ] Field injection instead of constructor injection +- [ ] JPA N+1 query (missing `fetch join` or `@EntityGraph`) +- [ ] Incorrect `equals`/`hashCode` on JPA entities (use business key, not ID) +- [ ] `Optional.get()` without `isPresent()` check +- [ ] Stream operations with side effects + +**Full guide:** [Java Review Guide](java.md) + +## PHP + +- [ ] Missing `declare(strict_types=1);` in new files +- [ ] Weak comparison (`==`, `!=`) in auth, token, payment, or state logic +- [ ] `in_array()` / `array_search()` used without strict mode +- [ ] SQL built with string concatenation instead of prepared statements +- [ ] User input echoed without context-aware escaping +- [ ] Passwords stored with `md5()` / `sha1()` instead of `password_hash()` +- [ ] Untrusted data passed to `unserialize()` +- [ ] PHP 8.2+ dynamic properties used instead of declared properties +- [ ] Errors hidden with `@` or swallowed in empty `catch` blocks +- [ ] File uploads using client-provided names or missing MIME/size validation + +**Full guide:** [PHP Review Guide](php.md) + +## Swift + +- [ ] Force-unwrap (`!`) or `try!` where safe unwrapping is possible +- [ ] Closure capturing `self` strongly without `[weak self]` (retain cycle) +- [ ] Reference type (`class`) used where a value type (`struct`) is intended +- [ ] Errors swallowed instead of propagated via `throws` / `Result` +- [ ] Data race across concurrency boundaries (missing `Sendable`, `@MainActor`, actor isolation) +- [ ] Fire-and-forget `Task {}` that is never cancelled or leaks +- [ ] `@ObservedObject` used where `@StateObject` is required for ownership +- [ ] Implicitly unwrapped optional (`var x: T!`) outside IBOutlets +- [ ] Over-broad access control (`public` / `open` where `internal` suffices) + +**Full guide:** [Swift Review Guide](swift.md) + +## C + +- [ ] Pointer/buffer overflow or underflow +- [ ] Undefined behavior (use-after-free, double-free, null deref) +- [ ] Missing error handling after allocation (`malloc` can return `NULL`) +- [ ] Integer overflow in size calculations +- [ ] Resource leaks (missing `free`, `fclose`, etc.) +- [ ] Missing `static` on file-local functions/variables + +**Full guide:** [C Review Guide](c.md) + +## C++ + +- [ ] Missing RAII wrapper for resources +- [ ] Violating Rule of 0/3/5 (destructor, copy, move) +- [ ] Exception safety issues (no `noexcept` where applicable) +- [ ] Dangling references from returned iterators or references +- [ ] Unnecessary copies (missing `std::move` or pass-by-reference) + +**Full guide:** [C++ Review Guide](cpp.md) + +## SQL + +- [ ] String concatenation for queries (SQL injection risk) — use parameterized queries +- [ ] Missing indexes on filtered/joined columns +- [ ] `SELECT *` instead of specific columns +- [ ] N+1 query patterns +- [ ] Missing `LIMIT` on large tables +- [ ] Not handling `NULL` comparisons correctly (`IS NULL` vs `= NULL`) +- [ ] Missing transactions for related operations +- [ ] Incorrect JOIN types +- [ ] Collation / case sensitivity surprises across databases (MySQL vs Postgres defaults) +- [ ] Date and timezone handling errors (naive timestamps, server-local `NOW()`, DST) + +**See also:** [Security Review Guide](security-review-guide.md) for SQL injection prevention + +## API Design + +- [ ] Inconsistent resource naming +- [ ] Wrong HTTP methods (POST for idempotent operations) +- [ ] Missing pagination for list endpoints +- [ ] Incorrect status codes +- [ ] Missing rate limiting +- [ ] Missing input validation and sanitization +- [ ] Trusting client-side validation only + +## Testing + +- [ ] Testing implementation details instead of behavior +- [ ] Missing edge case tests +- [ ] Flaky tests (non-deterministic) +- [ ] Tests with external dependencies (no mocks) +- [ ] Missing negative tests (error cases) +- [ ] Overly complex test setup diff --git a/.agents/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md b/.agents/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md new file mode 100644 index 0000000..a03cd8e --- /dev/null +++ b/.agents/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md @@ -0,0 +1,520 @@ +# Async & Concurrency Patterns — Cross-Language Guide + +> This document covers concurrency model comparisons, common pitfalls, cross-language best practices, and structured concurrency patterns. + +## Table of Contents + +- [Concurrency Model Comparison](#concurrency-model-comparison) +- [Common Pitfalls](#common-pitfalls) +- [Best Practices](#best-practices) +- [Cross-Language Code Examples](#cross-language-code-examples) +- [Review Checklist](#review-checklist) + +--- + +## Concurrency Model Comparison + +| Model | Languages | Core Concept | Pros | Cons | +| ---------------------------- | ------------------ | ------------------------------------------ | ------------------------------------------ | -------------------------------------- | +| **Goroutines + Channels** | Go | Lightweight coroutines + CSP communication | Minimal syntax, low overhead | Manual cancellation propagation | +| **async/await + Event Loop** | Python, TypeScript | Single-threaded cooperative multitasking | Lock-free, easy to reason about | Cannot block the event loop | +| **async/await + Tokio** | Rust | Futures + runtime scheduling | Zero-cost abstraction, compile-time safety | Steep learning curve | +| **Coroutines + Flow** | Kotlin | Suspend functions + structured concurrency | Automatic cancellation, lifecycle-bound | Complex Dispatcher selection | +| **async/await + Actors** | Swift | Structured concurrency + Actor isolation | Compile-time data race checking | Swift 6 migration cost | +| **async/await + TPL** | C# | Task + thread pool | Mature ecosystem, ConfigureAwait | Implicit thread switching | +| **Threads + Mutexes** | C++, Java, all | OS threads + shared memory | True parallelism | Complex lock management, deadlock risk | + +### When to Choose What + +``` +I/O-bound (network, database, files): + → async/await (Python, TS, Rust, Swift, C#) + → goroutines (Go) + → coroutines (Kotlin) + +CPU-bound (computation, image processing): + → thread pool (Java, C++, C#) + → multiprocessing (Python) + → spawn_blocking (Rust tokio) + → Dispatchers.Default (Kotlin) + +Mixed: + → async + spawn_blocking (Rust) + → async + run_in_executor (Python) + → goroutines + sync.Mutex (Go) +``` + +--- + +## Common Pitfalls + +### Pitfall 1: Race Condition + +Multiple concurrent tasks read and write shared state, and the result depends on execution order. + +``` +// Generic pseudocode +counter = 0 + +task1: counter += 1 // read counter=0, write counter=1 +task2: counter += 1 // read counter=0, write counter=1 +// expected counter=2, actual counter=1 +``` + +**Solution**: Mutexes, atomic operations, or encapsulate shared state in an Actor. + +### Pitfall 2: Deadlock + +Two or more tasks wait for locks held by each other. + +``` +task1: lock(A); lock(B); // holds A, waits for B +task2: lock(B); lock(A); // holds B, waits for A +// both wait forever +``` + +**Solution**: + +- Consistent lock acquisition order +- Timeout locks (tryLock with timeout) +- Avoid nested locks + +### Pitfall 3: Starvation + +Low-priority tasks never get a chance to execute. + +``` +// High-priority tasks keep arriving, low-priority tasks queue forever +``` + +**Solution**: Fair locks, task priority queues, concurrency limits. + +### Pitfall 4: Goroutine / Task Leak + +Starting concurrent tasks without ensuring they exit. + +```go +// ❌ Go: goroutine leak +func process() { + ch := make(chan int) + go func() { + result := <-ch // if nobody sends, goroutine blocks forever + }() + // function returns, but goroutine is still waiting +} +``` + +```python +# ❌ Python: Task leak +async def process(): + task = asyncio.create_task(long_running()) + # function returns, but task is still running +``` + +**Solution**: Use context/done channel (Go), TaskGroup (Python), structured concurrency (Kotlin/Swift). + +### Pitfall 5: Blocking in an Async Context + +```python +# ❌ Python: Using synchronous I/O in an async function blocks the event loop +async def handle(): + result = requests.get(url) # blocks! entire event loop stalls + return result + +# ✅ Use async I/O or offload blocking operations to a thread pool +async def handle(): + result = await aiohttp.get(url) # non-blocking + return result + +# Or offload synchronous code to a thread pool +async def handle(): + result = await asyncio.to_thread(requests.get, url) + return result +``` + +```rust +// ❌ Rust: Blocking in an async function +async fn handle() { + let result = std::fs::read_to_string("large.txt"); // blocks tokio runtime +} + +// ✅ Use spawn_blocking +async fn handle() { + let result = tokio::task::spawn_blocking(|| { + std::fs::read_to_string("large.txt") + }).await?; +} +``` + +--- + +## Best Practices + +### 1. Structured Concurrency + +Ensure the lifetime of concurrent tasks is bound to the scope that created them. When the parent task is cancelled, child tasks are automatically cancelled. + +```kotlin +// ✅ Kotlin: coroutineScope ensures all child coroutines complete when the scope ends +suspend fun processItems(items: List) = coroutineScope { + items.forEach { item -> + launch { processItem(item) } // child coroutine + } + // waits for all child coroutines to complete when scope ends +} + +// If processItems is cancelled, all child coroutines are automatically cancelled +``` + +```swift +// ✅ Swift: async let + TaskGroup +func processItems() async throws { + async let resultA = fetchA() // concurrent execution + async let resultB = fetchB() + let combined = try await (resultA, resultB) // wait for both +} +``` + +```python +# ✅ Python 3.11+: TaskGroup +async def process_items(): + async with asyncio.TaskGroup() as tg: + for item in items: + tg.create_task(process_item(item)) + # TaskGroup waits for all tasks to complete on exit + # If one task fails, remaining tasks are automatically cancelled +``` + +### 2. Cancellation Propagation + +Ensure cancellation signals propagate correctly to all child tasks. + +```go +// ✅ Go: context propagates cancellation +func processAll(ctx context.Context, items []Item) error { + g, ctx := errgroup.WithContext(ctx) + for _, item := range items { + item := item + g.Go(func() error { + return processItem(ctx, item) + }) + } + return g.Wait() // if any fails, context is cancelled, remaining tasks receive the signal +} +``` + +```rust +// ✅ Rust: tokio::select! + JoinHandle +async fn process_with_timeout(item: Item) -> Result { + tokio::select! { + result = process(item) => result, + _ = tokio::time::sleep(Duration::from_secs(30)) => { + Err(anyhow!("processing timed out")) + } + } +} +``` + +### 3. Backpressure + +When the producer is much faster than the consumer, limit the queue size to prevent memory bloat. + +```go +// ✅ Go: Buffered channel as natural backpressure +func process(items <-chan Item) <-chan Result { + results := make(chan Result, 10) // buffer 10 results + go func() { + for item := range items { + results <- processItem(item) // blocks when buffer is full + } + close(results) + }() + return results +} +``` + +```kotlin +// ✅ Kotlin: Flow has built-in backpressure +fun itemsFlow(): Flow = flow { + for (item in fetchAll()) { + emit(item) // suspends when collector is not ready + } +} +// Use buffer() to control buffering strategy +itemsFlow() + .buffer(capacity = 10, onBufferOverflow = BufferOverflow.SUSPEND) + .collect { process(it) } +``` + +### 4. Limit Concurrency + +Prevent resource exhaustion from starting too many tasks simultaneously. + +```python +# ✅ Python: Semaphore to limit concurrency +async def fetch_all(urls: list[str], max_concurrent: int = 10): + semaphore = asyncio.Semaphore(max_concurrent) + + async def fetch_one(url: str): + async with semaphore: + return await aiohttp.get(url) + + return await asyncio.gather(*[fetch_one(url) for url in urls]) +``` + +```go +// ✅ Go: errgroup + semaphore +func fetchAll(ctx context.Context, urls []string, maxConcurrent int) error { + g, ctx := errgroup.WithContext(ctx) + sem := make(chan struct{}, maxConcurrent) + + for _, url := range urls { + url := url + g.Go(func() error { + sem <- struct{}{} // acquire semaphore + defer func() { <-sem }() // release semaphore + return fetch(ctx, url) + }) + } + return g.Wait() +} +``` + +--- + +## Cross-Language Code Examples + +### Go: Goroutines + Channels + Context + +```go +// ✅ Complete pattern: context cancellation + errgroup + bounded concurrency +func processBatch(ctx context.Context, items []Item) ([]Result, error) { + g, ctx := errgroup.WithContext(ctx) + results := make([]Result, len(items)) + sem := make(chan struct{}, 10) // at most 10 concurrent + + for i, item := range items { + i, item := i, item + g.Go(func() error { + select { + case sem <- struct{}{}: + case <-ctx.Done(): + return ctx.Err() + } + defer func() { <-sem }() + + result, err := process(ctx, item) + if err != nil { + return fmt.Errorf("item %d: %w", i, err) + } + results[i] = result + return nil + }) + } + + if err := g.Wait(); err != nil { + return nil, err + } + return results, nil +} +``` + +### Python: asyncio + TaskGroup + +```python +# ✅ Python 3.11+: Structured concurrency + bounded concurrency + timeout +import asyncio + +async def process_batch(items: list[Item], max_concurrent: int = 10) -> list[Result]: + semaphore = asyncio.Semaphore(max_concurrent) + + async def process_one(item: Item) -> Result: + async with semaphore: + return await process(item) + + async with asyncio.TaskGroup() as tg: + tasks = [tg.create_task(process_one(item)) for item in items] + + return [task.result() for task in tasks] +``` + +### Rust: tokio + select + spawn_blocking + +```rust +// ✅ Bounded concurrency + timeout + isolated blocking operations +use tokio::sync::Semaphore; +use std::sync::Arc; + +async fn process_batch(items: Vec, max_concurrent: usize) -> Result> { + let sem = Arc::new(Semaphore::new(max_concurrent)); + let mut handles = Vec::new(); + + for item in items { + let permit = sem.clone().acquire_owned().await?; + handles.push(tokio::spawn(async move { + let _permit = permit; // drop on completion + tokio::select! { + result = process(item) => result, + _ = tokio::time::sleep(Duration::from_secs(30)) => { + Err(anyhow!("timeout")) + } + } + })); + } + + let mut results = Vec::new(); + for handle in handles { + results.push(handle.await??); + } + Ok(results) +} +``` + +### Kotlin: Coroutines + Flow + Dispatchers + +```kotlin +// ✅ Structured concurrency + bounded concurrency + cancellation safety +suspend fun processBatch(items: List, maxConcurrent: Int = 10): List { + val semaphore = Semaphore(maxConcurrent) + + return coroutineScope { + items.map { item -> + async(Dispatchers.IO) { + semaphore.withPermit { + process(item) + } + } + }.awaitAll() + } +} + +// ✅ Flow: streaming + backpressure +fun itemStream(): Flow = flow { + for (item in fetchAllItems()) { + emit(process(item)) + } +} + .flowOn(Dispatchers.IO) + .buffer(capacity = 10) + .catch { e -> logger.error("stream failed", e) } +``` + +### Swift: async/await + TaskGroup + Actors + +```swift +// ✅ Structured concurrency + actor isolation +actor ResultCollector { + private var results: [Result] = [] + func add(_ result: Result) { results.append(result) } + func all() -> [Result] { results } +} + +func processBatch(items: [Item], maxConcurrent: Int = 10) async throws -> [Result] { + let collector = ResultCollector() + + try await withThrowingTaskGroup(of: Void.self) { group in + var active = 0 + for item in items { + if active >= maxConcurrent { + try await group.next() + active -= 1 + } + group.addTask { + let result = try await process(item) + await collector.add(result) + } + active += 1 + } + } + + return await collector.all() +} +``` + +### C#: async/await + SemaphoreSlim + CancellationToken + +```csharp +// ✅ Bounded concurrency + cancellation + exception handling +async Task> ProcessBatchAsync( + List items, + int maxConcurrent = 10, + CancellationToken ct = default) +{ + using var semaphore = new SemaphoreSlim(maxConcurrent); + var tasks = items.Select(async item => + { + await semaphore.WaitAsync(ct); + try + { + return await ProcessAsync(item, ct); + } + finally + { + semaphore.Release(); + } + }); + + var results = await Task.WhenAll(tasks); + return results.ToList(); +} +``` + +### TypeScript: Worker-pool Concurrency Limit + +```typescript +// ✅ Worker-pool pattern: fixed number of workers compete for task queue +// Results are assigned by original index, ensuring output order matches input order. +async function processWithLimit( + items: T[], + fn: (item: T) => Promise, + limit: number +): Promise { + const results: R[] = [] + let index = 0 + + const workers = Array.from({ length: limit }, async () => { + while (index < items.length) { + const i = index++ + results[i] = await fn(items[i]) + } + }) + + await Promise.all(workers) + return results +} +``` + +--- + +## Review Checklist + +### Basic Checks + +- [ ] Concurrent tasks have a clear exit mechanism (no leaks) +- [ ] Shared state is properly protected (mutex, actor, channel) +- [ ] No blocking operations in async contexts +- [ ] Cancellation signals propagate correctly to all child tasks + +### Architecture Checks + +- [ ] Uses structured concurrency (TaskGroup / coroutineScope / errgroup) +- [ ] Concurrency has an upper bound (semaphore / bounded channel) +- [ ] Long-running tasks support timeout +- [ ] Backpressure mechanism prevents memory bloat + +### Performance Checks + +- [ ] Concurrency granularity is reasonable (not too fine, not too coarse) +- [ ] I/O-bound uses async, CPU-bound uses threads/processes +- [ ] Lock hold time is minimized +- [ ] No unnecessary awaits (parallelizable operations executed serially) + +### Language-Specific + +- [ ] Go: context propagation, errgroup usage, reasonable channel buffering +- [ ] Python: event loop not blocked, TaskGroup manages lifecycle +- [ ] Rust: spawn_blocking isolates blocking operations, select! handles timeouts +- [ ] Kotlin: coroutineScope for structured concurrency, correct Dispatcher selection +- [ ] Swift: @MainActor protects UI, actor isolates mutable state +- [ ] C#: CancellationToken propagation, ConfigureAwait(false) in library code +- [ ] TypeScript: Promise.all + concurrency limit, AbortController for cancellation diff --git a/.agents/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md b/.agents/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md new file mode 100644 index 0000000..c0777d5 --- /dev/null +++ b/.agents/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md @@ -0,0 +1,497 @@ +# Error Handling Principles — Cross-Language Guide + +> This document covers core error handling principles, common anti-patterns, error hierarchy design, and logging best practices. Each principle includes cross-language code examples. + +## Table of Contents + +- [Core Principles](#core-principles) +- [Anti-Patterns](#anti-patterns) +- [Error Hierarchy Design](#error-hierarchy-design) +- [Logging Best Practices](#logging-best-practices) +- [Cross-Language Code Examples](#cross-language-code-examples) +- [Review Checklist](#review-checklist) + +--- + +## Core Principles + +### Principle 1: Don't Swallow Errors + +Every error must be handled: propagate it upward, log it, or convert it to a more meaningful error. **Never** silently ignore it. + +``` +// Pseudocode +result = risky_operation() +if error: + // Must do one of the following: + // 1. return error to caller (propagate) + // 2. log + return fallback (degrade) + // 3. panic/crash (when unrecoverable) +``` + +### Principle 2: Add Context + +Error messages should include the **operation description** and **key parameters**, so debuggers can locate the problem without reading the call chain. + +``` +// ❌ No context +"failed" + +// ✅ With context +"failed to process order #12345: payment gateway timeout after 30s" +``` + +### Principle 3: Use Specific Types + +Use error types to distinguish failure reasons, allowing callers to handle different failure scenarios precisely. + +``` +// ❌ Generic error +throw new Error("something went wrong") + +// ✅ Specific types +throw new OrderNotFoundError(orderId) +throw new PaymentTimeoutException(gatewayName, timeoutMs) +``` + +### Principle 4: Fail Fast + +Validate preconditions before starting an operation to fail early. This avoids inconsistent states caused by discovering errors after partial execution. + +``` +// ❌ Discovering invalid parameters halfway through +def process(data, config): + result = expensive_computation(data) # already spent 5 seconds + if not config.valid: + raise ValueError("invalid config") # 5 seconds wasted + +// ✅ Validate first +def process(data, config): + if not config.valid: + raise ValueError("invalid config") + result = expensive_computation(data) +``` + +### Principle 5: Handle Errors Only Once + +Don't handle the same error at every level (both log and return and wrap). Choose one approach and let the caller decide how to handle it. + +``` +// ❌ Both log and return (duplicate handling) +if err: + log.error("failed: %s", err) + return err + +// ✅ Only wrap and return, let the top level handle uniformly +if err: + return wrap_error("operation failed", err) +``` + +--- + +## Anti-Patterns + +### Anti-Pattern 1: Empty catch Block + +```python +# ❌ Python: Bare except swallows all exceptions (including KeyboardInterrupt) +try: + result = risky() +except: + pass + +# ❌ Java: Empty catch swallows exception +try { + result = risky(); +} catch (Exception e) { + // do nothing +} + +# ❌ Go: Ignoring error +result, _ := risky() + +# ❌ Rust: unwrap() in production code +let result = risky().unwrap(); // panic on error +``` + +### Anti-Pattern 2: Overly Broad catch + +```python +# ❌ Catching all exceptions, cannot distinguish failure types +try: + result = risky() +except Exception as e: + logger.error(f"failed: {e}") + +# ✅ Catch specific exceptions +try: + result = risky() +except ConnectionError as e: + logger.warning(f"network issue, retrying: {e}") + result = retry(risky) +except ValueError as e: + logger.error(f"bad input: {e}") + raise +``` + +### Anti-Pattern 3: Losing the Original Exception + +```python +# ❌ Lost the original exception's stack and information +try: + result = external_api.call() +except APIError as e: + raise RuntimeError("API failed") # lost the cause + +# ✅ Preserve exception chain +try: + result = external_api.call() +except APIError as e: + raise RuntimeError("API failed") from e +``` + +```java +// ❌ Losing original exception +catch (IOException e) { + throw new ServiceException("IO failed"); +} + +// ✅ Preserve cause +catch (IOException e) { + throw new ServiceException("IO failed", e); +} +``` + +### Anti-Pattern 4: Using Exceptions for Flow Control + +```python +# ❌ Using exceptions for normal flow control (slow and unclear) +try: + user = users[name] +except KeyError: + user = create_default_user(name) + +# ✅ Explicit check +user = users.get(name) or create_default_user(name) +``` + +```go +// ❌ Go: panic for flow control +func getUser(id int) User { + if id <= 0 { + panic("invalid id") + } +} + +// ✅ Go: Return error +func getUser(id int) (User, error) { + if id <= 0 { + return User{}, fmt.Errorf("invalid user id: %d", id) + } +} +``` + +### Anti-Pattern 5: Ignoring Return Values + +```csharp +// ❌ Ignoring returned bool/Result +dict.TryGetValue("key", out var value); +// value may be default, but code continues as if successful + +// ✅ Check return value +if (!dict.TryGetValue("key", out var value)) +{ + throw new KeyNotFoundException("key not found"); +} +``` + +--- + +## Error Hierarchy Design + +### Three-Layer Error Architecture + +``` +┌─────────────────────────────────────────────────┐ +│ Application Errors │ +│ - AppError / ServiceError │ +│ - Caught by global exception handler, returns │ +│ user-friendly response │ +├─────────────────────────────────────────────────┤ +│ Module Errors │ +│ - PaymentError, AuthError, ValidationError │ +│ - Each business module defines its own types │ +├─────────────────────────────────────────────────┤ +│ Infrastructure Errors │ +│ - IOError, NetworkError, DatabaseError │ +│ - Low-level errors from OS, network, database │ +└─────────────────────────────────────────────────┘ +``` + +### Design Rules + +1. **Module-level errors inherit from application-level base class**, enabling global catch +2. **Infrastructure errors are converted to module-level errors at module boundaries**, not exposed to upper layers +3. **Each error type includes sufficient context** for debugging (ID, timestamp, operation name) + +### Example Hierarchy (Python) + +```python +class AppError(Exception): + """Application base exception""" + pass + +class PaymentError(AppError): + """Payment module error""" + def __init__(self, order_id: str, reason: str): + self.order_id = order_id + super().__init__(f"payment failed for order {order_id}: {reason}") + +class PaymentGatewayTimeout(PaymentError): + """Payment gateway timeout""" + def __init__(self, order_id: str, gateway: str, timeout_ms: int): + self.gateway = gateway + self.timeout_ms = timeout_ms + super().__init__(order_id, f"gateway {gateway} timed out after {timeout_ms}ms") +``` + +### Example Hierarchy (Java) + +```java +public class AppException extends RuntimeException { + private final String errorCode; + public AppException(String errorCode, String message, Throwable cause) { + super(message, cause); + this.errorCode = errorCode; + } +} + +public class OrderNotFoundException extends AppException { + public OrderNotFoundException(Long orderId) { + super("ORDER_NOT_FOUND", "Order " + orderId + " not found", null); + } +} +``` + +--- + +## Logging Best Practices + +### Log Level Selection + +| Level | When to Use | Example | +| --------- | ------------------------------------- | --------------------------------------- | +| **ERROR** | Failures requiring human intervention | Payment failure, data inconsistency | +| **WARN** | Auto-recoverable anomalies | Retry succeeded, degraded handling | +| **INFO** | Normal business events | Order created, user login | +| **DEBUG** | Debugging information | Function parameters, intermediate state | + +### Log Format + +``` +// ❌ No structured information +log.error("failed to process") + +// ✅ Structured information + context +log.error("payment_failed", { + "order_id": "12345", + "gateway": "stripe", + "error_code": "card_declined", + "amount": 99.99, + "duration_ms": 2340 +}) +``` + +### Log Security + +- **Do not log sensitive information**: passwords, tokens, PII, full credit card numbers +- **Masking**: `email: a***@example.com` +- **Log injection protection**: escape user input to prevent forged log lines + +--- + +## Cross-Language Code Examples + +### Python + +```python +# ✅ Specific exception + context + exception chain +try: + response = http_client.post(url, data=payload) + response.raise_for_status() +except requests.ConnectionError as e: + raise PaymentGatewayError(f"cannot reach {gateway_name}") from e +except requests.HTTPError as e: + if response.status_code == 429: + raise RateLimitError(f"rate limited by {gateway_name}") from e + raise PaymentGatewayError(f"HTTP {response.status_code} from {gateway_name}") from e +``` + +### Java + +```java +// ✅ Specific exception + context + cause chain +try { + var response = httpClient.send(request, BodyHandlers.ofString()); + if (response.statusCode() == 404) { + throw new OrderNotFoundException(orderId); + } +} catch (IOException e) { + throw new PaymentGatewayException( + "gateway unreachable: " + gatewayUrl, e); +} +``` + +### Go + +```go +// ✅ Error wrapping + context + %w preserves chain +result, err := client.Do(req) +if err != nil { + return fmt.Errorf("payment gateway %s request failed: %w", gatewayName, err) +} +defer result.Body.Close() + +if result.StatusCode == http.StatusNotFound { + return fmt.Errorf("order %d not found: %w", orderID, ErrNotFound) +} +``` + +### Rust + +```rust +// ✅ thiserror defines error types + context +#[derive(Debug, thiserror::Error)] +enum PaymentError { + #[error("gateway {gateway} unreachable")] + GatewayUnreachable { + gateway: String, + #[source] + source: reqwest::Error, + }, + #[error("order {order_id} not found")] + OrderNotFound { order_id: u64 }, +} + +async fn process_payment(gateway: &str, order_id: u64) -> Result<(), PaymentError> { + let response = client.post(url) + .send() + .await + .map_err(|e| PaymentError::GatewayUnreachable { + gateway: gateway.into(), + source: e, + })?; + Ok(()) +} +``` + +### C# + +```csharp +// ✅ Specific exception + context +try +{ + var response = await httpClient.PostAsync(url, content); + response.EnsureSuccessStatusCode(); +} +catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound) +{ + throw new OrderNotFoundException(orderId, ex); +} +catch (HttpRequestException ex) +{ + throw new PaymentGatewayException($"gateway unreachable: {url}", ex); +} +``` + +### Swift + +```swift +// ✅ Error enum + context +enum PaymentError: Error { + case gatewayUnreachable(name: String, underlying: Error) + case orderNotFound(id: Int) + case declined(reason: String) +} + +func processPayment(orderId: Int) throws -> Receipt { + guard orderId > 0 else { + throw PaymentError.orderNotFound(id: orderId) + } + do { + let response = try networkClient.post(url, body: payload) + return try Receipt(from: response) + } catch let error as NetworkError { + throw PaymentError.gatewayUnreachable(name: gateway, underlying: error) + } +} +``` + +### TypeScript + +```typescript +// ✅ Custom error class + context +class PaymentError extends Error { + constructor( + message: string, + public readonly orderId: string, + public readonly gateway: string, + public readonly cause?: Error + ) { + super(message) + this.name = 'PaymentError' + } +} + +async function processPayment(orderId: string): Promise { + try { + const response = await fetch(url, { method: 'POST', body: payload }) + if (!response.ok) { + throw new PaymentError( + `gateway returned ${response.status}`, + orderId, + gatewayName + ) + } + return await response.json() + } catch (err) { + if (err instanceof TypeError) { + throw new PaymentError('gateway unreachable', orderId, gatewayName, err) + } + throw err + } +} +``` + +--- + +## Review Checklist + +### Core Checks + +- [ ] No empty catch blocks or silently ignored errors +- [ ] Error messages include operation description and key parameters +- [ ] Specific error types used (not generic Error/Exception) +- [ ] Exception chain preserved (from / cause / %w) +- [ ] Preconditions validated before operation starts (fail fast) + +### Architecture Checks + +- [ ] Clear error hierarchy defined (application/module/infrastructure) +- [ ] Global exception handler catches unhandled errors +- [ ] API boundaries convert internal errors to appropriate HTTP status codes + +### Logging Checks + +- [ ] Error logs include structured context +- [ ] No sensitive information logged (passwords, tokens, PII) +- [ ] Log levels used correctly (ERROR vs WARN vs INFO) + +### Language-Specific + +- [ ] Go: errors not ignored, use `%w` for wrapping +- [ ] Python: catch specific exceptions, use `from` to preserve chain +- [ ] Java: exceptions have cause, use specific types +- [ ] Rust: `?` propagation, custom Error types +- [ ] C#: `when` filter, specific exception types +- [ ] Swift: do-catch, Result for deferred handling diff --git a/.agents/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md b/.agents/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md new file mode 100644 index 0000000..21810e8 --- /dev/null +++ b/.agents/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md @@ -0,0 +1,312 @@ +# N+1 Query Problem — Cross-Language Guide + +> The N+1 query is the most common performance anti-pattern in ORMs and database access layers. This document covers problem definition, detection methods, general solutions, and cross-language code examples. + +## Table of Contents + +- [Problem Definition](#problem-definition) +- [Performance Impact](#performance-impact) +- [Detection Methods](#detection-methods) +- [General Solutions](#general-solutions) +- [Language-Specific Implementations](#language-specific-implementations) +- [Review Checklist](#review-checklist) + +--- + +## Problem Definition + +The N+1 query refers to: **1 query fetches N records, then N additional queries are triggered in a loop** to fetch related data. + +``` +Request flow: + 1 query → Fetch N main records + N queries → Query related data once per main record + ───────── + Total: 1 + N queries +``` + +### Impact + +| Problem | Effect | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------ | +| **Linear growth in query count** | 100 records = 101 SQL queries, 1000 records = 1001 queries | +| **Network latency accumulation** | Each query has round-trip time (RTT), N round trips >> 1 batch query | +| **Connection pool exhaustion** | Large number of queries exhaust database connections, slowing down the entire application | +| **Hard to detect in development** | Dev environments have little data, N+1 is not obvious; performance collapses in production with large data volumes | + +--- + +## Performance Impact + +### Scenario Comparison: Fetching 100 Users and Their Orders + +| Approach | SQL Count | Latency (assuming RTT=1ms) | Suitable Scenario | +| -------------------- | ----------- | -------------------------- | --------------------------------- | +| N+1 lazy loading | 101 queries | ~101ms | Very small data volumes | +| Eager loading (JOIN) | 1 query | ~1ms | One-to-many, moderate data volume | +| Eager loading (IN) | 2 queries | ~2ms | Many-to-many, large datasets | +| DataLoader / batch | 2 queries | ~2ms | GraphQL / complex graph queries | + +### SQL Count Comparison + +```sql +-- ❌ N+1: 1 + 100 = 101 queries +SELECT * FROM users; -- 1 query +SELECT * FROM orders WHERE user_id = 1; -- query 2 +SELECT * FROM orders WHERE user_id = 2; -- query 3 +... +SELECT * FROM orders WHERE user_id = 100; -- query 101 + +-- ✅ Batch: 2 queries +SELECT * FROM users; +SELECT * FROM orders WHERE user_id IN (1,2,...,100); +``` + +--- + +## Detection Methods + +### 1. ORM SQL Logging + +Enable SQL logging and observe query counts in test or development environments: + +```python +# Django +import logging +logging.getLogger('django.db.backends').setLevel(logging.DEBUG) + +# SQLAlchemy +import logging +logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO) +``` + +```java +// Spring Boot application.yml +spring: + jpa: + show-sql: true + properties: + hibernate.format_sql: true +``` + +```csharp +// EF Core +optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information); +``` + +### 2. Query Count Assertions + +Assert SQL query counts in tests: + +```python +# Django: django-assert-num-queries +from django.test.utils import CaptureQueriesContext +from django.db import connection + +with CaptureQueriesContext(connection) as ctx: + list(User.objects.select_related("profile").all()) +assert len(ctx) <= 2 # expect at most 2 queries +``` + +```java +// Hibernate: p6spy or datasource-proxy +// Count SQL executions in tests +assertThat(sqlCount).isLessThanOrEqualTo(2); +``` + +### 3. APM / Database Monitoring Tools + +- **Django Debug Toolbar** — Real-time SQL count and timing display +- **p6spy** (Java) — JDBC layer interception, logs all SQL +- **MiniProfiler** (.NET) — In-page SQL statistics +- **DataDog / New Relic** — Production slow query alerts + +--- + +## General Solutions + +### Solution 1: Eager Loading (JOIN Preload) + +A single JOIN query fetches both main and related records. Suitable for one-to-one, one-to-many. + +### Solution 2: Batch Fetching (IN Clause Batch Query) + +Two queries: main records + `WHERE id IN (...)` to batch fetch related records. Suitable for many-to-many, large datasets. + +### Solution 3: DataLoader Pattern + +In GraphQL or complex graph query scenarios, collect all needed IDs and merge them into a single batch query. + +``` +// DataLoader pseudocode +class DataLoader { + load(K key) → V // Register demand, don't query immediately + loadAll([K]) → [V] // Merge into a single batch query +} +``` + +### Solution 4: Projection + +Query only the needed fields to reduce data transfer: + +```sql +-- ❌ Fetch all columns +SELECT * FROM users JOIN profiles ON ... + +-- ✅ Project only needed fields +SELECT u.name, p.avatar_url FROM users u JOIN profiles p ON ... +``` + +--- + +## Language-Specific Implementations + +### Python / Django + +> See [Django Guide](../django.md#n1-query-optimization) + +```python +# ForeignKey / OneToOne → select_related (SQL JOIN) +books = Book.objects.select_related("publisher") + +# M2M / reverse FK → prefetch_related (2 queries + Python merge) +authors = Author.objects.prefetch_related("books") + +# Nested prefetch +authors = Author.objects.prefetch_related("books__publisher") + +# Prefetch object for fine-grained control +from django.db.models import Prefetch +authors = Author.objects.prefetch_related( + Prefetch("books", queryset=Book.objects.filter(published=True), to_attr="published_books") +) +``` + +### Python / SQLAlchemy (FastAPI) + +> See [FastAPI Guide](../fastapi.md#database-sessions--n1) + +```python +from sqlalchemy.orm import selectinload + +# selectinload: IN clause batch loading (recommended for async scenarios) +stmt = select(Order).options(selectinload(Order.customer)) + +# joinedload: JOIN loading +stmt = select(Order).options(joinedload(Order.customer)) +``` + +### Java / JPA (Spring Boot) + +> See [Java Guide](../java.md) + +```java +// ❌ FetchType.EAGER or triggering lazy loading in a loop +@OneToMany(fetch = FetchType.EAGER) // dangerous! + +// ✅ JOIN FETCH +@Query("SELECT u FROM User u JOIN FETCH u.orders") +List findAllWithOrders(); + +// ✅ @EntityGraph (declarative) +@EntityGraph(attributePaths = {"orders", "profile"}) +List findAll(); + +// ✅ @BatchSize (reduces N+1 to N/batchSize + 1) +@OneToMany +@BatchSize(size = 50) +private List orders; +``` + +### C# / EF Core + +> See [C# Guide](../csharp.md) + +```csharp +// ❌ N+1: foreach triggers lazy loading +foreach (var blog in await context.Blogs.ToListAsync()) + foreach (var post in blog.Posts) // queries on every iteration! + +// ✅ Include + ThenInclude +var blogs = await context.Blogs + .Include(b => b.Posts) + .ToListAsync(); + +// ✅ Projection (safest, avoids over-fetching) +var data = await context.Blogs + .Select(b => new { b.Url, PostTitles = b.Posts.Select(p => p.Title) }) + .ToListAsync(); +``` + +### PHP / Laravel / Doctrine + +> See [PHP Guide](../php.md) + +```php +// ❌ Querying inside a loop +foreach ($orders as $order) { + $customer = $customerRepo->find($order->customerId); + render($order, $customer); +} + +// ✅ Batch preloading +$customerIds = array_unique(array_map(fn($o) => $o->customerId, $orders)); +$customers = $customerRepo->findByIds($customerIds); + +foreach ($orders as $order) { + render($order, $customers[$order->customerId] ?? null); +} + +// Laravel Eloquent: with() +$orders = Order::with('customer')->get(); + +// Doctrine: JOIN FETCH +$dql = 'SELECT o, c FROM Order o JOIN o.customer c'; +``` + +### TypeScript / Prisma + +```typescript +// ❌ N+1 +const users = await prisma.user.findMany() +for (const user of users) { + user.posts = await prisma.post.findMany({ where: { userId: user.id } }) +} + +// ✅ include (Prisma auto-generates JOIN or batch query) +const users = await prisma.user.findMany({ + include: { posts: true }, +}) + +// ✅ Nested include +const users = await prisma.user.findMany({ + include: { + posts: { + include: { comments: true }, + }, + }, +}) +``` + +--- + +## Review Checklist + +### Detection + +- [ ] SQL logging or query count monitoring enabled +- [ ] Query count assertions in tests +- [ ] APM tool configured with N+1 alerts + +### Fixes + +- [ ] ForeignKey / OneToOne relationships use JOIN eager loading +- [ ] M2M / reverse relationships use IN batch preloading +- [ ] Avoid triggering database queries in loops +- [ ] Use projection to fetch only needed fields + +### Architecture + +- [ ] List APIs are paginated to avoid loading too many records at once +- [ ] GraphQL scenarios use DataLoader +- [ ] Caching strategy (Redis) for high-frequency related data reads diff --git a/.agents/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md b/.agents/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md new file mode 100644 index 0000000..e4d405a --- /dev/null +++ b/.agents/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md @@ -0,0 +1,308 @@ +# SQL Injection Prevention Guide + +Language-agnostic SQL injection prevention strategies with cross-language code examples. + +> **Related**: [Security Review Guide](../security-review-guide.md) for comprehensive security checklist and decision framework. + +## Attack Types + +SQL injection (SQLi) is ranked #3 in the OWASP Top 10 (2021). Three common variants: + +| Type | Description | Risk | +|------|-------------|------| +| **Classic (In-band)** | Attacker receives results directly in the HTTP response | Data exfiltration, authentication bypass | +| **Blind (Boolean/Time-based)** | Attacker infers data from response differences or timing | Slower but still viable for data extraction | +| **Out-of-band** | Attacker uses DNS/HTTP callbacks to exfiltrate data | Less common but harder to detect | + +## Universal Prevention Strategy + +1. **Parameterized queries** — always (the #1 defense) +2. **ORM safe usage** — understand what your ORM escapes +3. **Input validation** — whitelist over blacklist +4. **Least privilege** — database user with minimal permissions +5. **WAF** — web application firewall as defense-in-depth + +--- + +## Cross-Language Examples + +### Python + +```python +# ❌ Vulnerable: string formatting +query = f"SELECT * FROM users WHERE id = {user_id}" +cursor.execute(query) + +# ❌ Vulnerable: % formatting +cursor.execute("SELECT * FROM users WHERE id = %s" % user_id) + +# ✅ Parameterized (DB-API) +cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) + +# ✅ SQLAlchemy ORM +User.query.filter(User.id == user_id).all() + +# ❌ SQLAlchemy raw SQL with string interpolation +session.execute(text(f"SELECT * FROM users WHERE id = {user_id}")) + +# ✅ SQLAlchemy raw SQL with bound parameters +session.execute(text("SELECT * FROM users WHERE id = :id"), {"id": user_id}) + +# ✅ Django ORM +User.objects.filter(id=user_id) + +# ❌ Django extra() with string interpolation +User.objects.extra(where=[f"username = '{username}'"]) + +# ✅ Django raw() with parameters +User.objects.raw("SELECT * FROM users WHERE id = %s", [user_id]) +``` + +### Java + +```java +// ❌ Vulnerable: string concatenation +String query = "SELECT * FROM users WHERE id = " + userId; +Statement stmt = connection.createStatement(); +ResultSet rs = stmt.executeQuery(query); + +// ✅ JDBC PreparedStatement +String query = "SELECT * FROM users WHERE id = ?"; +PreparedStatement stmt = connection.prepareStatement(query); +stmt.setLong(1, userId); +ResultSet rs = stmt.executeQuery(); + +// ✅ JPA parameter binding +@Query("SELECT u FROM User u WHERE u.id = :id") +User findById(@Param("id") Long id); + +// ✅ Spring Data JPA method naming +User findById(Long id); + +// ❌ JPA native query with string concatenation +entityManager.createNativeQuery( + "SELECT * FROM users WHERE name = '" + name + "'" +); + +// ✅ JPA native query with parameter binding +Query query = entityManager.createNativeQuery( + "SELECT * FROM users WHERE name = :name" +); +query.setParameter("name", name); +``` + +### Go + +```go +// ❌ Vulnerable: fmt.Sprintf +query := fmt.Sprintf("SELECT * FROM users WHERE id = %s", userID) +rows, err := db.Query(query) + +// ✅ database/sql parameterized +rows, err := db.Query("SELECT * FROM users WHERE id = ?", userID) + +// ✅ Named parameters (sqlx) +rows, err := db.NamedQuery( + "SELECT * FROM users WHERE id = :id", + map[string]interface{}{"id": userID}, +) + +// ⚠️ Dynamic identifiers (table/column names) can't use placeholders +// Must validate against whitelist +var allowedColumns = map[string]bool{ + "id": true, "name": true, "email": true, "created_at": true, +} + +func queryWithOrder(db *sql.DB, orderBy string) (*sql.Rows, error) { + if !allowedColumns[orderBy] { + return nil, fmt.Errorf("invalid column: %s", orderBy) + } + return db.Query( + fmt.Sprintf("SELECT * FROM users ORDER BY %s", orderBy), + ) +} +``` + +### Node.js + +```typescript +// ❌ Vulnerable: template literal +const query = `SELECT * FROM users WHERE id = ${userId}`; +const result = await client.query(query); + +// ✅ pg parameterized ($1, $2, ...) +const result = await client.query( + "SELECT * FROM users WHERE id = $1", + [userId] +); + +// ✅ Prisma ORM (parameterized by default) +const user = await prisma.user.findUnique({ + where: { id: userId }, +}); + +// ❌ Prisma $queryRawUnsafe with string interpolation +await prisma.$queryRawUnsafe( + `SELECT * FROM users WHERE id = ${userId}` +); + +// ✅ Prisma $queryRaw with tagged template (safe) +await prisma.$queryRaw` + SELECT * FROM users WHERE id = ${userId} +`; +``` + +### PHP + +```php +query($sql)->fetch(); + +// ✅ PDO prepared statements +$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email"); +$stmt->execute(['email' => $email]); +$user = $stmt->fetch(PDO::FETCH_ASSOC); + +// ✅ PDO positional placeholders +$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$id]); + +// ❌ mysqli with string interpolation +$result = mysqli_query($conn, + "SELECT * FROM users WHERE id = " . $id +); + +// ✅ mysqli prepared statements +$stmt = mysqli_prepare($conn, "SELECT * FROM users WHERE id = ?"); +mysqli_stmt_bind_param($stmt, "i", $id); +mysqli_stmt_execute($stmt); + +// ✅ Laravel Eloquent ORM +User::where('id', $id)->first(); + +// ❌ Laravel DB::raw with interpolation +DB::select(DB::raw("SELECT * FROM users WHERE id = {$id}")); + +// ✅ Laravel parameterized raw +DB::select("SELECT * FROM users WHERE id = ?", [$id]); +``` + +### C# / .NET + +```csharp +// ❌ Vulnerable: string concatenation +var query = $"SELECT * FROM Users WHERE Id = {userId}"; +using var cmd = new SqlCommand(query, connection); +var reader = cmd.ExecuteReader(); + +// ✅ ADO.NET parameterized +var query = "SELECT * FROM Users WHERE Id = @Id"; +using var cmd = new SqlCommand(query, connection); +cmd.Parameters.AddWithValue("@Id", userId); + +// ✅ Dapper parameterized +var users = connection.Query( + "SELECT * FROM Users WHERE Id = @Id", + new { Id = userId } +); + +// ❌ Dapper with string interpolation +var users = connection.Query( + $"SELECT * FROM Users WHERE Id = {userId}" +); + +// ✅ EF Core (parameterized by default) +var user = await context.Users + .Where(u => u.Id == userId) + .FirstOrDefaultAsync(); + +// ❌ EF Core FromSqlRaw with interpolation +var users = context.Users + .FromSqlRaw($"SELECT * FROM Users WHERE Id = {userId}") + .ToList(); + +// ✅ EF Core FromSql with FormattableString (parameterized) +var users = context.Users + .FromSql($"SELECT * FROM Users WHERE Id = {userId}") + .ToList(); +``` + +--- + +## ORM Unsafe Usage Patterns + +ORMs do NOT automatically prevent SQL injection in all cases: + +```python +# ❌ SQLAlchemy: text() with f-string +session.execute(text(f"SELECT * FROM users WHERE id = {user_id}")) + +# ❌ Django: extra() / RawSQL() with string interpolation +User.objects.extra(where=[f"username = '{username}'"]) +User.objects.annotate( + val=RawSQL(f"SELECT col FROM other WHERE id = {user_id}") +) + +# ❌ JPA: createNativeQuery with string concatenation +entityManager.createNativeQuery("SELECT * FROM users WHERE name = '" + name + "'") + +# ❌ EF Core: FromSqlRaw with string interpolation +context.Users.FromSqlRaw($"SELECT * FROM Users WHERE Id = {userId}") +``` + +**Rule**: Every ORM has a "raw SQL" escape hatch. String interpolation in that escape hatch = SQL injection. Always use the ORM's parameter binding mechanism. + +--- + +## Dynamic Identifiers (Table/Column Names) + +Placeholders can only bind **values**, not table names, column names, or SQL keywords. For dynamic identifiers: + +```python +# ✅ Whitelist validation +ALLOWED_COLUMNS = {"id", "name", "email", "created_at"} +ALLOWED_DIRECTIONS = {"ASC", "DESC"} + +def get_users(order_by: str, direction: str) -> list[User]: + if order_by not in ALLOWED_COLUMNS: + raise ValueError(f"Invalid column: {order_by}") + if direction.upper() not in ALLOWED_DIRECTIONS: + raise ValueError(f"Invalid direction: {direction}") + + return User.objects.order_by( + f"{'-' if direction.upper() == 'DESC' else ''}{order_by}" + ) +``` + +--- + +## Detection & Testing + +```bash +# Automated scanning +sqlmap -u "https://example.com/api/users?id=1" --batch + +# Static analysis (Python) +bandit -r src/ -f custom + +# Static analysis (Java) +spotbugs -textui build/classes + +# Code review keywords to search for +grep -rn "f\".*SELECT\|f'.*SELECT\|fmt.Sprintf.*SELECT\|format.*SELECT" src/ +grep -rn "query.*\+.*\|query.*&\|query.*concat" src/ +``` + +--- + +## Review Checklist + +- [ ] All SQL queries use parameterized queries (no string interpolation) +- [ ] ORM raw SQL methods use bound parameters, not string formatting +- [ ] Dynamic identifiers (table/column names) validated against whitelist +- [ ] Database user has least privilege (no DROP/ALTER for app user) +- [ ] No SQL queries constructed from user input without parameterization +- [ ] Static analysis tools (Bandit, SpotBugs, SonarQube) run in CI \ No newline at end of file diff --git a/.agents/skills/code-review-skill/reference/cross-cutting/xss-prevention.md b/.agents/skills/code-review-skill/reference/cross-cutting/xss-prevention.md new file mode 100644 index 0000000..f5b48bb --- /dev/null +++ b/.agents/skills/code-review-skill/reference/cross-cutting/xss-prevention.md @@ -0,0 +1,264 @@ +# XSS Prevention Guide + +Language-agnostic Cross-Site Scripting prevention strategies with cross-framework code examples. + +> **Related**: [Security Review Guide](../security-review-guide.md) for comprehensive security checklist and decision framework. + +## XSS Types + +XSS is ranked #3 in the OWASP Top 10 (2021, merged with Injection). Three variants: + +| Type | Description | Attack Vector | +|------|-------------|---------------| +| **Reflected** | Malicious script reflected off the server in the response | URL parameters, form submissions | +| **Stored (Persistent)** | Malicious script stored in the database and served to users | Comments, profiles, messages | +| **DOM-based** | Client-side JavaScript modifies the DOM unsafely | `innerHTML`, `document.write()`, `eval()` | + +## Universal Prevention Strategy + +1. **Output encoding** — encode data for the context it's rendered in (HTML, JS, URL, CSS) +2. **Content Security Policy (CSP)** — restrict which scripts can execute +3. **Input sanitization** — only when rich text is required (DOMPurify) +4. **Framework auto-escaping** — rely on framework defaults, audit escape hatches + +> **Key distinction**: Input validation prevents bad data from entering the system. Output encoding prevents bad data from being rendered as code. Both are necessary; neither alone is sufficient. + +--- + +## Cross-Framework Examples + +### React + +```typescript +// ✅ React auto-escapes JSX expressions (default safe) +return
{userInput}
; + +// ❌ dangerouslySetInnerHTML bypasses escaping +return
; + +// ✅ If HTML is required, sanitize first +import DOMPurify from 'dompurify'; +return
; + +// ❌ href with javascript: protocol +return Click; + +// ✅ Validate URL protocol +const safeUrl = userInput.startsWith('https://') ? userInput : '#'; +return Click; + +// ❌ eval / new Function with user input +const result = eval(userInput); + +// ❌ innerHTML in refs / effects +useEffect(() => { + ref.current.innerHTML = userInput; +}, [userInput]); +``` + +### Vue + +```html + +
{{ userInput }}
+ + +
+ + +
+``` + +```typescript +import DOMPurify from 'dompurify'; + +export default { + methods: { + sanitized(input: string): string { + return DOMPurify.sanitize(input); + } + } +}; + +// ❌ v-bind:href with javascript: protocol +// Click — userInput could be "javascript:alert(1)" +``` + +### Angular + +```typescript +// ✅ Angular auto-escapes interpolation (default safe) +template: `
{{ userInput }}
` + +// ❌ bypassSecurityTrustHtml disables sanitization +import { DomSanitizer } from '@angular/platform-browser'; + +constructor(private sanitizer: DomSanitizer) { + this.unsafe = this.sanitizer.bypassSecurityTrustHtml(userInput); +} + +// ❌ bypassSecurityTrustUrl with javascript: protocol +this.unsafeUrl = this.sanitizer.bypassSecurityTrustUrl(userInput); + +// ✅ Only use bypassSecurityTrust* with server-validated content +// and document the reason +``` + +### Svelte + +```svelte + +
{userInput}
+ + +
{@html userInput}
+ + + +
{@html sanitized}
+``` + +### Django (Server-Side) + +```python +# ✅ Django auto-escapes template variables +# template:

{{ user_bio }}

+ +# ❌ mark_safe bypasses auto-escaping +from django.utils.safestring import mark_safe +return HttpResponse(mark_safe(f"

{user_bio}

")) + +# ❌ autoescape off in template +# {% autoescape off %}{{ user_bio }}{% endautoescape %} + +# ✅ If mark_safe is necessary, escape first +from django.utils.html import escape +return HttpResponse(mark_safe(f"

{escape(user_bio)}

")) +``` + +### Server-Side Rendering + +```typescript +// ❌ SSR: injecting raw user data into HTML +const html = `
${userInput}
`; + +// ✅ Always escape server-side rendered content +import escapeHtml from 'escape-html'; +const html = `
${escapeHtml(userInput)}
`; + +// ❌ JSON serialization without escaping +const json = JSON.stringify({ name: userInput }); +// userInput could contain to break out of script tags + +// ✅ JSON in HTML: escape < and > +const safe = JSON.stringify({ name: userInput }) + .replace(//g, '\\u003e'); +``` + +--- + +## Content Security Policy (CSP) + +CSP is defense-in-depth. Even if XSS escapes output encoding, CSP limits what an attacker can do. + +```nginx +# ✅ Recommended CSP (strict) +Content-Security-Policy: + default-src 'self'; + script-src 'self' 'nonce-{random}' 'strict-dynamic'; + style-src 'self' 'unsafe-inline'; + img-src 'self' data: https:; + object-src 'none'; + base-uri 'self'; + form-action 'self'; + frame-ancestors 'none'; +``` + +```typescript +// ✅ Express middleware +import helmet from 'helmet'; + +app.use(helmet.contentSecurityPolicy({ + directives: { + defaultSrc: ["'self'"], + scriptSrc: ["'self'", "'nonce-{random}'"], + styleSrc: ["'self'", "'unsafe-inline'"], + objectSrc: ["'none'"], + baseUri: ["'self'"], + formAction: ["'self'"], + frameAncestors: ["'none'"], + }, +})); +``` + +```html + + + + + + + + +``` + +**CSP anti-patterns to avoid:** +- `script-src 'unsafe-inline'` without nonce/hash +- `script-src 'unsafe-eval'` (enables `eval()`) +- `default-src *` (allows loading from any origin) +- `script-src https:` (allows any HTTPS origin, including attacker-controlled) + +--- + +## Input Validation vs Output Encoding + +| Layer | What | When | Example | +|-------|------|------|---------| +| **Input validation** | Reject/clean data on entry | At API boundary | Reject ` + +" onmouseover="alert(1) +javascript:alert(1) +'-alert(1)-' + +# Static analysis (code review) +grep -rn "innerHTML\|dangerouslySetInnerHTML\|v-html\|bypassSecurityTrust\|mark_safe\|@html\|{@html" src/ +grep -rn "eval(\|new Function\|document.write\|setTimeout.*string\|setInterval.*string" src/ +``` + +--- + +## Review Checklist + +- [ ] Framework auto-escaping is relied upon by default (no manual escaping) +- [ ] `dangerouslySetInnerHTML` / `v-html` / `bypassSecurityTrust` / `{@html}` / `mark_safe` are audited +- [ ] All HTML rendering escape hatches are preceded by `DOMPurify.sanitize()` or equivalent +- [ ] CSP is configured with nonce-based or hash-based script-src +- [ ] No `eval()`, `new Function()`, or `javascript:` URLs with user input +- [ ] No inline event handlers (`onclick="..."`) when CSP is enabled +- [ ] Server-side rendered content is escaped before injection +- [ ] JSON in HTML is properly escaped (`` → `\u003c/script\u003e`) \ No newline at end of file diff --git a/.agents/skills/code-review-skill/reference/performance-review-guide.md b/.agents/skills/code-review-skill/reference/performance-review-guide.md new file mode 100644 index 0000000..dbc532a --- /dev/null +++ b/.agents/skills/code-review-skill/reference/performance-review-guide.md @@ -0,0 +1,829 @@ +# Performance Review Guide + +Performance review guide covering frontend, backend, database, algorithmic complexity, and API performance. + +## Table of Contents + +- [Frontend Performance (Core Web Vitals)](#frontend-performance-core-web-vitals) +- [JavaScript Performance](#javascript-performance) +- [Memory Management](#memory-management) +- [Database Performance](#database-performance) +- [API Performance](#api-performance) +- [Algorithmic Complexity](#algorithmic-complexity) +- [Performance Review Checklist](#performance-review-checklist) + +--- + +## Frontend Performance (Core Web Vitals) + +### 2024 Core Metrics + +| Metric | Full Name | Target | Meaning | +| ------- | ------------------------- | ------- | ------------------------------------------------ | +| **LCP** | Largest Contentful Paint | ≤ 2.5s | Largest content paint time | +| **INP** | Interaction to Next Paint | ≤ 200ms | Interaction response time (replaced FID in 2024) | +| **CLS** | Cumulative Layout Shift | ≤ 0.1 | Cumulative layout shift | +| **FCP** | First Contentful Paint | ≤ 1.8s | First content paint | +| **TBT** | Total Blocking Time | ≤ 200ms | Main thread blocking time | + +### LCP Optimization Check + +```javascript +// ❌ LCP image lazy-loaded - delays critical content + + +// ✅ LCP image loaded immediately + + +// ❌ Unoptimized image format + // PNG file too large + +// ✅ Modern image format + responsive + + + + Hero + +``` + +**Review points:** + +- [ ] Does the LCP element have `fetchpriority="high"` set? +- [ ] Are WebP/AVIF formats used? +- [ ] Is there server-side rendering or static generation? +- [ ] Is CDN configured correctly? + +### FCP Optimization Check + +```html + + + + + + + + +@font-face { font-family: 'CustomFont'; src: url('font.woff2'); } + + +@font-face { font-family: 'CustomFont'; src: url('font.woff2'); font-display: +swap; /* Use system font first, switch after load */ } +``` + +### INP Optimization Check + +```javascript +// ❌ Long task blocks main thread +button.addEventListener('click', () => { + // 500ms synchronous operation + processLargeData(data) + updateUI() +}) + +// ✅ Split long tasks +button.addEventListener('click', async () => { + // Yield to main thread + ;(await scheduler.yield?.()) ?? new Promise((r) => setTimeout(r, 0)) + + // Process in batches + for (const chunk of chunks) { + processChunk(chunk) + await scheduler.yield?.() + } + updateUI() +}) + +// ✅ Use Web Worker for heavy computation +const worker = new Worker('heavy-computation.js') +worker.postMessage(data) +worker.onmessage = (e) => updateUI(e.data) +``` + +### CLS Optimization Check + +```css +/* ❌ Media without specified dimensions */ +img { + width: 100%; +} + +/* ✅ Reserve space */ +img { + width: 100%; + aspect-ratio: 16 / 9; +} + +/* ❌ Dynamic content insertion causing layout shift */ +.ad-container { +} + +/* ✅ Reserve fixed height */ +.ad-container { + min-height: 250px; +} +``` + +**CLS Review Checklist:** + +- [ ] Do images/videos have width/height or aspect-ratio? +- [ ] Does font loading use `font-display: swap`? +- [ ] Is space reserved for dynamic content? +- [ ] Is content insertion above existing content avoided? + +--- + +## JavaScript Performance + +### Code Splitting and Lazy Loading + +```javascript +// ❌ Load all code at once +import { HeavyChart } from './charts' +import { PDFExporter } from './pdf' +import { AdminPanel } from './admin' + +// ✅ Load on demand +const HeavyChart = lazy(() => import('./charts')) +const PDFExporter = lazy(() => import('./pdf')) + +// ✅ Route-level code splitting +const routes = [ + { + path: '/dashboard', + component: lazy(() => import('./pages/Dashboard')), + }, + { + path: '/admin', + component: lazy(() => import('./pages/Admin')), + }, +] +``` + +### Bundle Size Optimization + +```javascript +// ❌ Import entire library +import _ from 'lodash' +import moment from 'moment' + +// ✅ Import on demand +import debounce from 'lodash/debounce' +import { format } from 'date-fns' + +// ❌ No Tree Shaking +export default { + fn1() {}, + fn2() {}, // unused but still bundled +} + +// ✅ Named exports support Tree Shaking +export function fn1() {} +export function fn2() {} +``` + +**Bundle Review Checklist:** + +- [ ] Is dynamic import() used for code splitting? +- [ ] Are large libraries imported on demand? +- [ ] Has bundle size been analyzed? (webpack-bundle-analyzer) +- [ ] Are there unused dependencies? + +### List Rendering Optimization + +```javascript +// ❌ Rendering large lists +function List({ items }) { + return ( +
    + {items.map((item) => ( +
  • {item.name}
  • + ))} +
+ ) // 10000 items = 10000 DOM nodes +} + +// ✅ Virtual list - only render visible items +import { FixedSizeList } from 'react-window' + +function VirtualList({ items }) { + return ( + + {({ index, style }) =>
{items[index].name}
} +
+ ) +} +``` + +**Large Data Review Points:** + +- [ ] Do lists with more than 100 items use virtual scrolling? +- [ ] Do tables support pagination or virtualization? +- [ ] Is there unnecessary full rendering? + +--- + +## Memory Management + +### Common Memory Leaks + +#### 1. Unremoved Event Listeners + +```javascript +// ❌ Event still listening after component unmount +useEffect(() => { + window.addEventListener('resize', handleResize) +}, []) + +// ✅ Clean up event listener +useEffect(() => { + window.addEventListener('resize', handleResize) + return () => window.removeEventListener('resize', handleResize) +}, []) +``` + +#### 2. Un cleaned Timers + +```javascript +// ❌ Timer not cleaned up +useEffect(() => { + setInterval(fetchData, 5000) +}, []) + +// ✅ Clean up timer +useEffect(() => { + const timer = setInterval(fetchData, 5000) + return () => clearInterval(timer) +}, []) +``` + +#### 3. Closure References + +```javascript +// ❌ Closure holds large object reference +function createHandler() { + const largeData = new Array(1000000).fill('x') + + return function handler() { + // largeData is referenced by closure, cannot be garbage collected + console.log(largeData.length) + } +} + +// ✅ Only keep necessary data +function createHandler() { + const largeData = new Array(1000000).fill('x') + const length = largeData.length // Only keep the needed value + + return function handler() { + console.log(length) + } +} +``` + +#### 4. Un cleaned Subscriptions + +```javascript +// ❌ WebSocket/EventSource not closed +useEffect(() => { + const ws = new WebSocket('wss://...') + ws.onmessage = handleMessage +}, []) + +// ✅ Clean up connection +useEffect(() => { + const ws = new WebSocket('wss://...') + ws.onmessage = handleMessage + return () => ws.close() +}, []) +``` + +### Memory Review Checklist + +```markdown +- [ ] Do all useEffects have cleanup functions? +- [ ] Are event listeners removed on component unmount? +- [ ] Are timers cleaned up? +- [ ] Are WebSocket/SSE connections closed? +- [ ] Are large objects released promptly? +- [ ] Are there global variables accumulating data? +``` + +### Detection Tools + +| Tool | Purpose | +| ---------------------- | ------------------------------- | +| Chrome DevTools Memory | Heap snapshot analysis | +| MemLab (Meta) | Automated memory leak detection | +| Performance Monitor | Real-time memory monitoring | + +--- + +## Database Performance + +### N+1 Query Problem + +```python +# ❌ N+1 problem - 1 + N queries +users = User.objects.all() # 1 query +for user in users: + print(user.profile.bio) # N queries (one per user) + +# ✅ Eager Loading - 2 queries +users = User.objects.select_related('profile').all() +for user in users: + print(user.profile.bio) # no extra queries + +# ✅ Use prefetch_related for many-to-many +posts = Post.objects.prefetch_related('tags').all() +``` + +```javascript +// TypeORM example +// ❌ N+1 problem +const users = await userRepository.find() +for (const user of users) { + const posts = await user.posts // queries on every iteration +} + +// ✅ Eager Loading +const users = await userRepository.find({ + relations: ['posts'], +}) +``` + +### Index Optimization + +```sql +-- ❌ Full table scan +SELECT * FROM orders WHERE status = 'pending'; + +-- ✅ Add index +CREATE INDEX idx_orders_status ON orders(status); + +-- ❌ Index invalidated: function operation +SELECT * FROM users WHERE YEAR(created_at) = 2024; + +-- ✅ Range query can use index +SELECT * FROM users +WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'; + +-- ❌ Index invalidated: LIKE prefix wildcard +SELECT * FROM products WHERE name LIKE '%phone%'; + +-- ✅ Prefix match can use index +SELECT * FROM products WHERE name LIKE 'phone%'; +``` + +### Query Optimization + +```sql +-- ❌ SELECT * fetches unnecessary columns +SELECT * FROM users WHERE id = 1; + +-- ✅ Only query needed columns +SELECT id, name, email FROM users WHERE id = 1; + +-- ❌ Large table without LIMIT +SELECT * FROM logs WHERE type = 'error'; + +-- ✅ Paginated query +SELECT * FROM logs WHERE type = 'error' LIMIT 100 OFFSET 0; + +-- ❌ Executing queries in a loop +for id in user_ids: + cursor.execute("SELECT * FROM users WHERE id = %s", (id,)) + +-- ✅ Batch query +cursor.execute("SELECT * FROM users WHERE id IN %s", (tuple(user_ids),)) +``` + +### Database Review Checklist + +```markdown +🔴 Must check: + +- [ ] Are there N+1 queries? +- [ ] Do WHERE clause columns have indexes? +- [ ] Is SELECT \* avoided? +- [ ] Do large table queries have LIMIT? + +🟡 Recommended checks: + +- [ ] Is EXPLAIN used to analyze query plans? +- [ ] Is composite index column order correct? +- [ ] Are there unused indexes? +- [ ] Is there slow query log monitoring? +``` + +--- + +## API Performance + +### Pagination Implementation + +```javascript +// ❌ Return all data +app.get('/users', async (req, res) => { + const users = await User.findAll() // could return 100000 records + res.json(users) +}) + +// ✅ Pagination + max limit +app.get('/users', async (req, res) => { + const page = parseInt(req.query.page) || 1 + const limit = Math.min(parseInt(req.query.limit) || 20, 100) // max 100 + const offset = (page - 1) * limit + + const { rows, count } = await User.findAndCountAll({ + limit, + offset, + order: [['id', 'ASC']], + }) + + res.json({ + data: rows, + pagination: { + page, + limit, + total: count, + totalPages: Math.ceil(count / limit), + }, + }) +}) +``` + +### Caching Strategy + +```javascript +// ✅ Redis cache example +async function getUser(id) { + const cacheKey = `user:${id}` + + // 1. Check cache + const cached = await redis.get(cacheKey) + if (cached) { + return JSON.parse(cached) + } + + // 2. Query database + const user = await db.users.findById(id) + + // 3. Write to cache (set expiration) + await redis.setex(cacheKey, 3600, JSON.stringify(user)) + + return user +} + +// ✅ HTTP cache headers +app.get('/static-data', (req, res) => { + res.set({ + 'Cache-Control': 'public, max-age=86400', // 24 hours + ETag: 'abc123', + }) + res.json(data) +}) +``` + +### Response Compression + +```javascript +// ✅ Enable Gzip/Brotli compression +const compression = require('compression') +app.use(compression()) + +// ✅ Only return necessary fields +// Request: GET /users?fields=id,name,email +app.get('/users', async (req, res) => { + const fields = req.query.fields?.split(',') || ['id', 'name'] + const users = await User.findAll({ + attributes: fields, + }) + res.json(users) +}) +``` + +### Rate Limiting Protection + +```javascript +// ✅ Rate limiting +const rateLimit = require('express-rate-limit') + +const limiter = rateLimit({ + windowMs: 60 * 1000, // 1 minute + max: 100, // max 100 requests + message: { error: 'Too many requests, please try again later.' }, +}) + +app.use('/api/', limiter) +``` + +### API Review Checklist + +```markdown +- [ ] Do list endpoints have pagination? +- [ ] Is there a max per-page limit? +- [ ] Is hot data cached? +- [ ] Is response compression enabled? +- [ ] Is there rate limiting? +- [ ] Are only necessary fields returned? +``` + +--- + +## Algorithmic Complexity + +### Common Complexity Comparison + +| Complexity | Name | 10 items | 1000 items | 1 million items | Example | +| ---------- | ------------ | -------- | ---------- | --------------- | ------------------- | +| O(1) | Constant | 1 | 1 | 1 | Hash lookup | +| O(log n) | Logarithmic | 3 | 10 | 20 | Binary search | +| O(n) | Linear | 10 | 1000 | 1 million | Array traversal | +| O(n log n) | Linearithmic | 33 | 10000 | 20 million | Quicksort | +| O(n²) | Quadratic | 100 | 1 million | 1 trillion | Nested loops | +| O(2ⁿ) | Exponential | 1024 | ∞ | ∞ | Recursive Fibonacci | + +### Identification in Code Review + +```javascript +// ❌ O(n²) - nested loops +function findDuplicates(arr) { + const duplicates = [] + for (let i = 0; i < arr.length; i++) { + for (let j = i + 1; j < arr.length; j++) { + if (arr[i] === arr[j]) { + duplicates.push(arr[i]) + } + } + } + return duplicates +} + +// ✅ O(n) - using Set +function findDuplicates(arr) { + const seen = new Set() + const duplicates = new Set() + for (const item of arr) { + if (seen.has(item)) { + duplicates.add(item) + } + seen.add(item) + } + return [...duplicates] +} +``` + +```javascript +// ❌ O(n²) - calling includes on every iteration +function removeDuplicates(arr) { + const result = [] + for (const item of arr) { + if (!result.includes(item)) { + // includes is O(n) + result.push(item) + } + } + return result +} + +// ✅ O(n) - using Set +function removeDuplicates(arr) { + return [...new Set(arr)] +} +``` + +```javascript +// ❌ O(n) lookup - traversing every time +const users = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }, ...]; + +function getUser(id) { + return users.find(u => u.id === id); // O(n) +} + +// ✅ O(1) lookup - using Map +const userMap = new Map(users.map(u => [u.id, u])); + +function getUser(id) { + return userMap.get(id); // O(1) +} +``` + +### Space Complexity Considerations + +```javascript +// ⚠️ O(n) space - creates new array +const doubled = arr.map((x) => x * 2) + +// ✅ O(1) space - in-place modification (if allowed) +for (let i = 0; i < arr.length; i++) { + arr[i] *= 2 +} + +// ⚠️ Excessive recursion depth may cause stack overflow +function factorial(n) { + if (n <= 1) return 1 + return n * factorial(n - 1) // O(n) stack space +} + +// ✅ Iterative version O(1) space +function factorial(n) { + let result = 1 + for (let i = 2; i <= n; i++) { + result *= i + } + return result +} +``` + +### Complexity Review Questions + +```markdown +💡 "This nested loop has O(n²) complexity, will have performance issues with large data" +🔴 "Using Array.includes() in a loop here is O(n²) overall, suggest using Set" +🟡 "This recursion depth may cause stack overflow, suggest converting to iteration or tail recursion" +``` + +--- + +## Performance Review Checklist + +### 🔴 Must Check (Blocking Level) + +**Frontend:** + +- [ ] Are LCP images lazy-loaded? (should not be) +- [ ] Is there `transition: all`? +- [ ] Are width/height/top/left animated? +- [ ] Are lists >100 items virtualized? + +**Backend:** + +- [ ] Are there N+1 queries? +- [ ] Do list endpoints have pagination? +- [ ] Is there SELECT \* on large tables? + +**General:** + +- [ ] Are there O(n²) or worse nested loops? +- [ ] Do useEffects/event listeners have cleanup? + +### 🟡 Recommended Checks (Important Level) + +**Frontend:** + +- [ ] Is code splitting used? +- [ ] Are large libraries imported on demand? +- [ ] Are images using WebP/AVIF? +- [ ] Are there unused dependencies? + +**Backend:** + +- [ ] Is hot data cached? +- [ ] Do WHERE columns have indexes? +- [ ] Is there slow query monitoring? + +**API:** + +- [ ] Is response compression enabled? +- [ ] Is there rate limiting? +- [ ] Are only necessary fields returned? + +### 🟢 Optimization Suggestions (Recommended Level) + +- [ ] Has bundle size been analyzed? +- [ ] Is CDN used? +- [ ] Is there performance monitoring? +- [ ] Have performance benchmarks been done? + +--- + +## Performance Measurement Thresholds + +### Frontend Metrics + +| Metric | Good | Needs Improvement | Poor | +| ---------------- | ------- | ----------------- | ------- | +| LCP | ≤ 2.5s | 2.5-4s | > 4s | +| INP | ≤ 200ms | 200-500ms | > 500ms | +| CLS | ≤ 0.1 | 0.1-0.25 | > 0.25 | +| FCP | ≤ 1.8s | 1.8-3s | > 3s | +| Bundle Size (JS) | < 200KB | 200-500KB | > 500KB | + +### Backend Metrics + +| Metric | Good | Needs Improvement | Poor | +| ----------------- | ------- | ----------------- | ------- | +| API Response Time | < 100ms | 100-500ms | > 500ms | +| Database Query | < 50ms | 50-200ms | > 200ms | +| Page Load | < 3s | 3-5s | > 5s | + +--- + +## Tool Recommendations + +### Frontend Performance + +| Tool | Purpose | +| -------------------------------------------------------------------------------------- | ----------------------------- | +| [Lighthouse](https://developer.chrome.com/docs/lighthouse/) | Core Web Vitals testing | +| [WebPageTest](https://www.webpagetest.org/) | Detailed performance analysis | +| [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) | Bundle analysis | +| [Chrome DevTools Performance](https://developer.chrome.com/docs/devtools/performance/) | Runtime performance analysis | + +### Memory Detection + +| Tool | Purpose | +| ----------------------------------------------------- | ------------------------------- | +| [MemLab](https://github.com/facebookincubator/memlab) | Automated memory leak detection | +| Chrome Memory Tab | Heap snapshot analysis | + +### Backend Performance + +| Tool | Purpose | +| -------------------------------------------------------------------------- | --------------------------------- | +| EXPLAIN | Database query plan analysis | +| [pganalyze](https://pganalyze.com/) | PostgreSQL performance monitoring | +| [New Relic](https://newrelic.com/) / [Datadog](https://www.datadoghq.com/) | APM monitoring | + +--- + +## Low-Level Efficiency Anti-Patterns + +Code-level efficiency mistakes, independent of architecture-level performance issues. Complements resource management and concurrency defects already covered in [common-bugs-checklist.md](common-bugs-checklist.md). + +### Unnecessary Repeated Work + +- [ ] Is the same function / query called repeatedly within the same request/render? +- [ ] Are files / configs read repeatedly inside a loop (loop-invariant)? +- [ ] Can computation results be cached or passed downstream? + +```typescript +// ❌ loop-invariant executed repeatedly inside loop +for (const path of paths) { + const config = JSON.parse(fs.readFileSync('config.json', 'utf-8')) + processFile(path, config) +} + +// ✅ Hoist outside the loop +const config = JSON.parse(fs.readFileSync('config.json', 'utf-8')) +for (const path of paths) processFile(path, config) +``` + +### Missed Concurrency Opportunities + +- [ ] Are independent async operations awaited sequentially? +- [ ] Can `Promise.all` / `asyncio.gather` / `tokio::join!` be used for concurrency? + +```typescript +// ❌ Sequential await +const a = await fetchA() +const b = await fetchB() + +// ✅ Concurrent +const [a, b] = await Promise.all([fetchA(), fetchB()]) +``` + +### Hot Path Bloat + +- [ ] Does module-level / import-time code perform heavy operations (file I/O, network, large object construction)? +- [ ] Does the per-request path have deferrable initialization? +- [ ] Does startup code block the first request? + +### Unbounded Data Structures + +> Resource lifecycle defects (unclosed connections, unremoved listeners, uncleared timers) are covered in [common-bugs-checklist.md → Resource Management](common-bugs-checklist.md#resource-management). This section focuses on _capacity bounds_. + +- [ ] Do global dict / list / caches have a `max-size` or TTL? +- [ ] Do accumulating data structures (queues, logs, metrics buffers) have an upper bound? +- [ ] Are per-request allocated objects persistently referenced and unable to be GC'd? + +```python +# ❌ Unbounded cache +_cache: dict[str, Any] = {} + +# ✅ Bounded LRU +from functools import lru_cache + +@lru_cache(maxsize=256) +def get_cached(key: str) -> Any: + return expensive_computation(key) +``` + +--- + +## Reference Resources + +- [Core Web Vitals - web.dev](https://web.dev/articles/vitals) +- [Optimizing Core Web Vitals - Vercel](https://vercel.com/guides/optimizing-core-web-vitals-in-2024) +- [MemLab - Meta Engineering](https://engineering.fb.com/2022/09/12/open-source/memlab/) +- [Big O Cheat Sheet](https://www.bigocheatsheet.com/) +- [N+1 Query Problem - Stack Overflow](https://stackoverflow.com/questions/97197/what-is-the-n1-selects-problem-in-orm-object-relational-mapping) +- [API Performance Optimization](https://algorithmsin60days.com/blog/optimizing-api-performance/) diff --git a/.agents/skills/code-review-skill/reference/react.md b/.agents/skills/code-review-skill/reference/react.md new file mode 100644 index 0000000..05e08ae --- /dev/null +++ b/.agents/skills/code-review-skill/reference/react.md @@ -0,0 +1,876 @@ +# React Code Review Guide + +React review focus: Hooks rules, appropriateness of performance optimization, component design, and modern React 19/RSC patterns. + +## Table of Contents + +- [Basic Hooks Rules](#basic-hooks-rules) +- [useEffect Patterns](#useeffect-patterns) +- [useMemo / useCallback](#usememo--usecallback) +- [Component Design](#component-design) +- [Error Boundaries & Suspense](#error-boundaries--suspense) +- [Server Components (RSC)](#server-components-rsc) +- [React 19 Actions & Forms](#react-19-actions--forms) +- [Suspense & Streaming SSR](#suspense--streaming-ssr) +- [TanStack Query v5](#tanstack-query-v5) +- [Review Checklists](#review-checklists) + +--- + +## Basic Hooks Rules + +```tsx +// ❌ Conditionally calling Hooks — violates Hooks rules +function BadComponent({ isLoggedIn }) { + if (isLoggedIn) { + const [user, setUser] = useState(null) // Error! + } + return
...
+} + +// ✅ Hooks must be called at the top level of the component +function GoodComponent({ isLoggedIn }) { + const [user, setUser] = useState(null) + if (!isLoggedIn) return + return
{user?.name}
+} +``` + +--- + +## useEffect Patterns + +```tsx +// ❌ Missing or incomplete dependency array +function BadEffect({ userId }) { + const [user, setUser] = useState(null) + useEffect(() => { + fetchUser(userId).then(setUser) + }, []) // Missing userId dependency! +} + +// ✅ Complete dependency array +function GoodEffect({ userId }) { + const [user, setUser] = useState(null) + useEffect(() => { + let cancelled = false + fetchUser(userId).then((data) => { + if (!cancelled) setUser(data) + }) + return () => { + cancelled = true + } // Cleanup function + }, [userId]) +} + +// ❌ useEffect for derived state (anti-pattern) +function BadDerived({ items }) { + const [filteredItems, setFilteredItems] = useState([]) + useEffect(() => { + setFilteredItems(items.filter((i) => i.active)) + }, [items]) // Unnecessary effect + extra render + return +} + +// ✅ Compute directly during render, or use useMemo +function GoodDerived({ items }) { + const filteredItems = useMemo(() => items.filter((i) => i.active), [items]) + return +} + +// ❌ useEffect for event response +function BadEventEffect() { + const [query, setQuery] = useState('') + useEffect(() => { + if (query) { + analytics.track('search', { query }) // Should be in event handler + } + }, [query]) +} + +// ✅ Perform side effects in event handlers +function GoodEvent() { + const [query, setQuery] = useState('') + const handleSearch = (q: string) => { + setQuery(q) + analytics.track('search', { query: q }) + } +} +``` + +--- + +## useMemo / useCallback + +```tsx +// ❌ Over-optimization — constants don't need useMemo +function OverOptimized() { + const config = useMemo(() => ({ timeout: 5000 }), []) // Meaningless + const handleClick = useCallback(() => { + console.log('clicked') + }, []) // Meaningless if not passed to a memo component +} + +// ✅ Only optimize when needed +function ProperlyOptimized() { + const config = { timeout: 5000 } // Define simple objects directly + const handleClick = () => console.log('clicked') +} + +// ❌ useCallback dependency always changes +function BadCallback({ data }) { + // data is a new object every render, useCallback is ineffective + const process = useCallback(() => { + return data.map(transform) + }, [data]) +} + +// ✅ useMemo + useCallback used with React.memo +const MemoizedChild = React.memo(function Child({ onClick, items }) { + return
{items.length}
+}) + +function Parent({ rawItems }) { + const items = useMemo(() => processItems(rawItems), [rawItems]) + const handleClick = useCallback(() => { + console.log(items.length) + }, [items]) + return +} +``` + +--- + +## Component Design + +```tsx +// ❌ Defining components inside components — creates new component every render +function BadParent() { + function ChildComponent() { + // New function every render! + return
child
+ } + return +} + +// ✅ Define components outside +function ChildComponent() { + return
child
+} +function GoodParent() { + return +} + +// ❌ Props are always new object references +function BadProps() { + return ( + {}} // New function every render + /> + ) +} + +// ✅ Stable references +const style = { color: 'red' } +function GoodProps() { + const handleClick = useCallback(() => {}, []) + return +} +``` + +--- + +## Error Boundaries & Suspense + +```tsx +// ❌ No error boundary +function BadApp() { + return ( + }> + {/* Error crashes the entire app */} + + ) +} + +// ✅ Error Boundary wrapping Suspense +function GoodApp() { + return ( + }> + }> + + + + ) +} +``` + +--- + +## Server Components (RSC) + +```tsx +// ❌ Using client features in a Server Component +// app/page.tsx (Server Component by default) +function BadServerComponent() { + const [count, setCount] = useState(0); // Error! No hooks in RSC + return ; +} + +// ✅ Extract interactive logic to a Client Component +// app/counter.tsx +'use client'; +function Counter() { + const [count, setCount] = useState(0); + return ; +} + +// app/page.tsx (Server Component) +async function GoodServerComponent() { + const data = await fetchData(); // Can directly await + return ( +
+

{data.title}

+ {/* Client component */} +
+ ); +} + +// ❌ 'use client' placed incorrectly — entire tree becomes client +// layout.tsx +'use client'; // This makes all child components client components +export default function Layout({ children }) { ... } + +// ✅ Only use 'use client' for components that need interactivity +// Isolate client logic to leaf components +``` + +--- + +## React 19 Actions & Forms + +React 19 introduced the Actions system and new form handling Hooks, simplifying async operations and optimistic updates. + +### useActionState + +```tsx +// ❌ Traditional approach: multiple state variables +function OldForm() { + const [isPending, setIsPending] = useState(false) + const [error, setError] = useState(null) + const [data, setData] = useState(null) + + const handleSubmit = async (formData: FormData) => { + setIsPending(true) + setError(null) + try { + const result = await submitForm(formData) + setData(result) + } catch (e) { + setError(e.message) + } finally { + setIsPending(false) + } + } +} + +// ✅ React 19: useActionState for unified management +import { useActionState } from 'react' + +function NewForm() { + const [state, formAction, isPending] = useActionState( + async (prevState, formData: FormData) => { + try { + const result = await submitForm(formData) + return { success: true, data: result } + } catch (e) { + return { success: false, error: e.message } + } + }, + { success: false, data: null, error: null } + ) + + return ( + + + + {state.error &&

{state.error}

} + + ) +} +``` + +### useFormStatus + +```tsx +// ❌ Prop drilling form status +function BadSubmitButton({ isSubmitting }) { + return +} + +// ✅ useFormStatus accesses parent
status (no props needed) +import { useFormStatus } from 'react-dom' + +function SubmitButton() { + const { pending, data, method, action } = useFormStatus() + // Note: Must be used in a child component inside + return ( + + ) +} + +// ❌ useFormStatus called in the same component as form — doesn't work +function BadForm() { + const { pending } = useFormStatus() // Cannot get status here! + return ( + + +
+ ) +} + +// ✅ useFormStatus must be in a child component of the form +function GoodForm() { + return ( +
+ {/* useFormStatus is called inside here */} + + ) +} +``` + +### useOptimistic + +```tsx +// ❌ Waiting for server response before updating UI +function SlowLike({ postId, likes }) { + const [likeCount, setLikeCount] = useState(likes) + const [isPending, setIsPending] = useState(false) + + const handleLike = async () => { + setIsPending(true) + const newCount = await likePost(postId) // Wait... + setLikeCount(newCount) + setIsPending(false) + } +} + +// ✅ useOptimistic for instant feedback, auto-rollback on failure +import { useOptimistic } from 'react' + +function FastLike({ postId, likes }) { + const [optimisticLikes, addOptimisticLike] = useOptimistic( + likes, + (currentLikes, increment: number) => currentLikes + increment + ) + + const handleLike = async () => { + addOptimisticLike(1) // Update UI immediately + try { + await likePost(postId) // Sync in background + } catch { + // React auto-rolls back to original likes value + } + } + + return +} +``` + +### Server Actions (Next.js 15+) + +```tsx +// ❌ Client-side API call +'use client' +function ClientForm() { + const handleSubmit = async (formData: FormData) => { + const res = await fetch('/api/submit', { + method: 'POST', + body: formData, + }) + // ... + } +} + +// ✅ Server Action + useActionState +// actions.ts +;('use server') +export async function createPost(prevState: any, formData: FormData) { + const title = formData.get('title') + await db.posts.create({ title }) + revalidatePath('/posts') + return { success: true } +} + +// form.tsx +;('use client') +import { createPost } from './actions' + +function PostForm() { + const [state, formAction, isPending] = useActionState(createPost, null) + return ( +
+ + + + ) +} +``` + +--- + +## Suspense & Streaming SSR + +Suspense and Streaming are core features of React 18+, widely used in frameworks like Next.js 15 in 2025. + +### Basic Suspense + +```tsx +// ❌ Traditional loading state management +function OldComponent() { + const [data, setData] = useState(null) + const [isLoading, setIsLoading] = useState(true) + + useEffect(() => { + fetchData() + .then(setData) + .finally(() => setIsLoading(false)) + }, []) + + if (isLoading) return + return +} + +// ✅ Suspense declarative loading state +function NewComponent() { + return ( + }> + {' '} + {/* Internally uses use() or Suspense-compatible data fetching */} + + ) +} +``` + +### Multiple Independent Suspense Boundaries + +```tsx +// ❌ Single boundary — all content loads together +function BadLayout() { + return ( + }> +
+ {/* Slow */} + {/* Fast */} + + ) +} + +// ✅ Independent boundaries — each part streams independently +function GoodLayout() { + return ( + <> +
{/* Shown immediately */} +
+ }> + {/* Loads independently */} + + }> + {/* Loads independently */} + +
+ + ) +} +``` + +### Next.js 15 Streaming + +```tsx +// app/page.tsx - Automatic Streaming +export default async function Page() { + // This await does not block the entire page + const data = await fetchSlowData() + return
{data}
+} + +// app/loading.tsx - Automatic Suspense boundary +export default function Loading() { + return +} +``` + +### use() Hook (React 19) + +```tsx +// ✅ Read Promise in component +import { use } from 'react' + +function Comments({ commentsPromise }) { + const comments = use(commentsPromise) // Automatically triggers Suspense + return ( +
    + {comments.map((c) => ( +
  • {c.text}
  • + ))} +
+ ) +} + +// Parent component creates Promise, child component consumes +function Post({ postId }) { + const commentsPromise = fetchComments(postId) // Don't await + return ( +
+ + }> + + +
+ ) +} +``` + +--- + +## TanStack Query v5 + +TanStack Query is the most popular data fetching library in the React ecosystem, v5 is the current stable version. + +### Basic Configuration + +```tsx +// ❌ Incorrect default configuration +const queryClient = new QueryClient() // Default config may not be suitable + +// ✅ Production recommended configuration +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 1000 * 60 * 5, // Data considered fresh for 5 minutes + gcTime: 1000 * 60 * 30, // Garbage collected after 30 minutes (renamed in v5) + retry: 3, + refetchOnWindowFocus: false, // Decide based on requirements + }, + }, +}) +``` + +### queryOptions (v5 new) + +```tsx +// ❌ Duplicated queryKey and queryFn definitions +function Component1() { + const { data } = useQuery({ + queryKey: ['users', userId], + queryFn: () => fetchUser(userId), + }) +} + +function prefetchUser(queryClient, userId) { + queryClient.prefetchQuery({ + queryKey: ['users', userId], // Duplicated! + queryFn: () => fetchUser(userId), // Duplicated! + }) +} + +// ✅ queryOptions unified definition, type-safe +import { queryOptions } from '@tanstack/react-query' + +const userQueryOptions = (userId: string) => + queryOptions({ + queryKey: ['users', userId], + queryFn: () => fetchUser(userId), + }) + +function Component1({ userId }) { + const { data } = useQuery(userQueryOptions(userId)) +} + +function prefetchUser(queryClient, userId) { + queryClient.prefetchQuery(userQueryOptions(userId)) +} + +// getQueryData is also type-safe +const user = queryClient.getQueryData(userQueryOptions(userId).queryKey) +``` + +### Common Pitfalls + +```tsx +// ❌ staleTime of 0 causes excessive requests +useQuery({ + queryKey: ['data'], + queryFn: fetchData, + // staleTime defaults to 0, refetches on every component mount +}) + +// ✅ Set a reasonable staleTime +useQuery({ + queryKey: ['data'], + queryFn: fetchData, + staleTime: 1000 * 60, // Won't refetch within 1 minute +}) + +// ❌ Using unstable references in queryFn +function BadQuery({ filters }) { + useQuery({ + queryKey: ['items'], // queryKey doesn't include filters! + queryFn: () => fetchItems(filters), // filters changes won't trigger refetch + }) +} + +// ✅ queryKey includes all parameters that affect data +function GoodQuery({ filters }) { + useQuery({ + queryKey: ['items', filters], // filters is part of queryKey + queryFn: () => fetchItems(filters), + }) +} +``` + +### useSuspenseQuery + +> **Important limitation**: useSuspenseQuery differs significantly from useQuery, understand its limitations before choosing. + +#### useSuspenseQuery Limitations + +| Feature | useQuery | useSuspenseQuery | +| ----------------- | -------------------- | ------------------------ | +| `enabled` option | ✅ Supported | ❌ Not supported | +| `placeholderData` | ✅ Supported | ❌ Not supported | +| `data` type | `T \| undefined` | `T` (guaranteed) | +| Error handling | `error` property | Throws to Error Boundary | +| Loading state | `isLoading` property | Suspends to Suspense | + +#### Alternative for Unsupported enabled + +```tsx +// ❌ Using useQuery + enabled for conditional queries +function BadSuspenseQuery({ userId }) { + const { data } = useSuspenseQuery({ + queryKey: ['user', userId], + queryFn: () => fetchUser(userId), + enabled: !!userId, // useSuspenseQuery doesn't support enabled! + }) +} + +// ✅ Component composition for conditional rendering +function GoodSuspenseQuery({ userId }) { + // useSuspenseQuery guarantees data is T, not T | undefined + const { data } = useSuspenseQuery({ + queryKey: ['user', userId], + queryFn: () => fetchUser(userId), + }) + return +} + +function Parent({ userId }) { + if (!userId) return + return ( + }> + + + ) +} +``` + +#### Error Handling Differences + +```tsx +// ❌ useSuspenseQuery has no error property +function BadErrorHandling() { + const { data, error } = useSuspenseQuery({...}); + if (error) return ; // error is always null! +} + +// ✅ Use Error Boundary for error handling +function GoodErrorHandling() { + return ( + }> + }> + + + + ); +} + +function DataComponent() { + // Errors throw to Error Boundary + const { data } = useSuspenseQuery({ + queryKey: ['data'], + queryFn: fetchData, + }); + return ; +} +``` + +#### When to Choose useSuspenseQuery + +```tsx +// ✅ Suitable scenarios: +// 1. Data is always needed (unconditional query) +// 2. Component must have data to render +// 3. Using React 19's Suspense pattern +// 4. Server components + client hydration + +// ❌ Unsuitable scenarios: +// 1. Conditional queries (triggered by user action) +// 2. Need placeholderData or initial data +// 3. Need to handle loading/error state within component +// 4. Multiple queries with dependencies + +// ✅ Multiple independent queries with useSuspenseQueries +function MultipleQueries({ userId }) { + const [userQuery, postsQuery] = useSuspenseQueries({ + queries: [ + { queryKey: ['user', userId], queryFn: () => fetchUser(userId) }, + { queryKey: ['posts', userId], queryFn: () => fetchPosts(userId) }, + ], + }) + // Both queries execute in parallel, component renders after both complete + return +} +``` + +### Optimistic Updates (v5 Simplified) + +```tsx +// ❌ Manually managing cache for optimistic updates (complex) +const mutation = useMutation({ + mutationFn: updateTodo, + onMutate: async (newTodo) => { + await queryClient.cancelQueries({ queryKey: ['todos'] }) + const previousTodos = queryClient.getQueryData(['todos']) + queryClient.setQueryData(['todos'], (old) => [...old, newTodo]) + return { previousTodos } + }, + onError: (err, newTodo, context) => { + queryClient.setQueryData(['todos'], context.previousTodos) + }, + onSettled: () => { + queryClient.invalidateQueries({ queryKey: ['todos'] }) + }, +}) + +// ✅ v5 simplified: use variables for optimistic UI +function TodoList() { + const { data: todos } = useQuery(todosQueryOptions) + const { mutate, variables, isPending } = useMutation({ + mutationFn: addTodo, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['todos'] }) + }, + }) + + return ( +
    + {todos?.map((todo) => ( + + ))} + {/* Optimistically display the todo being added */} + {isPending && } +
+ ) +} +``` + +### v5 State Field Changes + +```tsx +// v4: isLoading indicates first load or subsequent fetch +// v5: isPending means no data, isLoading = isPending && isFetching + +const { data, isPending, isFetching, isLoading } = useQuery({...}); + +// isPending: No data in cache (first load) +// isFetching: Request in progress (including background refresh) +// isLoading: isPending && isFetching (first load in progress) + +// ❌ Direct migration from v4 code +if (isLoading) return ; // Behavior may differ in v5 + +// ✅ Be explicit about intent +if (isPending) return ; // Show loading when no data +// or +if (isLoading) return ; // During first load +``` + +--- + +## Review Checklists + +### Hooks Rules + +- [ ] Hooks called at the top level of component/custom Hook +- [ ] No Hooks called in conditions/loops +- [ ] useEffect dependency array is complete +- [ ] useEffect has cleanup function (subscriptions/timers/requests) +- [ ] No useEffect for computing derived state + +### Performance Optimization (Principle of Moderation) + +- [ ] useMemo/useCallback only used when truly needed +- [ ] React.memo paired with stable prop references +- [ ] No child components defined inside components +- [ ] No new objects/functions created in JSX (unless passed to non-memo components) +- [ ] Long lists use virtualization (react-window/react-virtual) + +### Component Design + +- [ ] Component has single responsibility, under 200 lines +- [ ] Logic and presentation separated (Custom Hooks) +- [ ] Clear Props interface, using TypeScript +- [ ] Avoid Props Drilling (consider Context or composition) + +### State Management + +- [ ] State kept close to where it's needed (minimal necessary scope) +- [ ] Complex state uses useReducer +- [ ] Global state uses Context or state library +- [ ] Avoid unnecessary state (derived > stored) + +### Error Handling + +- [ ] Critical areas have Error Boundary +- [ ] Suspense used with Error Boundary +- [ ] Async operations have error handling + +### Server Components (RSC) + +- [ ] 'use client' only for components needing interactivity +- [ ] Server Component doesn't use Hooks/event handlers +- [ ] Client components kept at leaf nodes as much as possible +- [ ] Data fetching done in Server Component + +### React 19 Forms + +- [ ] Use useActionState instead of multiple useState +- [ ] useFormStatus called in form child component +- [ ] useOptimistic not used for critical business (payments, etc.) +- [ ] Server Action correctly marked with 'use server' + +### Suspense & Streaming + +- [ ] Divide Suspense boundaries based on UX requirements +- [ ] Each Suspense has a corresponding Error Boundary +- [ ] Provide meaningful fallback (skeleton > spinner) +- [ ] Avoid awaiting slow data at layout level + +### TanStack Query + +- [ ] queryKey includes all parameters that affect data +- [ ] Set reasonable staleTime (not default 0) +- [ ] useSuspenseQuery doesn't use enabled +- [ ] Invalidate related queries after mutation success +- [ ] Understand isPending vs isLoading difference + +### Testing + +- [ ] Use @testing-library/react +- [ ] Use screen to query elements +- [ ] Use userEvent instead of fireEvent +- [ ] Prefer \*ByRole queries +- [ ] Test behavior, not implementation details diff --git a/.agents/skills/code-review-skill/reference/security-review-guide.md b/.agents/skills/code-review-skill/reference/security-review-guide.md new file mode 100644 index 0000000..d2ab45f --- /dev/null +++ b/.agents/skills/code-review-skill/reference/security-review-guide.md @@ -0,0 +1,494 @@ +# Security Review Guide + +Security-focused code review checklist based on OWASP Top 10 and best practices. + +## Authentication & Authorization + +### Authentication +- [ ] Passwords hashed with strong algorithm (bcrypt, argon2) +- [ ] Password complexity requirements enforced +- [ ] Account lockout after failed attempts +- [ ] Secure password reset flow +- [ ] Multi-factor authentication for sensitive operations +- [ ] Session tokens are cryptographically random +- [ ] Session timeout implemented + +### Authorization +- [ ] Authorization checks on every request +- [ ] Principle of least privilege applied +- [ ] Role-based access control (RBAC) properly implemented +- [ ] No privilege escalation paths +- [ ] Direct object reference checks (IDOR prevention) +- [ ] API endpoints protected appropriately + +### JWT Security +```typescript +// ❌ Insecure JWT configuration +jwt.sign(payload, 'weak-secret'); + +// ✅ Secure JWT configuration +jwt.sign(payload, process.env.JWT_SECRET, { + algorithm: 'RS256', + expiresIn: '15m', + issuer: 'your-app', + audience: 'your-api' +}); + +// ❌ Not verifying JWT properly +const decoded = jwt.decode(token); // No signature verification! + +// ✅ Verify signature and claims +const decoded = jwt.verify(token, publicKey, { + algorithms: ['RS256'], + issuer: 'your-app', + audience: 'your-api' +}); +``` + +## Input Validation + +### SQL Injection Prevention + +**The #1 rule**: Always use parameterized queries. Never concatenate user input into SQL strings. + +Every major language and framework has a parameterized query mechanism: +- Python: `cursor.execute("SELECT ...", params)` / ORM filter methods +- Java: `PreparedStatement` / JPA `@Query` with `@Param` +- Go: `db.Query("SELECT ...", args...)` +- Node.js: `client.query("SELECT ...", [args])` / Prisma ORM +- PHP: PDO prepared statements / Laravel Eloquent +- C#: ADO.NET `SqlParameter` / Dapper / EF Core LINQ + +> **See [SQL Injection Prevention Guide](cross-cutting/sql-injection-prevention.md) for complete cross-language examples, ORM unsafe patterns, dynamic identifier handling, and detection tools.** + +### XSS Prevention + +**The #1 rule**: Rely on framework auto-escaping. Audit every escape hatch. + +Every major framework auto-escapes by default: +- React: JSX auto-escapes. Audit `dangerouslySetInnerHTML`. +- Vue: `{{ }}` auto-escapes. Audit `v-html`. +- Angular: Interpolation auto-escapes. Audit `bypassSecurityTrustHtml`. +- Svelte: `{ }` auto-escapes. Audit `{@html}`. +- Django: Templates auto-escape. Audit `mark_safe`. + +For defense-in-depth, configure Content Security Policy (CSP) with nonce-based `script-src`. + +> **See [XSS Prevention Guide](cross-cutting/xss-prevention.md) for complete cross-framework examples, CSP configuration, input validation vs output encoding, and detection tools.** + +### CSRF Prevention + +**CSRF Token Implementation** +```typescript +// ✅ Server: generate and validate CSRF token +import crypto from 'node:crypto'; + +function generateCsrfToken(): string { + return crypto.randomBytes(32).toString('hex'); +} + +// Middleware: validate token on state-changing requests +app.post('/api/data', (req, res) => { + const token = req.headers['x-csrf-token']; + const sessionToken = req.session.csrfToken; + if (!token || token !== sessionToken) { + return res.status(403).json({ error: 'Invalid CSRF token' }); + } + // ...handle request +}); +``` + +**Python (Django)** +```python +# ✅ Django: built-in CSRF protection +# settings.py +MIDDLEWARE = [ + 'django.middleware.csrf.CsrfViewMiddleware', # 默认启用 +] + +# templates: include CSRF token +#
+# {% csrf_token %} +#
+ +# ❌ Disabling CSRF on a view +@csrf_exempt # 除非绝对必要,否则不使用 +def my_view(request): + ... +``` + +**Java (Spring Boot)** +```java +// ✅ Spring Security: CSRF enabled by default +@Configuration +@EnableWebSecurity +public class SecurityConfig { + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) { + http.csrf(csrf -> csrf + .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) + ); + return http.build(); + } +} +``` + +**SameSite Cookie** +```typescript +// ✅ Set SameSite cookie as additional defense +res.cookie('session', sessionId, { + httpOnly: true, + secure: true, + sameSite: 'strict', // 或 'lax' 用于允许导航 GET 请求 + maxAge: 3600000, +}); +``` + +### SSRF Prevention + +```python +# ❌ Vulnerable: user-controlled URL +import requests +url = request.GET.get('url') +response = requests.get(url) + +# ✅ Validate URL against whitelist +ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com'] + +def is_safe_url(url: str) -> bool: + from urllib.parse import urlparse + parsed = urlparse(url) + return parsed.hostname in ALLOWED_HOSTS + +if is_safe_url(url): + response = requests.get(url) +``` + +```typescript +// ❌ Vulnerable: fetching arbitrary URLs +const url = req.query.url; +const response = await fetch(url); + +// ✅ Validate URL before fetching +const ALLOWED_DOMAINS = ['api.internal.com']; + +function isSafeUrl(url: string): boolean { + try { + const parsed = new URL(url); + // Block internal IPs + if (parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1') { + return false; + } + if (parsed.hostname.match(/^10\.|^172\.(1[6-9]|2\d|3[01])\.|^192\.168\./)) { + return false; // Block private IP ranges + } + return ALLOWED_DOMAINS.includes(parsed.hostname); + } catch { + return false; + } +} +``` + +```go +// ✅ Go: validate URL before making requests +import "net/url" + +func isSafeURL(rawURL string) bool { + u, err := url.Parse(rawURL) + if err != nil { + return false + } + // Block internal IPs + if u.Hostname() == "localhost" || u.Hostname() == "127.0.0.1" { + return false + } + // Only allow HTTPS + if u.Scheme != "https" { + return false + } + return true +} +``` + +### IDOR(不安全直接对象引用) + +```python +# ❌ Vulnerable: no ownership check +def get_order(request, order_id): + order = Order.objects.get(id=order_id) # 任何用户可查看任何订单 + return JsonResponse(order.to_dict()) + +# ✅ Check ownership before returning +def get_order(request, order_id): + order = Order.objects.filter(id=order_id, user=request.user).first() + if not order: + return JsonResponse({'error': 'Not found'}, status=404) + return JsonResponse(order.to_dict()) +``` + +```typescript +// ❌ Vulnerable: no authorization check +app.get('/api/orders/:id', async (req, res) => { + const order = await db.order.findUnique({ + where: { id: Number(req.params.id) } + }); + res.json(order); +}); + +// ✅ Include user context in query +app.get('/api/orders/:id', async (req, res) => { + const order = await db.order.findFirst({ + where: { + id: Number(req.params.id), + userId: req.user.id, // Scope to current user + } + }); + if (!order) return res.status(404).json({ error: 'Not found' }); + res.json(order); +}); +``` + +```java +// ✅ Spring Security: method-level authorization +@GetMapping("/api/orders/{id}") +@PreAuthorize("@orderService.isOwner(#id, authentication.principal.id)") +public Order getOrder(@PathVariable Long id) { + return orderService.findById(id); +} +``` + +**UUID vs 自增 ID** +```typescript +// ❌ 自增 ID 可被枚举 +// GET /api/users/1, /api/users/2, /api/users/3 ... + +// ✅ UUID 不可预测 +// GET /api/users/550e8400-e29b-41d4-a716-446655440000 + +// ⚠️ UUID 只是防止枚举,不是权限控制 +// 仍然需要验证当前用户是否有权访问该资源 +``` + +### Command Injection Prevention + +**Python** +```python +# ❌ Vulnerable: shell=True +import subprocess +subprocess.run(f"convert {filename} output.png", shell=True) + +# ✅ Use list arguments without shell +subprocess.run(['convert', filename, 'output.png'], check=True) + +# ✅ Validate and sanitize input +import shlex +safe_filename = shlex.quote(filename) +``` + +**Node.js** +```typescript +// ❌ Vulnerable: exec with string interpolation +import { exec } from 'node:child_process'; +exec(`convert ${filename} output.png`); + +// ✅ Use execFile with array arguments +import { execFile } from 'node:child_process'; +execFile('convert', [filename, 'output.png'], (error, stdout) => { + if (error) throw error; +}); + +// ❌ Never pass user input to shell +exec(`echo ${userInput}`); // userInput = "; rm -rf /" + +// ✅ Sanitize or use non-shell alternatives +import { writeFile } from 'node:fs/promises'; +await writeFile('output.txt', userInput); // No shell involved +``` + +**Go** +```go +// ❌ Vulnerable: shell command with user input +cmd := exec.Command("sh", "-c", "echo " + userInput) + +// ✅ Use exec.Command with separate arguments +cmd := exec.Command("echo", userInput) + +// ❌ Passing user input to shell +out, _ := exec.Command("bash", "-c", "cat "+filename).Output() + +// ✅ Read file directly without shell +data, err := os.ReadFile(filename) +``` + +**Java** +```java +// ❌ Vulnerable: Runtime.exec with string concatenation +Runtime.getRuntime().exec("convert " + filename + " output.png"); + +// ✅ Use ProcessBuilder with separate arguments +ProcessBuilder pb = new ProcessBuilder("convert", filename, "output.png"); +Process process = pb.start(); + +// ❌ Dangerous: passing user input to shell +Runtime.getRuntime().exec(new String[]{"sh", "-c", "echo " + userInput}); +``` + +## Data Protection + +### Sensitive Data Handling +- [ ] No secrets in source code +- [ ] Secrets stored in environment variables or secret manager +- [ ] Sensitive data encrypted at rest +- [ ] Sensitive data encrypted in transit (HTTPS) +- [ ] PII handled according to regulations (GDPR, etc.) +- [ ] Sensitive data not logged +- [ ] Secure data deletion when required + +### Configuration Security +```yaml +# ❌ Secrets in config files +database: + password: "super-secret-password" + +# ✅ Reference environment variables +database: + password: ${DATABASE_PASSWORD} +``` + +### Error Messages +```typescript +// ❌ Leaking sensitive information +catch (error) { + return res.status(500).json({ + error: error.stack, // Exposes internal details + query: sqlQuery // Exposes database structure + }); +} + +// ✅ Generic error messages +catch (error) { + logger.error('Database error', { error, userId }); // Log internally + return res.status(500).json({ + error: 'An unexpected error occurred' + }); +} +``` + +## API Security + +### Rate Limiting +- [ ] Rate limiting on all public endpoints +- [ ] Stricter limits on authentication endpoints +- [ ] Per-user and per-IP limits +- [ ] Graceful handling when limits exceeded + +### CORS Configuration +```typescript +// ❌ Overly permissive CORS +app.use(cors({ origin: '*' })); + +// ✅ Restrictive CORS +app.use(cors({ + origin: ['https://your-app.com'], + methods: ['GET', 'POST'], + credentials: true +})); +``` + +### HTTP Headers +```typescript +// Security headers to set +app.use(helmet({ + contentSecurityPolicy: { + directives: { + defaultSrc: ["'self'"], + scriptSrc: ["'self'"], + styleSrc: ["'self'", "'unsafe-inline'"], + } + }, + hsts: { maxAge: 31536000, includeSubDomains: true }, + noSniff: true, + xssFilter: true, + frameguard: { action: 'deny' } +})); +``` + +## Cryptography + +### Secure Practices +- [ ] Using well-established algorithms (AES-256, RSA-2048+) +- [ ] Not implementing custom cryptography +- [ ] Using cryptographically secure random number generation +- [ ] Proper key management and rotation +- [ ] Secure key storage (HSM, KMS) + +### Common Mistakes +```typescript +// ❌ Weak random generation +const token = Math.random().toString(36); + +// ✅ Cryptographically secure random +const crypto = require('crypto'); +const token = crypto.randomBytes(32).toString('hex'); + +// ❌ MD5/SHA1 for passwords +const hash = crypto.createHash('md5').update(password).digest('hex'); + +// ✅ Use bcrypt or argon2 +const bcrypt = require('bcrypt'); +const hash = await bcrypt.hash(password, 12); +``` + +## Dependency Security + +### Checklist +- [ ] Dependencies from trusted sources only +- [ ] No known vulnerabilities (npm audit, cargo audit) +- [ ] Dependencies kept up to date +- [ ] Lock files committed (package-lock.json, Cargo.lock) +- [ ] Minimal dependency usage +- [ ] License compliance verified + +### Audit Commands +```bash +# Node.js +npm audit +npm audit fix + +# Python +pip-audit +safety check + +# Rust +cargo audit + +# General +snyk test +``` + +## Logging & Monitoring + +### Secure Logging +- [ ] No sensitive data in logs (passwords, tokens, PII) +- [ ] Logs protected from tampering +- [ ] Appropriate log retention +- [ ] Security events logged (login attempts, permission changes) +- [ ] Log injection prevented + +```typescript +// ❌ Logging sensitive data +logger.info(`User login: ${email}, password: ${password}`); + +// ✅ Safe logging +logger.info('User login attempt', { email, success: true }); +``` + +## Security Review Severity Levels + +| Severity | Description | Action | +|----------|-------------|--------| +| **Critical** | Immediate exploitation possible, data breach risk | Block merge, fix immediately | +| **High** | Significant vulnerability, requires specific conditions | Block merge, fix before release | +| **Medium** | Moderate risk, defense in depth concern | Should fix, can merge with tracking | +| **Low** | Minor issue, best practice violation | Nice to fix, non-blocking | +| **Info** | Suggestion for improvement | Optional enhancement | diff --git a/.agents/skills/code-review-skill/reference/typescript.md b/.agents/skills/code-review-skill/reference/typescript.md new file mode 100644 index 0000000..70c1166 --- /dev/null +++ b/.agents/skills/code-review-skill/reference/typescript.md @@ -0,0 +1,1028 @@ +# TypeScript/JavaScript Code Review Guide + +> TypeScript code review guide, covering type system, generics, conditional types, strict mode, async/await patterns, and other core topics. + +## Table of Contents + +- [Type Safety Fundamentals](#type-safety-fundamentals) +- [Generic Patterns](#generic-patterns) +- [Advanced Types](#advanced-types) +- [Strict Mode Configuration](#strict-mode-configuration) +- [Async Handling](#async-handling) +- [Immutability](#immutability) +- [ESLint Rules](#eslint-rules) +- [Testing](#testing) +- [Module Resolution](#module-resolution) +- [TS 4.9+ / 5.x New Features](#ts-49--5x-new-features) +- [Review Checklist](#review-checklist) + +--- + +## Type Safety Fundamentals + +### Avoid Using any + +```typescript +// ❌ Using any defeats type safety +function processData(data: any) { + return data.value // No type checking, may crash at runtime +} + +// ✅ Use proper types +interface DataPayload { + value: string +} +function processData(data: DataPayload) { + return data.value +} + +// ✅ Use unknown + type guards for unknown types +function processUnknown(data: unknown) { + if (typeof data === 'object' && data !== null && 'value' in data) { + return (data as { value: string }).value + } + throw new Error('Invalid data') +} +``` + +### Type Narrowing + +```typescript +// ❌ Unsafe type assertion +function getLength(value: string | string[]) { + return (value as string[]).length // Error if it's a string +} + +// ✅ Use type guards +function getLength(value: string | string[]): number { + if (Array.isArray(value)) { + return value.length + } + return value.length +} + +// ✅ Use in operator +interface Dog { + bark(): void +} +interface Cat { + meow(): void +} + +function speak(animal: Dog | Cat) { + if ('bark' in animal) { + animal.bark() + } else { + animal.meow() + } +} +``` + +### Literal Types and as const + +```typescript +// ❌ Type too broad +const config = { + endpoint: '/api', + method: 'GET' // type is string +}; + +// ✅ Use as const for literal types +const config = { + endpoint: '/api', + method: 'GET' +} as const; // method type is 'GET' + +// ✅ Used for function parameters +function request(method: 'GET' | 'POST', url: string) { ... } +request(config.method, config.endpoint); // Correct! +``` + +--- + +## Generic Patterns + +### Basic Generics + +```typescript +// ❌ Duplicated code +function getFirstString(arr: string[]): string | undefined { + return arr[0] +} +function getFirstNumber(arr: number[]): number | undefined { + return arr[0] +} + +// ✅ Use generics +function getFirst(arr: T[]): T | undefined { + return arr[0] +} +``` + +### Generic Constraints + +```typescript +// ❌ Generic without constraints, cannot access properties +function getProperty(obj: T, key: string) { + return obj[key] // Error: cannot index +} + +// ✅ Use keyof constraint +function getProperty(obj: T, key: K): T[K] { + return obj[key] +} + +const user = { name: 'Alice', age: 30 } +getProperty(user, 'name') // Return type is string +getProperty(user, 'age') // Return type is number +getProperty(user, 'foo') // Error: 'foo' not in keyof User +``` + +### Generic Default Values + +```typescript +// ✅ Provide reasonable default types +interface ApiResponse { + data: T; + status: number; + message: string; +} + +// Can omit generic parameter +const response: ApiResponse = { data: null, status: 200, message: 'OK' }; +// Or specify it +const userResponse: ApiResponse = { ... }; +``` + +### Common Utility Types + +```typescript +// ✅ Make good use of built-in utility types +interface User { + id: number + name: string + email: string +} + +type PartialUser = Partial // All properties optional +type RequiredUser = Required // All properties required +type ReadonlyUser = Readonly // All properties readonly +type UserKeys = keyof User // 'id' | 'name' | 'email' +type NameOnly = Pick // { name: string } +type WithoutId = Omit // { name: string; email: string } +type UserRecord = Record // { [key: string]: User } +``` + +--- + +## Advanced Types + +### Conditional Types + +```typescript +// ✅ Return different types based on input type +type IsString = T extends string ? true : false + +type A = IsString // true +type B = IsString // false + +// ✅ Extract array element type +type ElementType = T extends (infer U)[] ? U : never + +type Elem = ElementType // string + +// ✅ Extract function return type (built-in ReturnType) +type MyReturnType = T extends (...args: any[]) => infer R ? R : never +``` + +### Mapped Types + +```typescript +// ✅ Transform all properties of an object type +type Nullable = { + [K in keyof T]: T[K] | null +} + +interface User { + name: string + age: number +} + +type NullableUser = Nullable +// { name: string | null; age: number | null } + +// ✅ Add prefix +type Getters = { + [K in keyof T as `get${Capitalize}`]: () => T[K] +} + +type UserGetters = Getters +// { getName: () => string; getAge: () => number } +``` + +### Template Literal Types + +```typescript +// ✅ Type-safe event names +type EventName = 'click' | 'focus' | 'blur' +type HandlerName = `on${Capitalize}` +// 'onClick' | 'onFocus' | 'onBlur' + +// ✅ API route types +type ApiRoute = `/api/${string}` +const route: ApiRoute = '/api/users' // OK +const badRoute: ApiRoute = '/users' // Error +``` + +### Discriminated Unions + +```typescript +// ✅ Use discriminant property for type safety +type Result = { success: true; data: T } | { success: false; error: E } + +function handleResult(result: Result) { + if (result.success) { + console.log(result.data.name) // TypeScript knows data exists + } else { + console.log(result.error.message) // TypeScript knows error exists + } +} + +// ✅ Redux Action pattern +type Action = + | { type: 'INCREMENT'; payload: number } + | { type: 'DECREMENT'; payload: number } + | { type: 'RESET' } + +function reducer(state: number, action: Action): number { + switch (action.type) { + case 'INCREMENT': + return state + action.payload // payload type is known + case 'DECREMENT': + return state - action.payload + case 'RESET': + return 0 // No payload here + } +} +``` + +--- + +## Strict Mode Configuration + +### Recommended tsconfig.json + +```json +{ + "compilerOptions": { + // ✅ Must-enable strict options + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "useUnknownInCatchVariables": true, + + // ✅ Additional recommended options + "noUncheckedIndexedAccess": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "exactOptionalPropertyTypes": true, + "noPropertyAccessFromIndexSignature": true + } +} +``` + +### Impact of noUncheckedIndexedAccess + +```typescript +// tsconfig: "noUncheckedIndexedAccess": true + +const arr = [1, 2, 3] +const first = arr[0] // Type is number | undefined + +// ❌ Direct usage may error +console.log(first.toFixed(2)) // Error: may be undefined + +// ✅ Check first +if (first !== undefined) { + console.log(first.toFixed(2)) +} + +// ✅ Or use non-null assertion (when certain) +console.log(arr[0]!.toFixed(2)) +``` + +--- + +## Async Handling + +### Promise Error Handling + +```typescript +// ❌ Not handling async errors +async function fetchUser(id: string) { + const response = await fetch(`/api/users/${id}`) + return response.json() // Network errors not handled +} + +// ✅ Handle errors properly +async function fetchUser(id: string): Promise { + try { + const response = await fetch(`/api/users/${id}`) + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`) + } + return await response.json() + } catch (error) { + if (error instanceof Error) { + throw new Error(`Failed to fetch user: ${error.message}`) + } + throw error + } +} +``` + +### Promise.all vs Promise.allSettled + +```typescript +// ❌ Promise.all fails all if one fails +async function fetchAllUsers(ids: string[]) { + const users = await Promise.all(ids.map(fetchUser)) + return users // One failure fails all +} + +// ✅ Promise.allSettled gets all results +async function fetchAllUsers(ids: string[]) { + const results = await Promise.allSettled(ids.map(fetchUser)) + + const users: User[] = [] + const errors: Error[] = [] + + for (const result of results) { + if (result.status === 'fulfilled') { + users.push(result.value) + } else { + errors.push(result.reason) + } + } + + return { users, errors } +} +``` + +### Race Condition Handling + +```typescript +// ❌ Race condition: old request may overwrite new request +function useSearch() { + const [query, setQuery] = useState('') + const [results, setResults] = useState([]) + + useEffect(() => { + fetch(`/api/search?q=${query}`) + .then((r) => r.json()) + .then(setResults) // Old request may return later! + }, [query]) +} + +// ✅ Use AbortController +function useSearch() { + const [query, setQuery] = useState('') + const [results, setResults] = useState([]) + + useEffect(() => { + const controller = new AbortController() + + fetch(`/api/search?q=${query}`, { signal: controller.signal }) + .then((r) => r.json()) + .then(setResults) + .catch((e) => { + if (e.name !== 'AbortError') throw e + }) + + return () => controller.abort() + }, [query]) +} +``` + +--- + +## Immutability + +### Readonly and ReadonlyArray + +```typescript +// ❌ Mutable parameter may be accidentally modified +function processUsers(users: User[]) { + users.sort((a, b) => a.name.localeCompare(b.name)) // Modifies original array! + return users +} + +// ✅ Use readonly to prevent modification +function processUsers(users: readonly User[]): User[] { + return [...users].sort((a, b) => a.name.localeCompare(b.name)) +} + +// ✅ Deep readonly +type DeepReadonly = { + readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] +} +``` + +### Immutable Function Parameters + +```typescript +// ✅ Use as const and readonly to protect data +function createConfig(routes: T) { + return routes +} + +const routes = createConfig(['home', 'about', 'contact'] as const) +// Type is readonly ['home', 'about', 'contact'] +``` + +--- + +## ESLint Rules + +### Recommended @typescript-eslint Rules + +```javascript +// eslint.config.js (flat config, typescript-eslint v8) +import eslint from '@eslint/js' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + eslint.configs.recommended, + // Ruleset requiring type information, corresponds to old recommended-requiring-type-checking + tseslint.configs.recommendedTypeChecked, + tseslint.configs.strictTypeChecked, + { + languageOptions: { + parserOptions: { + // Let typed rules automatically find the corresponding tsconfig + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + // ✅ Type safety + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-return': 'error', + + // ✅ Best practices + '@typescript-eslint/explicit-function-return-type': 'warn', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/no-misused-promises': 'error', + + // ✅ Code style + '@typescript-eslint/consistent-type-imports': 'error', + '@typescript-eslint/prefer-nullish-coalescing': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + }, + } +) +``` + +### Common ESLint Error Fixes + +```typescript +// ❌ no-floating-promises: Promise must be handled +async function save() { ... } +save(); // Error: Unhandled Promise + +// ✅ Handle explicitly +await save(); +// or +save().catch(console.error); +// or explicitly ignore +void save(); + +// ❌ no-misused-promises: Cannot use Promise in non-async position +const items = [1, 2, 3]; +items.forEach(async (item) => { // Error! + await processItem(item); +}); + +// ✅ Use for...of +for (const item of items) { + await processItem(item); +} +// or Promise.all +await Promise.all(items.map(processItem)); +``` + +--- + +--- + +## Testing + +### Vitest vs Jest Choice + +```typescript +// ✅ New projects recommend Vitest (integrates with Vite ecosystem, native ESM support) +// vitest.config.ts +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/**/*.test.ts'], + coverage: { + provider: 'v8', + reporter: ['text', 'lcov'], + }, + }, +}) + +// ✅ Existing Jest projects can keep it, note config differences +// jest.config.ts +import type { Config } from 'jest' + +const config: Config = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, +} +export default config +``` + +### Type Testing (tsd / expect-type) + +```typescript +// ✅ Use expect-type to verify type inference +import { expectTypeOf } from 'vitest' + +function getFirst(arr: T[]): T | undefined { + return arr[0] +} + +it('should infer correct return type', () => { + const result = getFirst([1, 2, 3]) + expectTypeOf(result).toEqualTypeOf() +}) + +// ✅ Use expect-type to verify function signature +const fn = (a: string, b: number) => a.repeat(b) +expectTypeOf(fn).parameters.toEqualTypeOf<[string, number]>() +expectTypeOf(fn).returns.toBeString() + +// ❌ Type errors will be caught at compile time +const result = getFirst(['a', 'b']) +// @ts-expect-error: Type mismatch +expectTypeOf(result).toEqualTypeOf() +``` + +### Snapshot Testing Best Practices + +```typescript +// ✅ Snapshots suitable for: stable output structures, config objects, error messages +it('should match serialized config', () => { + const config = createAppConfig() + expect(config).toMatchSnapshot() +}) + +// ❌ Avoid: large objects, dynamic data, random values +it('should not snapshot large payloads', () => { + const hugePayload = { users: generateRandomUsers(1000) } + // Too-long snapshots are hard to review, unclear intent on change +}) + +// ✅ Use inline snapshot for small fragments +it('should generate correct error message', () => { + expect(formatError('INVALID_INPUT')).toMatchInlineSnapshot( + `"Error: Invalid input provided"` + ) +}) + +// ✅ Use snapshot property matchers for dynamic values +it('should match user with generated id', () => { + expect(createUser('Alice')).toMatchSnapshot({ + id: expect.any(String), + createdAt: expect.any(Date), + }) +}) +``` + +### Mock Strategies + +```typescript +// ✅ Vitest: vi.mock auto-hoists +import { vi, describe, it, expect } from 'vitest' + +vi.mock('./api', () => ({ + fetchUser: vi.fn().mockResolvedValue({ id: 1, name: 'Alice' }), +})) + +it('should display user', async () => { + const { fetchUser } = await import('./api') + const user = await fetchUser('1') + expect(user.name).toBe('Alice') +}) + +// ✅ Jest: jest.mock also auto-hoists +jest.mock('./database', () => ({ + query: jest.fn().mockResolvedValue([{ id: 1 }]), +})) + +// ❌ Avoid partial mocks — testing the mock rather than real behavior +jest.mock('./utils', () => ({ + ...jest.requireActual('./utils'), + calculateTotal: jest.fn(), // Other functions are real, this one is fake +})) +``` + +### Testing Utilities + +```typescript +// ✅ Use testing-library for DOM testing +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +it('should submit form', async () => { + render(); + await userEvent.type(screen.getByLabelText('Email'), 'alice@example.com'); + await userEvent.click(screen.getByRole('button', { name: 'Submit' })); + expect(screen.getByText('Welcome, Alice!')).toBeInTheDocument(); +}); + +// ✅ Use MSW for API mocking (Mock Service Worker) +import { http, HttpResponse } from 'msw'; +import { setupServer } from 'msw/node'; + +const server = setupServer( + http.get('/api/users/:id', ({ params }) => { + return HttpResponse.json({ id: params.id, name: 'Alice' }); + }) +); + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); +``` + +--- + +## Module Resolution + +### ESM vs CJS Differences and Pitfalls + +```typescript +// ❌ CJS style not available in ESM +// package.json: "type": "module" +const fs = require('fs') // Error: require is not defined +module.exports = { foo: 'bar' } // Error: module is not defined + +// ✅ Correct ESM syntax +import fs from 'node:fs' +export const foo = 'bar' + +// ✅ Get __dirname in ESM +import { fileURLToPath } from 'node:url' +import { dirname } from 'node:path' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +// ❌ Dynamic require in ESM +const moduleName = 'lodash' +const _ = require(moduleName) // Error! + +// ✅ ESM dynamic import +const _ = await import(moduleName) +``` + +### tsconfig paths and Path Aliases + +```json +// tsconfig.json +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"], + "@components/*": ["./src/components/*"], + "@utils/*": ["./src/utils/*"] + } + } +} +``` + +```typescript +// ✅ Before using aliases +import { Button } from '../../components/ui/Button' +import { formatDate } from '../../../utils/date' + +// ✅ After using aliases — clearer and less likely to break on file moves +import { Button } from '@components/ui/Button' +import { formatDate } from '@utils/date' +``` + +```typescript +// ⚠️ tsconfig paths only affect TS compilation, not runtime +// Need to pair with bundler (Vite, webpack) or tsx alias resolution + +// vite.config.ts +import { resolve } from 'node:path' + +export default defineConfig({ + resolve: { + alias: { + '@': resolve(__dirname, 'src'), + }, + }, +}) + +// ⚠️ When publishing npm packages, tsconfig paths don't auto-resolve +// Need tsc-alias or tsconfig-paths to handle +``` + +### package.json exports field + +```json +// package.json +{ + "name": "my-library", + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "types": "./dist/index.d.ts" + }, + "./utils": { + "import": "./dist/utils.mjs", + "require": "./dist/utils.cjs", + "types": "./dist/utils.d.ts" + }, + "./*": "./dist/*" + } +} +``` + +```typescript +// ✅ Consumer usage +import { foo } from 'my-library' // Resolves to "." condition +import { bar } from 'my-library/utils' // Resolves to "./utils" condition + +// ❌ Paths without exports mapping cannot be accessed +import { secret } from 'my-library/internal' // Error! +``` + +### Dynamic import() and Code Splitting + +```typescript +// ✅ Conditionally load modules +async function loadChartLibrary() { + if (typeof window === 'undefined') return null; // SSR skip + const { Chart } = await import('chart.js'); + return Chart; +} + +// ✅ React lazy-loaded components +const AdminPanel = lazy(() => import('./AdminPanel')); +// Use with Suspense +}> + + + +// ✅ With error handling +const AdminPanel = lazy(() => + import('./AdminPanel').catch(() => ({ + default: () => , + })) +); +``` + +--- + +## TS 4.9+ / 5.x New Features + +### satisfies Keyword (TS 4.9+) + +```typescript +// ❌ Without satisfies: type too broad +const palette = { + red: '#ff0000', + green: '#00ff00', + blue: '#0000ff', +} +// palette.red type is string, lost the precise value '#ff0000' + +// ✅ satisfies preserves literal types while validating structure +const palette = { + red: '#ff0000', + green: '#00ff00', + blue: '#0000ff', +} satisfies Record + +// palette.red type is '#ff0000' (not string) +// But adding new properties still validates the format +``` + +```typescript +// ✅ satisfies used to validate object conforms to interface +interface UserConfig { + theme: 'light' | 'dark' + locale: string +} + +const config = { + theme: 'dark', + locale: 'en-US', +} satisfies UserConfig +// config.theme type is 'dark' (not 'light' | 'dark') +// All properties pass satisfies type check +``` + +### const Type Parameters (TS 5.0+) + +```typescript +// ❌ Before: needed as const assertion +function getRoutes(routes: T) { + return routes +} +const routes = getRoutes(['home', 'about'] as const) + +// ✅ TS 5.0+: const type parameters +function getRoutes(routes: T) { + return routes +} +const routes = getRoutes(['home', 'about']) +// routes type is readonly ['home', 'about'] +``` + +```typescript +// ✅ Real-world scenario: type-safe config objects +declare function createConfig>( + config: T +): T + +const config = createConfig({ + api: { url: 'https://api.example.com', version: 2 }, + features: { newDashboard: true }, +}) +// config.api.url type is 'https://api.example.com' (literal) +``` + +### Decorators (Stage 3 Decorators, TS 5.0+) + +```typescript +// ✅ Stage 3 decorators (TS 5.0+, experimentalDecorators no longer needed) +function logged( + target: (this: This, ...args: Args) => Return, + context: ClassMethodDecoratorContext +) { + return function (this: This, ...args: Args): Return { + console.log(`Calling ${String(context.name)} with`, args) + return target.apply(this, args) + } +} + +class Calculator { + @logged + add(a: number, b: number): number { + return a + b + } +} + +// Output: Calling add with [1, 2] +new Calculator().add(1, 2) +``` + +```typescript +// ⚠️ Stage 3 decorators differ from legacy experimentalDecorators +// Legacy: requires "experimentalDecorators": true in tsconfig +// New (TS 5.0+): supported by default, no extra config needed + +// ❌ Legacy decorator signature (still supported but marked as legacy) +function deprecated(constructor: T) { + return class extends constructor { + /* ... */ + } +} + +// ✅ New decorator distinguishes context by type +function sealed( + target: T, + context: ClassDecoratorContext +) { + // context.kind === 'class' +} +``` + +### using Declarations (Explicit Resource Management, TS 5.2+) + +```typescript +// ✅ Use Symbol.dispose for automatic cleanup +class TempFile implements Disposable { + private path: string + + constructor() { + this.path = `/tmp/file-${Date.now()}` + } + + write(data: string) { + /* ... */ + } + + [Symbol.dispose]() { + // Automatic cleanup — regardless of how function exits (normal/exception) + fs.unlinkSync(this.path) + console.log(`Cleaned up: ${this.path}`) + } +} + +function processFile() { + using file = new TempFile() // using declaration + file.write('data') + // file[Symbol.dispose]() called automatically when scope ends +} +``` + +```typescript +// ✅ AsyncDisposable for async resources (TS 5.2+) +class DatabaseConnection implements AsyncDisposable { + private db: sqlite3.Database + + async connect() { + this.db = new sqlite3.Database(':memory:') + } + + async [Symbol.asyncDispose]() { + await this.db.close() + } +} + +async function query() { + await using conn = new DatabaseConnection() // await using + await conn.connect() + // await conn[Symbol.asyncDispose]() called automatically when scope ends +} +``` + +### Enum Improvements (TS 5.0+) + +```typescript +// ✅ All enums are now union enums (TS 5.0+) +enum Color { + Red = 'RED', + Green = 'GREEN', +} + +// Before: Color behaved inconsistently as a type +// Now: Color fully acts as a string literal union type +const color: Color = Color.Red // TypeScript now has better inference for Color type +``` + +## Review Checklist + +### Type System + +- [ ] No use of `any` (use `unknown` + type guards instead) +- [ ] Interfaces and type definitions are complete and meaningfully named +- [ ] Generics used to improve code reusability +- [ ] Union types have correct type narrowing +- [ ] Good use of utility types (Partial, Pick, Omit, etc.) + +### Generics + +- [ ] Generics have appropriate constraints (extends) +- [ ] Generic parameters have reasonable default values +- [ ] Avoid over-generalization (KISS principle) + +### Strict Mode + +- [ ] tsconfig.json has strict: true enabled +- [ ] noUncheckedIndexedAccess enabled +- [ ] No use of @ts-ignore (use @ts-expect-error instead) + +### Async Code + +- [ ] async functions have error handling +- [ ] Promise rejections are properly handled +- [ ] No floating promises (unhandled Promises) +- [ ] Concurrent requests use Promise.all or Promise.allSettled +- [ ] Race conditions handled with AbortController + +### Immutability + +- [ ] No direct mutation of function parameters +- [ ] Use spread operator to create new objects/arrays +- [ ] Consider using readonly modifier + +### ESLint + +- [ ] Using @typescript-eslint/recommended +- [ ] No ESLint warnings or errors +- [ ] Using consistent-type-imports diff --git a/.agents/skills/solid/SKILL.md b/.agents/skills/solid/SKILL.md new file mode 100644 index 0000000..20fb2d5 --- /dev/null +++ b/.agents/skills/solid/SKILL.md @@ -0,0 +1,270 @@ +--- +name: solid +description: Use this skill when writing code, implementing features, refactoring, planning architecture, designing systems, reviewing code, or debugging. This skill transforms junior-level code into senior-engineer quality software through SOLID principles, TDD, clean code practices, and professional software design. +--- + +# Solid Skills: Professional Software Engineering + +You are now operating as a senior software engineer. Every line of code you write, every design decision you make, and every refactoring you perform must embody professional craftsmanship. + +## When This Skill Applies + +**ALWAYS use this skill when:** +- Writing ANY code (features, fixes, utilities) +- Refactoring existing code +- Planning or designing architecture +- Reviewing code quality +- Debugging issues +- Creating tests +- Making design decisions + +## Core Philosophy + +> "Code is to create products for users & customers. Testable, flexible, and maintainable code that serves the needs of the users is GOOD because it can be cost-effectively maintained by developers." + +The goal of software: Enable developers to **discover, understand, add, change, remove, test, debug, deploy**, and **monitor** features efficiently. + +## The Non-Negotiable Process + +### 1. ALWAYS Start with Tests (TDD) + +**Red-Green-Refactor is not optional:** + +``` +1. RED - Write a failing test that describes the behavior +2. GREEN - Write the SIMPLEST code to make it pass +3. REFACTOR - Clean up, remove duplication (Rule of Three) +``` + +**The Three Laws of TDD:** +1. You cannot write production code unless it makes a failing test pass +2. You cannot write more test code than is sufficient to fail +3. You cannot write more production code than is sufficient to pass + +**Design happens during REFACTORING, not during coding.** + +See: [references/tdd.md](references/tdd.md) + +### 2. Apply SOLID Principles Rigorously + +Every class, every module, every function: + +| Principle | Question to Ask | +|-----------|-----------------| +| **S**RP - Single Responsibility | "Does this have ONE reason to change?" | +| **O**CP - Open/Closed | "Can I extend without modifying?" | +| **L**SP - Liskov Substitution | "Can subtypes replace base types safely?" | +| **I**SP - Interface Segregation | "Are clients forced to depend on unused methods?" | +| **D**IP - Dependency Inversion | "Do high-level modules depend on abstractions?" | + +See: [references/solid-principles.md](references/solid-principles.md) + +### 3. Write Clean, Human-Readable Code + +**Naming (in order of priority):** +1. **Consistency** - Same concept = same name everywhere +2. **Understandability** - Domain language, not technical jargon +3. **Specificity** - Precise, not vague (avoid `data`, `info`, `manager`) +4. **Brevity** - Short but not cryptic +5. **Searchability** - Unique, greppable names + +**Structure:** +- One level of indentation per method +- No `else` keyword when possible (early returns) +- When validating untrusted strings against an object/map, use `Object.hasOwn(...)` (or `Object.prototype.hasOwnProperty.call(...)`) — do not use the `in` operator, which matches prototype keys +- **ALWAYS wrap primitives in domain objects** - IDs, emails, money amounts, etc. +- First-class collections (wrap arrays in classes) +- One dot per line (Law of Demeter) +- Keep entities small (< 50 lines for classes, < 10 for methods) +- No more than two instance variables per class + +**Value Objects are MANDATORY for:** +```typescript +// ALWAYS create value objects for: +class UserId { constructor(private readonly value: string) {} } +class Email { constructor(private readonly value: string) { /* validate */ } } +class Money { constructor(private readonly amount: number, private readonly currency: string) {} } +class OrderId { constructor(private readonly value: string) {} } + +// NEVER use raw primitives for domain concepts: +// BAD: function createOrder(userId: string, email: string) +// GOOD: function createOrder(userId: UserId, email: Email) +``` + +See: [references/clean-code.md](references/clean-code.md) + +### 4. Design with Responsibility in Mind + +**Ask these questions for every class:** +1. "What pattern is this?" (Entity, Service, Repository, Factory, etc.) +2. "Is it doing too much?" (Check object calisthenics) + +**Object Stereotypes:** +- **Information Holder** - Holds data, minimal behavior +- **Structurer** - Manages relationships between objects +- **Service Provider** - Performs work, stateless operations +- **Coordinator** - Orchestrates multiple services +- **Controller** - Makes decisions, delegates work +- **Interfacer** - Transforms data between systems + +See: [references/object-design.md](references/object-design.md) + +### 5. Manage Complexity Ruthlessly + +**Essential complexity** = inherent to the problem domain +**Accidental complexity** = introduced by our solutions + +**Detect complexity through:** +- Change amplification (small change = many files) +- Cognitive load (hard to understand) +- Unknown unknowns (surprises in behavior) + +**Fight complexity with:** +- YAGNI - Don't build what you don't need NOW +- KISS - Simplest solution that works +- DRY - But only after Rule of Three (wait for 3 duplications) + +See: [references/complexity.md](references/complexity.md) + +### 6. Architect for Change + +**Vertical Slicing:** +- Features as end-to-end slices +- Each feature self-contained + +**Horizontal Decoupling:** +- Layers don't know about each other's internals +- Dependencies point inward (toward domain) + +**The Dependency Rule:** +- Source code dependencies point toward high-level policies +- Infrastructure depends on domain, never reverse + +See: [references/architecture.md](references/architecture.md) + +## The Four Elements of Simple Design (XP) + +In priority order: +1. **Runs all the tests** - Must work correctly +2. **Expresses intent** - Readable, reveals purpose +3. **No duplication** - DRY (but Rule of Three) +4. **Minimal** - Fewest classes, methods possible + +## Code Smell Detection + +**Stop and refactor when you see:** + +| Smell | Solution | +|-------|----------| +| Long Method | Extract methods, compose method pattern | +| Large Class | Extract class, single responsibility | +| Long Parameter List | Introduce parameter object | +| Divergent Change | Split into focused classes | +| Shotgun Surgery | Move related code together | +| Feature Envy | Move method to the envied class | +| Data Clumps | Extract class for grouped data | +| Primitive Obsession | Wrap in value objects | +| Switch Statements | Replace with polymorphism | +| Parallel Inheritance | Merge hierarchies | +| Speculative Generality | YAGNI - remove unused abstractions | + +See: [references/code-smells.md](references/code-smells.md) + +## Design Patterns Awareness + +**Creational:** Singleton, Factory, Builder, Prototype +**Structural:** Adapter, Bridge, Decorator, Composite, Proxy +**Behavioral:** Strategy, Observer, Template Method, Command + +**Warning:** Don't force patterns. Let them emerge from refactoring. + +See: [references/design-patterns.md](references/design-patterns.md) + +## Testing Strategy + +**Test Types (from inner to outer):** +1. **Unit Tests** - Single class/function, fast, isolated +2. **Integration Tests** - Multiple components together +3. **E2E/Acceptance Tests** - Full system, user perspective + +**Arrange-Act-Assert Pattern:** +```typescript +// Arrange - Set up test state +const calculator = new Calculator(); + +// Act - Execute the behavior +const result = calculator.add(2, 3); + +// Assert - Verify the outcome +expect(result).toBe(5); +``` + +**Test Naming:** Use concrete examples, not abstract statements +```typescript +// BAD: 'can add numbers' +// GOOD: 'when adding 2 + 3, returns 5' +``` + +See: [references/testing.md](references/testing.md) + +## Behavioral Principles + +- **Tell, Don't Ask** - Command objects, don't query and decide +- **Design by Contract** - Preconditions, postconditions, invariants +- **Hollywood Principle** - "Don't call us, we'll call you" (IoC) +- **Law of Demeter** - Only talk to immediate friends + +## Pre-Code Checklist + +Before writing ANY code, answer: + +1. [ ] Do I understand the requirement? (Write acceptance criteria first) +2. [ ] What test will I write first? +3. [ ] What is the simplest solution? +4. [ ] What patterns might apply? (Don't force them) +5. [ ] Am I solving a real problem or a hypothetical one? + +## During-Code Checklist + +While coding, continuously ask: + +1. [ ] Is this the simplest thing that could work? +2. [ ] Does this class have a single responsibility? +3. [ ] Am I depending on abstractions or concretions? +4. [ ] Can I name this more clearly? +5. [ ] Is there duplication I should extract? (Rule of Three) + +## Post-Code Checklist + +After the code works: + +1. [ ] Do all tests pass? +2. [ ] Is there any dead code to remove? +3. [ ] Can I simplify any complex conditions? +4. [ ] Are names still accurate after changes? +5. [ ] Would a junior understand this in 6 months? + +## Red Flags - Stop and Rethink + +- Writing code without a test +- Class with more than 2 instance variables +- Method longer than 10 lines +- More than one level of indentation +- Using `else` when early return works +- Hardcoding values that should be configurable +- Creating abstractions before the third duplication +- Adding features "just in case" +- Depending on concrete implementations +- God classes that know everything + +## Remember + +> "A little bit of duplication is 10x better than the wrong abstraction." + +> "Focus on WHAT needs to happen, not HOW it needs to happen." + +> "Design principles become second nature through practice. Eventually, you won't think about SOLID - you'll just write SOLID code." + +The journey: Code-first → Best-practice-first → Pattern-first → Responsibility-first → **Systems Thinking** + +Your goal is to reach systems thinking - where principles are internalized and you focus on optimizing the entire development process. diff --git a/.agents/skills/solid/references/architecture.md b/.agents/skills/solid/references/architecture.md new file mode 100644 index 0000000..7b149d3 --- /dev/null +++ b/.agents/skills/solid/references/architecture.md @@ -0,0 +1,318 @@ +# Software Architecture + +## The Goal of Architecture + +Enable the development team to: +1. **Add** features with minimal friction +2. **Change** existing features safely +3. **Remove** features cleanly +4. **Test** features in isolation +5. **Deploy** independently when possible + +## Architectural Principles + +### 1. Vertical Boundaries (Features/Slices) + +Organize by **feature**, not by technical layer. + +``` +BAD: Layer-first +src/ + controllers/ + UserController.ts + OrderController.ts + services/ + UserService.ts + OrderService.ts + repositories/ + UserRepository.ts + OrderRepository.ts + +GOOD: Feature-first +src/ + users/ + UserController.ts + UserService.ts + UserRepository.ts + orders/ + OrderController.ts + OrderService.ts + OrderRepository.ts +``` + +**Why:** Changes to "users" feature stay in `users/`. High cohesion within features. + +### 2. Horizontal Boundaries (Layers) + +Separate concerns into layers with clear dependencies. + +``` +┌──────────────────────────────────────┐ +│ Presentation │ UI, Controllers, CLI +├──────────────────────────────────────┤ +│ Application │ Use Cases, Orchestration +├──────────────────────────────────────┤ +│ Domain │ Business Logic, Entities +├──────────────────────────────────────┤ +│ Infrastructure │ Database, APIs, External +└──────────────────────────────────────┘ +``` + +### 3. The Dependency Rule + +**Dependencies point INWARD.** + +``` +Infrastructure → Application → Domain + ↓ ↓ ↓ + (outer) (middle) (inner) +``` + +- Inner layers know NOTHING about outer layers +- Domain has zero dependencies on infrastructure +- Use interfaces to invert dependencies + +```typescript +// Domain defines the interface (inner) +interface UserRepository { + save(user: User): Promise; + findById(id: UserId): Promise; +} + +// Infrastructure implements it (outer) +class PostgresUserRepository implements UserRepository { + save(user: User): Promise { + // SQL here + } +} + +// Domain service uses the interface +class UserService { + constructor(private repo: UserRepository) {} // Depends on abstraction +} +``` + +### 4. Contracts + +Interfaces define boundaries between components. + +```typescript +// The contract +interface PaymentGateway { + charge(amount: Money, card: CardDetails): Promise; + refund(chargeId: string): Promise; +} + +// Multiple implementations possible +class StripeGateway implements PaymentGateway { } +class PayPalGateway implements PaymentGateway { } +class MockGateway implements PaymentGateway { } // For tests +``` + +### 5. Cross-Cutting Concerns + +Concerns that span multiple features: logging, auth, validation, error handling. + +**Options:** +- Middleware/interceptors +- Decorators +- Aspect-oriented approaches +- Base classes (use sparingly) + +```typescript +// Middleware approach +class LoggingMiddleware { + handle(request: Request, next: Handler): Response { + console.log(`Request: ${request.path}`); + const response = next(request); + console.log(`Response: ${response.status}`); + return response; + } +} +``` + +### 6. Conway's Law + +> "Organizations design systems that mirror their communication structure." + +**Implication:** Team structure affects architecture. Align both intentionally. + +--- + +## Common Architectural Styles + +### Layered Architecture + +Traditional layers: Presentation → Business → Persistence + +**Pros:** Simple, well-understood +**Cons:** Can become a "big ball of mud" without discipline + +### Hexagonal Architecture (Ports & Adapters) + +Domain at center, adapters around the edges. + +``` + ┌─────────────────────┐ + │ HTTP Adapter │ + └─────────┬───────────┘ + │ +┌─────────────────▼─────────────────┐ +│ DOMAIN │ +│ ┌─────────────────────────┐ │ +│ │ Business Logic │ │ +│ │ Use Cases │ │ +│ └─────────────────────────┘ │ +└─────────────────┬─────────────────┘ + │ + ┌─────────▼───────────┐ + │ Database Adapter │ + └─────────────────────┘ +``` + +**Ports:** Interfaces defined by the domain +**Adapters:** Implementations that connect to the outside world + +### Clean Architecture + +Similar to Hexagonal, with explicit layers: + +1. **Entities** - Enterprise business rules +2. **Use Cases** - Application business rules +3. **Interface Adapters** - Controllers, Presenters, Gateways +4. **Frameworks & Drivers** - Web, DB, External interfaces + +--- + +## Feature-Driven Structure (Frontend) + +``` +src/ + features/ + auth/ + components/ + LoginForm.tsx + SignupForm.tsx + hooks/ + useAuth.ts + services/ + authService.ts + types/ + auth.types.ts + index.ts # Public API + checkout/ + components/ + hooks/ + services/ + types/ + index.ts + shared/ + components/ # Truly shared UI + hooks/ # Truly shared hooks + utils/ # Truly shared utilities +``` + +--- + +## Feature-Driven Structure (Backend) + +``` +src/ + modules/ + users/ + domain/ + User.ts + UserRepository.ts # Interface + application/ + CreateUser.ts # Use case + GetUser.ts # Use case + infrastructure/ + PostgresUserRepo.ts + presentation/ + UserController.ts + UserDTO.ts + orders/ + domain/ + application/ + infrastructure/ + presentation/ + shared/ + domain/ # Shared value objects + infrastructure/ # Shared infra utilities +``` + +--- + +## The Walking Skeleton + +Start with a minimal end-to-end slice: + +1. **Thinnest possible feature** that touches all layers +2. **Deployable** from day one +3. **Proves the architecture** works + +Example walking skeleton for e-commerce: +- User can view ONE product (hardcoded) +- User can add it to cart +- User can "checkout" (just logs) + +From there, flesh out each feature fully. + +--- + +## Testing Architecture + +``` +┌────────────────────────────────────────────┐ +│ E2E / Acceptance Tests │ Few, slow, high confidence +├────────────────────────────────────────────┤ +│ Integration Tests │ Some, medium speed +├────────────────────────────────────────────┤ +│ Unit Tests │ Many, fast, isolated +└────────────────────────────────────────────┘ +``` + +**Test by layer:** +- **Domain:** Unit tests (most tests here) +- **Application:** Integration tests with mocked infra +- **Infrastructure:** Integration tests with real dependencies +- **E2E:** Critical paths only + +--- + +## Architecture Decision Records (ADRs) + +Document significant decisions: + +```markdown +# ADR 001: Use PostgreSQL for persistence + +## Status +Accepted + +## Context +We need a database. Options: PostgreSQL, MongoDB, MySQL + +## Decision +PostgreSQL for: +- ACID compliance +- Team familiarity +- JSON support for flexibility + +## Consequences +- Need PostgreSQL expertise +- Schema migrations required +- Excellent query capabilities +``` + +--- + +## Red Flags in Architecture + +- **Circular dependencies** between modules +- **Domain depending on infrastructure** +- **Framework code in business logic** +- **No clear boundaries** between features +- **Shared mutable state** across modules +- **"Util" or "Common" packages** that grow forever +- **Database schema driving domain model** diff --git a/.agents/skills/solid/references/clean-code.md b/.agents/skills/solid/references/clean-code.md new file mode 100644 index 0000000..41a7686 --- /dev/null +++ b/.agents/skills/solid/references/clean-code.md @@ -0,0 +1,376 @@ +# Clean Code Practices + +## What is Clean Code? + +Code that is: +- **Easy to understand** - reveals intent clearly +- **Easy to change** - modifications are localized +- **Easy to test** - dependencies are injectable +- **Simple** - no unnecessary complexity + +## The Human-Centered Approach + +Code has THREE consumers: +1. **Users** - get their needs met +2. **Customers** - make or save money +3. **Developers** - must maintain it + +Design for all three, but remember: **developers read code 10x more than they write it.** + +## Naming Principles + +### 1. Consistency & Uniqueness (HIGHEST PRIORITY) +Same concept = same name everywhere. One name per concept. + +```typescript +// BAD: Inconsistent names for same concept +getUserById(id) +fetchCustomerById(id) +retrieveClientById(id) + +// GOOD: Consistent +getUser(id) +getOrder(id) +getProduct(id) +``` + +### 2. Understandability +Use domain language, not technical jargon. + +```typescript +// BAD: Technical +const arr = users.filter(u => u.isActive); + +// GOOD: Domain language +const activeCustomers = users.filter(user => user.isActive); +``` + +### 3. Specificity +Avoid vague names: `data`, `info`, `manager`, `handler`, `processor`, `utils` + +```typescript +// BAD: Vague +class DataManager { } +function processInfo(data) { } + +// GOOD: Specific +class OrderRepository { } +function validatePayment(payment) { } +``` + +### 4. Brevity (but not at cost of clarity) +Short names are good only if meaning is preserved. + +```typescript +// BAD: Too cryptic +const usrLst = getUsrs(); + +// BAD: Unnecessarily long +const listOfAllActiveUsersInTheSystem = getActiveUsers(); + +// GOOD: Brief but clear +const activeUsers = getActiveUsers(); +``` + +### 5. Searchability +Names should be unique enough to grep/search. + +```typescript +// BAD: Common word, hard to search +const data = fetch(); + +// GOOD: Unique, searchable +const orderSummary = fetchOrderSummary(); +``` + +### 6. Pronounceability +You should be able to say it in conversation. + +```typescript +// BAD +const genymdhms = generateYearMonthDayHourMinuteSecond(); + +// GOOD +const timestamp = generateTimestamp(); +``` + +### 7. Austerity +Avoid unnecessary filler words. + +```typescript +// BAD: Redundant +const userData = user; // 'Data' adds nothing +class UserClass { } // 'Class' adds nothing + +// GOOD +const user = user; +class User { } +``` + +--- + +## Object Calisthenics (9 Rules) + +Exercises to improve OO design. Follow strictly during practice, relax slightly in production. + +### 1. One Level of Indentation per Method + +```typescript +// BAD: Multiple levels +function process(orders: Order[]) { + for (const order of orders) { + if (order.isValid()) { + for (const item of order.items) { + if (item.inStock) { + // process... + } + } + } + } +} + +// GOOD: Extract methods +function process(orders: Order[]) { + orders.filter(o => o.isValid()).forEach(processOrder); +} + +function processOrder(order: Order) { + order.items.filter(i => i.inStock).forEach(processItem); +} +``` + +### 2. Don't Use the ELSE Keyword + +Use early returns, guard clauses, or polymorphism. + +```typescript +// BAD: else +function getDiscount(user: User): number { + if (user.isPremium) { + return 20; + } else { + return 0; + } +} + +// GOOD: Early return +function getDiscount(user: User): number { + if (user.isPremium) return 20; + return 0; +} +``` + +### 3. Wrap All Primitives and Strings + +Primitives should be wrapped in domain objects when they have meaning. + +```typescript +// BAD: Primitive obsession +function createUser(email: string, age: number) { } + +// GOOD: Value objects +class Email { + constructor(private value: string) { + if (!this.isValid(value)) throw new InvalidEmail(); + } + private isValid(email: string): boolean { ... } +} + +class Age { + constructor(private value: number) { + if (value < 0 || value > 150) throw new InvalidAge(); + } +} + +function createUser(email: Email, age: Age) { } +``` + +### 4. First-Class Collections + +Any class with a collection should have no other instance variables. + +```typescript +// BAD: Collection mixed with other state +class Order { + items: OrderItem[] = []; + customerId: string; + total: number; +} + +// GOOD: Collection is its own class +class OrderItems { + constructor(private items: OrderItem[] = []) {} + + add(item: OrderItem): void { ... } + total(): Money { ... } + isEmpty(): boolean { ... } +} + +class Order { + constructor( + private items: OrderItems, + private customerId: CustomerId + ) {} +} +``` + +### 5. One Dot per Line (Law of Demeter) + +Don't chain through object graphs. + +```typescript +// BAD: Train wreck +const city = order.customer.address.city; + +// GOOD: Tell, don't ask +const city = order.getShippingCity(); +``` + +### 6. Don't Abbreviate + +If a name is too long to type, the class is doing too much. + +```typescript +// BAD +const custRepo = new CustRepo(); +const ord = new Ord(); + +// GOOD +const customerRepository = new CustomerRepository(); +const order = new Order(); +``` + +### 7. Keep All Entities Small + +- Classes: < 50 lines +- Methods: < 10 lines +- Files: < 100 lines + +If larger, it's probably doing too much. Split it. + +### 8. No Classes with More Than Two Instance Variables + +Forces small, focused classes. + +```typescript +// BAD: Too many variables +class Order { + id: string; + customerId: string; + items: Item[]; + total: number; + status: string; +} + +// GOOD: Composed of smaller objects +class Order { + constructor( + private id: OrderId, + private details: OrderDetails + ) {} +} + +class OrderDetails { + constructor( + private customer: Customer, + private lineItems: LineItems + ) {} +} +``` + +### 9. No Getters/Setters/Properties + +Objects should have behavior, not just data. Tell objects what to do. + +```typescript +// BAD: Data bag with getters +class Account { + getBalance(): number { return this.balance; } + setBalance(value: number) { this.balance = value; } +} + +// Caller does the work +if (account.getBalance() >= amount) { + account.setBalance(account.getBalance() - amount); +} + +// GOOD: Behavior-rich object +class Account { + withdraw(amount: Money): WithdrawResult { + if (!this.canWithdraw(amount)) { + return WithdrawResult.insufficientFunds(); + } + this.balance = this.balance.subtract(amount); + return WithdrawResult.success(); + } +} + +// Caller tells, object decides +const result = account.withdraw(amount); +``` + +--- + +## Comments + +### When to Write Comments + +**Only write comments to explain WHY, not WHAT or HOW.** + +Code explains what and how. Comments explain business reasons, non-obvious decisions, or warnings. + +```typescript +// BAD: Explains what (redundant) +// Add 1 to counter +counter++; + +// GOOD: Explains why +// Compensate for 0-based indexing in legacy API +counter++; +``` + +### Prefer Self-Documenting Code + +Instead of commenting, rename to make intent clear. + +```typescript +// BAD: Comment needed +// Check if user can access premium features +if (user.subscriptionLevel >= 2 && !user.isBanned) { } + +// GOOD: Self-documenting +if (user.canAccessPremiumFeatures()) { } +``` + +--- + +## Formatting + +### Vertical Spacing +- Related code together +- Blank lines between concepts +- Most important/public at top + +### Horizontal Spacing +- Consistent indentation +- Space around operators +- Max line length ~80-120 characters + +### Storytelling +Code should read top-to-bottom like a story. High-level at top, details below. + +```typescript +class OrderProcessor { + // Public API first + process(order: Order): ProcessResult { + this.validate(order); + this.calculateTotals(order); + return this.save(order); + } + + // Supporting methods below, in order of appearance + private validate(order: Order): void { ... } + private calculateTotals(order: Order): void { ... } + private save(order: Order): ProcessResult { ... } +} +``` diff --git a/.agents/skills/solid/references/code-smells.md b/.agents/skills/solid/references/code-smells.md new file mode 100644 index 0000000..715482e --- /dev/null +++ b/.agents/skills/solid/references/code-smells.md @@ -0,0 +1,334 @@ +# Code Smells & Anti-Patterns + +## What Are Code Smells? + +Indicators that something MAY be wrong. Not bugs, but design problems that make code hard to understand, change, or test. + +## The Five Categories + +### 1. Bloaters +Code that has grown too large. + +| Smell | Symptom | Refactoring | +|-------|---------|-------------| +| **Long Method** | > 10 lines | Extract Method | +| **Large Class** | > 50 lines, multiple responsibilities | Extract Class | +| **Long Parameter List** | > 3 parameters | Introduce Parameter Object | +| **Data Clumps** | Same group of variables appear together | Extract Class | +| **Primitive Obsession** | Primitives instead of small objects | Wrap in Value Object | + +### 2. Object-Orientation Abusers +Misuse of OO principles. + +| Smell | Symptom | Refactoring | +|-------|---------|-------------| +| **Switch Statements** | Type checking, large switch/if-else | Replace with Polymorphism | +| **Parallel Inheritance** | Adding subclass requires adding another | Merge Hierarchies | +| **Refused Bequest** | Subclass doesn't use parent methods | Replace Inheritance with Delegation | +| **Alternative Classes** | Different interfaces, same concept | Rename, Extract Superclass | + +### 3. Change Preventers +Code that makes changes difficult. + +| Smell | Symptom | Refactoring | +|-------|---------|-------------| +| **Divergent Change** | One class changed for many reasons | Extract Class (SRP) | +| **Shotgun Surgery** | One change touches many classes | Move Method/Field together | +| **Parallel Inheritance** | (see above) | Merge Hierarchies | + +### 4. Dispensables +Code that can be removed. + +| Smell | Symptom | Refactoring | +|-------|---------|-------------| +| **Comments** | Explaining bad code | Rename, Extract Method | +| **Duplicate Code** | Copy-paste | Extract Method, Pull Up Method | +| **Dead Code** | Unreachable code | Delete | +| **Speculative Generality** | "Just in case" code | Delete (YAGNI) | +| **Lazy Class** | Class that does almost nothing | Inline Class | + +### 5. Couplers +Excessive coupling between classes. + +| Smell | Symptom | Refactoring | +|-------|---------|-------------| +| **Feature Envy** | Method uses another class's data extensively | Move Method | +| **Inappropriate Intimacy** | Classes know too much about each other | Move Method, Extract Class | +| **Message Chains** | `a.getB().getC().getD()` | Hide Delegate | +| **Middle Man** | Class only delegates | Inline Class | + +--- + +## The Seven Most Common Code Smells + +### 1. Long Method + +**Symptom:** Method > 10 lines, doing multiple things. + +```typescript +// SMELL +function processOrder(order: Order) { + // Validate + if (!order.items.length) throw new Error('Empty'); + if (!order.customer) throw new Error('No customer'); + + // Calculate + let total = 0; + for (const item of order.items) { + total += item.price * item.quantity; + if (item.discount) { + total -= item.discount; + } + } + + // Apply tax + const taxRate = getTaxRate(order.customer.state); + total = total * (1 + taxRate); + + // Save + db.orders.insert({ ...order, total }); + + // Notify + emailService.send(order.customer.email, 'Order confirmed'); +} + +// REFACTORED +function processOrder(order: Order) { + validateOrder(order); + const total = calculateTotal(order); + saveOrder(order, total); + notifyCustomer(order); +} +``` + +### 2. Large Class + +**Symptom:** Class with many responsibilities, > 50 lines. + +```typescript +// SMELL: God class +class User { + // User data + name: string; + email: string; + + // Authentication + login() { } + logout() { } + resetPassword() { } + + // Preferences + setTheme() { } + setLanguage() { } + + // Notifications + sendEmail() { } + sendSMS() { } + + // Billing + charge() { } + refund() { } +} + +// REFACTORED: Separate classes +class User { name: string; email: string; } +class AuthService { login(); logout(); resetPassword(); } +class UserPreferences { setTheme(); setLanguage(); } +class NotificationService { sendEmail(); sendSMS(); } +class BillingService { charge(); refund(); } +``` + +### 3. Feature Envy + +**Symptom:** Method uses another class's data more than its own. + +```typescript +// SMELL: Order envies Customer +class Order { + calculateShipping(customer: Customer): number { + if (customer.country === 'US') { + if (customer.state === 'CA') return 10; + return 15; + } + return 25; + } +} + +// REFACTORED: Move to Customer +class Customer { + getShippingCost(): number { + if (this.country === 'US') { + if (this.state === 'CA') return 10; + return 15; + } + return 25; + } +} + +class Order { + calculateShipping(): number { + return this.customer.getShippingCost(); + } +} +``` + +### 4. Primitive Obsession + +**Symptom:** Using primitives for domain concepts. + +```typescript +// SMELL +function createUser(email: string, age: number, zipCode: string) { + // No validation, easy to pass wrong values + if (!email.includes('@')) throw new Error(); + if (age < 0) throw new Error(); +} + +// REFACTORED: Value objects +class Email { + constructor(private value: string) { + if (!value.includes('@')) throw new InvalidEmail(); + } +} + +class Age { + constructor(private value: number) { + if (value < 0 || value > 150) throw new InvalidAge(); + } +} + +function createUser(email: Email, age: Age, address: Address) { + // Type system prevents invalid data +} +``` + +### 5. Switch Statements + +**Symptom:** Switching on type, repeated across codebase. + +```typescript +// SMELL +function getArea(shape: Shape): number { + switch (shape.type) { + case 'circle': return Math.PI * shape.radius ** 2; + case 'rectangle': return shape.width * shape.height; + case 'triangle': return 0.5 * shape.base * shape.height; + } +} + +function getPerimeter(shape: Shape): number { + switch (shape.type) { // Same switch again! + case 'circle': return 2 * Math.PI * shape.radius; + // ... + } +} + +// REFACTORED: Polymorphism +interface Shape { + getArea(): number; + getPerimeter(): number; +} + +class Circle implements Shape { + constructor(private radius: number) {} + getArea(): number { return Math.PI * this.radius ** 2; } + getPerimeter(): number { return 2 * Math.PI * this.radius; } +} +``` + +### 6. Inappropriate Intimacy + +**Symptom:** Classes know too much about each other's internals. + +```typescript +// SMELL +class Order { + process() { + const inventory = new Inventory(); + // Reaching into inventory's internals + for (const item of this.items) { + const stock = inventory.stockLevels[item.sku]; + if (stock.quantity < item.quantity) { + throw new Error('Out of stock'); + } + inventory.stockLevels[item.sku].quantity -= item.quantity; + } + } +} + +// REFACTORED: Tell, don't ask +class Inventory { + reserve(items: OrderItem[]): ReserveResult { + // Inventory manages its own state + for (const item of items) { + if (!this.canReserve(item)) { + return ReserveResult.outOfStock(item); + } + } + this.deductStock(items); + return ReserveResult.success(); + } +} + +class Order { + process(inventory: Inventory) { + const result = inventory.reserve(this.items); + if (!result.isSuccess()) { + throw new OutOfStockError(result.failedItem); + } + } +} +``` + +### 7. Speculative Generality + +**Symptom:** "Just in case" abstractions that aren't used. + +```typescript +// SMELL: Over-engineered for hypothetical needs +interface PaymentProcessor { + process(): void; + rollback(): void; + audit(): void; + generateReport(): void; + scheduleRecurring(): void; +} + +class StripeProcessor implements PaymentProcessor { + process() { /* actual code */ } + rollback() { throw new Error('Not implemented'); } + audit() { throw new Error('Not implemented'); } + generateReport() { throw new Error('Not implemented'); } + scheduleRecurring() { throw new Error('Not implemented'); } +} + +// REFACTORED: YAGNI +interface PaymentProcessor { + process(): void; +} + +class StripeProcessor implements PaymentProcessor { + process() { /* actual code */ } +} +// Add other methods when actually needed +``` + +--- + +## Prevention Strategies + +1. **Follow Object Calisthenics** - Rules prevent most smells +2. **Practice TDD** - Tests reveal design problems early +3. **Review in pairs** - Fresh eyes catch smells +4. **Refactor continuously** - Don't let smells accumulate +5. **Apply SOLID** - Prevents structural smells +6. **Use static analysis** - Tools catch common issues + +--- + +## When You Find a Smell + +1. **Confirm it's a problem** - Not all smells need fixing +2. **Ensure test coverage** - Before refactoring +3. **Refactor in small steps** - Keep tests passing +4. **Commit frequently** - Easy to revert if needed diff --git a/.agents/skills/solid/references/complexity.md b/.agents/skills/solid/references/complexity.md new file mode 100644 index 0000000..d7bd7f2 --- /dev/null +++ b/.agents/skills/solid/references/complexity.md @@ -0,0 +1,286 @@ +# Managing Complexity + +## The Two Types of Complexity + +### Essential Complexity +Inherent to the problem domain. Cannot be removed, only managed. +- Business rules +- Domain logic +- User requirements + +### Accidental Complexity +Introduced by our solutions. CAN and SHOULD be minimized. +- Poor abstractions +- Unnecessary indirection +- Framework ceremony +- Technical debt + +**Goal: Minimize accidental complexity while clearly expressing essential complexity.** + +--- + +## Detecting Complexity + +### 1. Change Amplification +Small changes require touching many files. + +**Symptom:** "To add this field, I need to update 15 files." + +**Cause:** Scattered responsibilities, poor abstraction boundaries. + +### 2. Cognitive Load +Code is hard to understand, requires holding too much in memory. + +**Symptom:** "I need to understand 10 other classes to understand this one." + +**Cause:** Tight coupling, hidden dependencies, unclear naming. + +### 3. Unknown Unknowns +Behavior is surprising, side effects are hidden. + +**Symptom:** "I changed this, and something completely unrelated broke." + +**Cause:** Global state, hidden dependencies, implicit contracts. + +--- + +## The XP Values for Fighting Complexity + +From Extreme Programming: + +### 1. Communication +Code should communicate clearly. Names, structure, tests all contribute. + +### 2. Simplicity +Do the simplest thing that could possibly work. + +### 3. Feedback +Fast feedback loops catch complexity early. TDD, CI, code review. + +### 4. Courage +Refactor aggressively. Don't let complexity accumulate. + +### 5. Respect +Respect future readers (including yourself). Write for humans first. + +--- + +## KISS - Keep It Simple, Silly + +> "The simplest solution that works is usually the best." + +### How to Apply: +1. Start with the obvious solution +2. Only add complexity when REQUIRED +3. Prefer boring, well-understood approaches +4. Question every abstraction + +```typescript +// Over-engineered +class UserServiceFactoryProvider { + private static instance: UserServiceFactoryProvider; + + static getInstance(): UserServiceFactoryProvider { ... } + createFactory(): UserServiceFactory { ... } +} + +// KISS +class UserService { + getUser(id: string): User { ... } +} +``` + +--- + +## YAGNI - You Aren't Gonna Need It + +> "Don't build features until they're actually needed." + +### Warning Signs: +- "We might need this later" +- "It would be nice to have" +- "Just in case" +- "For future extensibility" + +### The Cost of YAGNI Violations: +1. **Development time** - Building unused features +2. **Maintenance burden** - Code that must be maintained +3. **Cognitive load** - More to understand +4. **Wrong abstraction** - Guessing future needs incorrectly + +```typescript +// YAGNI violation: Building for hypothetical needs +class User { + // "We might need these someday" + middleName?: string; + secondaryEmail?: string; + faxNumber?: string; + linkedinProfile?: string; + twitterHandle?: string; +} + +// YAGNI: Only what's needed NOW +class User { + name: string; + email: Email; +} +``` + +--- + +## DRY - Don't Repeat Yourself (with The Rule of Three) + +> "Every piece of knowledge should have a single, unambiguous representation." + +### BUT: The Rule of Three + +**Don't extract duplication until you see it THREE times.** + +Why? The wrong abstraction is worse than duplication. + +``` +Duplication #1 → Leave it +Duplication #2 → Note it, leave it +Duplication #3 → NOW extract it +``` + +### Example: +```typescript +// First time - leave it +function processUserOrder(order) { + validate(order); + calculateTax(order); + save(order); +} + +// Second time - note the similarity, but leave it +function processGuestOrder(order) { + validate(order); + calculateTax(order); + save(order); + sendGuestEmail(order); +} + +// Third time - NOW extract +function processCorporateOrder(order) { + validate(order); + calculateTax(order); + save(order); + applyCorporateDiscount(order); +} + +// After three, extract the common parts +function processOrder(order: Order, postProcessing: (o: Order) => void) { + validate(order); + calculateTax(order); + save(order); + postProcessing(order); +} +``` + +--- + +## Separation of Concerns + +> "Each module should address a single concern." + +### Concerns to Separate: +- **Business logic** vs **Infrastructure** +- **What** (policy) vs **How** (mechanism) +- **Input** vs **Processing** vs **Output** +- **Data** vs **Behavior** + +### Example: +```typescript +// BAD: Mixed concerns +class OrderProcessor { + process(order: Order) { + // Validation + if (!order.items.length) throw new Error('Empty'); + + // Business logic + let total = 0; + for (const item of order.items) { + total += item.price * item.quantity; + } + + // Persistence + const db = new Database(); + db.query(`INSERT INTO orders...`); + + // Notification + const email = new EmailClient(); + email.send(order.customer.email, 'Order confirmed'); + } +} + +// GOOD: Separated concerns +class OrderProcessor { + constructor( + private validator: OrderValidator, + private calculator: OrderCalculator, + private repository: OrderRepository, + private notifier: OrderNotifier + ) {} + + process(order: Order): ProcessResult { + this.validator.validate(order); + const total = this.calculator.calculateTotal(order); + const savedOrder = this.repository.save(order); + this.notifier.notifyConfirmation(savedOrder); + return ProcessResult.success(savedOrder); + } +} +``` + +--- + +## Managing Technical Debt + +### Types of Technical Debt: +1. **Deliberate** - Conscious trade-off for speed +2. **Accidental** - Mistakes, lack of knowledge +3. **Bit rot** - Code degrades over time + +### The Boy Scout Rule: +> "Leave the code better than you found it." + +Every time you touch code: +- Improve one small thing +- Fix one naming issue +- Extract one method +- Add one missing test + +### When to Pay Down Debt: +- When it's in your path (you're already there) +- When it's blocking new features +- When it's causing bugs +- During dedicated refactoring time + +### When NOT to Refactor: +- Code that works and won't change +- Code being replaced soon +- When you don't have tests + +--- + +## The Four Elements of Simple Design + +In priority order (from XP): + +1. **Runs all the tests** + - If it doesn't work, nothing else matters + +2. **Expresses intent** + - Clear names, obvious structure + - Code tells the story + +3. **No duplication** + - DRY (but Rule of Three) + - Single source of truth + +4. **Minimal** + - Fewest classes and methods possible + - Remove anything unnecessary + +If these four are true, the design is simple enough. diff --git a/.agents/skills/solid/references/design-patterns.md b/.agents/skills/solid/references/design-patterns.md new file mode 100644 index 0000000..b2a0763 --- /dev/null +++ b/.agents/skills/solid/references/design-patterns.md @@ -0,0 +1,504 @@ +# Design Patterns + +## What Are Design Patterns? + +Reusable solutions to common design problems. A shared vocabulary for discussing design. + +## WARNING: Don't Force Patterns + +> "Let patterns emerge from refactoring, don't force them upfront." + +Patterns should solve problems you HAVE, not problems you MIGHT have. + +## When to Use Patterns + +1. **You recognize the problem** - You've seen it before +2. **The pattern fits** - Not forcing it +3. **It simplifies** - Doesn't add unnecessary complexity +4. **Team understands it** - Shared knowledge + +--- + +## Creational Patterns + +### Singleton + +**Purpose:** Ensure only one instance exists. + +**When to use:** Global configuration, connection pools, logging. + +**Warning:** Often overused. Consider dependency injection instead. + +```typescript +class Logger { + private static instance: Logger; + + private constructor() {} + + static getInstance(): Logger { + if (!Logger.instance) { + Logger.instance = new Logger(); + } + return Logger.instance; + } + + log(message: string): void { ... } +} +``` + +### Factory + +**Purpose:** Create objects without specifying exact class. + +**When to use:** Object creation logic is complex, or varies by type. + +```typescript +interface Notification { + send(message: string): void; +} + +class EmailNotification implements Notification { ... } +class SMSNotification implements Notification { ... } +class PushNotification implements Notification { ... } + +class NotificationFactory { + create(type: 'email' | 'sms' | 'push'): Notification { + switch (type) { + case 'email': return new EmailNotification(); + case 'sms': return new SMSNotification(); + case 'push': return new PushNotification(); + } + } +} +``` + +### Builder + +**Purpose:** Construct complex objects step by step. + +**When to use:** Objects with many optional parameters, test data creation. + +```typescript +class UserBuilder { + private user: Partial = {}; + + withName(name: string): UserBuilder { + this.user.name = name; + return this; + } + + withEmail(email: string): UserBuilder { + this.user.email = email; + return this; + } + + withAge(age: number): UserBuilder { + this.user.age = age; + return this; + } + + build(): User { + return new User( + this.user.name!, + this.user.email!, + this.user.age + ); + } +} + +// Usage +const user = new UserBuilder() + .withName('Alice') + .withEmail('alice@example.com') + .build(); +``` + +### Prototype + +**Purpose:** Create new objects by cloning existing ones. + +**When to use:** Object creation is expensive, or you need copies with slight variations. + +```typescript +interface Prototype { + clone(): Prototype; +} + +class Document implements Prototype { + constructor( + public title: string, + public content: string, + public metadata: Metadata + ) {} + + clone(): Document { + return new Document( + this.title, + this.content, + { ...this.metadata } + ); + } +} +``` + +--- + +## Structural Patterns + +### Adapter + +**Purpose:** Make incompatible interfaces work together. + +**When to use:** Integrating third-party libraries, legacy code. + +```typescript +// Third-party library with different interface +class OldPaymentAPI { + makePayment(cents: number): boolean { ... } +} + +// Our interface +interface PaymentGateway { + charge(amount: Money): ChargeResult; +} + +// Adapter +class OldPaymentAdapter implements PaymentGateway { + constructor(private oldAPI: OldPaymentAPI) {} + + charge(amount: Money): ChargeResult { + const cents = amount.toCents(); + const success = this.oldAPI.makePayment(cents); + return success ? ChargeResult.success() : ChargeResult.failed(); + } +} +``` + +### Decorator + +**Purpose:** Add behavior to objects dynamically. + +**When to use:** Adding features without modifying existing code. + +```typescript +interface Notifier { + send(message: string): void; +} + +class EmailNotifier implements Notifier { + send(message: string): void { + console.log(`Email: ${message}`); + } +} + +// Decorators +class SMSDecorator implements Notifier { + constructor(private wrapped: Notifier) {} + + send(message: string): void { + this.wrapped.send(message); + console.log(`SMS: ${message}`); + } +} + +class SlackDecorator implements Notifier { + constructor(private wrapped: Notifier) {} + + send(message: string): void { + this.wrapped.send(message); + console.log(`Slack: ${message}`); + } +} + +// Usage - compose behaviors +const notifier = new SlackDecorator( + new SMSDecorator( + new EmailNotifier() + ) +); +notifier.send('Alert!'); // Sends to all three +``` + +### Proxy + +**Purpose:** Control access to an object. + +**When to use:** Lazy loading, access control, logging, caching. + +```typescript +interface Image { + display(): void; +} + +class RealImage implements Image { + constructor(private filename: string) { + this.loadFromDisk(); // Expensive + } + + private loadFromDisk(): void { ... } + + display(): void { ... } +} + +// Lazy loading proxy +class ImageProxy implements Image { + private realImage: RealImage | null = null; + + constructor(private filename: string) {} + + display(): void { + if (!this.realImage) { + this.realImage = new RealImage(this.filename); + } + this.realImage.display(); + } +} +``` + +### Composite + +**Purpose:** Treat individual objects and compositions uniformly. + +**When to use:** Tree structures, hierarchies (files/folders, UI components). + +```typescript +interface Component { + getPrice(): number; +} + +class Product implements Component { + constructor(private price: number) {} + + getPrice(): number { + return this.price; + } +} + +class Box implements Component { + private children: Component[] = []; + + add(component: Component): void { + this.children.push(component); + } + + getPrice(): number { + return this.children.reduce( + (sum, child) => sum + child.getPrice(), + 0 + ); + } +} + +// Usage +const smallBox = new Box(); +smallBox.add(new Product(10)); +smallBox.add(new Product(20)); + +const bigBox = new Box(); +bigBox.add(smallBox); +bigBox.add(new Product(50)); + +console.log(bigBox.getPrice()); // 80 +``` + +--- + +## Behavioral Patterns + +### Strategy + +**Purpose:** Define a family of algorithms, make them interchangeable. + +**When to use:** Multiple ways to do something, switchable at runtime. + +```typescript +interface PricingStrategy { + calculate(basePrice: number): number; +} + +class RegularPricing implements PricingStrategy { + calculate(basePrice: number): number { + return basePrice; + } +} + +class PremiumDiscount implements PricingStrategy { + calculate(basePrice: number): number { + return basePrice * 0.8; // 20% off + } +} + +class BlackFriday implements PricingStrategy { + calculate(basePrice: number): number { + return basePrice * 0.5; // 50% off + } +} + +class ShoppingCart { + constructor(private pricing: PricingStrategy) {} + + calculateTotal(items: Item[]): number { + const base = items.reduce((sum, i) => sum + i.price, 0); + return this.pricing.calculate(base); + } +} +``` + +### Observer + +**Purpose:** Notify multiple objects about state changes. + +**When to use:** Event systems, pub/sub, reactive updates. + +```typescript +interface Observer { + update(event: Event): void; +} + +class EventEmitter { + private observers: Observer[] = []; + + subscribe(observer: Observer): void { + this.observers.push(observer); + } + + unsubscribe(observer: Observer): void { + this.observers = this.observers.filter(o => o !== observer); + } + + notify(event: Event): void { + this.observers.forEach(o => o.update(event)); + } +} + +// Usage +class OrderService extends EventEmitter { + placeOrder(order: Order): void { + // Process order... + this.notify({ type: 'ORDER_PLACED', order }); + } +} + +class EmailService implements Observer { + update(event: Event): void { + if (event.type === 'ORDER_PLACED') { + this.sendConfirmation(event.order); + } + } +} +``` + +### Template Method + +**Purpose:** Define algorithm skeleton, let subclasses override steps. + +**When to use:** Common algorithm with varying steps. + +```typescript +abstract class DataExporter { + // Template method - defines the algorithm + export(data: Data[]): void { + this.validate(data); + const formatted = this.format(data); + this.write(formatted); + this.notify(); + } + + // Common steps + private validate(data: Data[]): void { ... } + private notify(): void { ... } + + // Steps to override + protected abstract format(data: Data[]): string; + protected abstract write(content: string): void; +} + +class CSVExporter extends DataExporter { + protected format(data: Data[]): string { + return data.map(d => d.toCSV()).join('\n'); + } + + protected write(content: string): void { + fs.writeFileSync('export.csv', content); + } +} + +class JSONExporter extends DataExporter { + protected format(data: Data[]): string { + return JSON.stringify(data); + } + + protected write(content: string): void { + fs.writeFileSync('export.json', content); + } +} +``` + +### Command + +**Purpose:** Encapsulate a request as an object. + +**When to use:** Undo/redo, queuing, logging actions. + +```typescript +interface Command { + execute(): void; + undo(): void; +} + +class AddItemCommand implements Command { + constructor( + private cart: Cart, + private item: Item + ) {} + + execute(): void { + this.cart.add(this.item); + } + + undo(): void { + this.cart.remove(this.item); + } +} + +class CommandHistory { + private history: Command[] = []; + + execute(command: Command): void { + command.execute(); + this.history.push(command); + } + + undo(): void { + const command = this.history.pop(); + command?.undo(); + } +} +``` + +--- + +## Pattern Awareness + +### The Four-Dimensional Lens + +When analyzing new code/libraries, ask: + +1. **What problem does it solve?** (Creational, Structural, Behavioral) +2. **What scope?** (Object-level, Class-level, System-level) +3. **When is it applied?** (Compile-time, Runtime) +4. **How coupled?** (Tight, Loose) + +This helps recognize patterns even in unfamiliar code. + +--- + +## Anti-Patterns to Avoid + +| Anti-Pattern | Problem | Solution | +|--------------|---------|----------| +| **God Object** | Class does everything | Split by responsibility | +| **Spaghetti Code** | Tangled, no structure | Refactor to layers | +| **Golden Hammer** | Using one pattern for everything | Match pattern to problem | +| **Premature Optimization** | Optimizing before needed | YAGNI, profile first | +| **Copy-Paste Programming** | Duplication | Extract, Rule of Three | diff --git a/.agents/skills/solid/references/object-design.md b/.agents/skills/solid/references/object-design.md new file mode 100644 index 0000000..eb22c86 --- /dev/null +++ b/.agents/skills/solid/references/object-design.md @@ -0,0 +1,328 @@ +# Object-Oriented Design + +## Responsibility-Driven Design (RDD) + +The key insight: **Objects are defined by their responsibilities, not their data.** + +### Finding Objects + +Start with: +1. **Nouns** in requirements → candidate objects +2. **Verbs** → candidate methods/behaviors +3. **Domain concepts** → value objects + +### Finding Responsibilities + +Each object should answer: +- What does this object **know**? +- What does this object **do**? +- What does this object **decide**? + +### Object Stereotypes + +Every class fits one (or maybe two) stereotypes: + +| Stereotype | Purpose | Example | +|------------|---------|---------| +| **Information Holder** | Knows things, holds data | `User`, `Product`, `Address` | +| **Structurer** | Maintains relationships | `OrderItems`, `UserGroup` | +| **Service Provider** | Performs work | `PaymentProcessor`, `EmailSender` | +| **Coordinator** | Orchestrates workflow | `OrderFulfillmentService` | +| **Controller** | Makes decisions, delegates | `CheckoutController` | +| **Interfacer** | Transforms between systems | `UserAPIAdapter`, `DatabaseMapper` | + +### The Two Questions + +For every class, ask: +1. **"What pattern is this?"** - Which stereotype? Which design pattern? +2. **"Is it doing too much?"** - Check object calisthenics rules + +If you can't answer clearly, the class needs refactoring. + +--- + +## Tell, Don't Ask + +**Command objects to do work. Don't interrogate them and do the work yourself.** + +```typescript +// BAD: Asking, then doing +if (account.getBalance() >= amount) { + account.setBalance(account.getBalance() - amount); + // more logic here... +} + +// GOOD: Telling +const result = account.withdraw(amount); +if (result.isSuccess()) { + // ... +} +``` + +The object that has the data should have the behavior. + +--- + +## Design by Contract (DbC) + +Every method has: +- **Preconditions** - What must be true BEFORE calling +- **Postconditions** - What will be true AFTER calling +- **Invariants** - What is ALWAYS true about the object + +```typescript +class BankAccount { + private balance: Money; + + // INVARIANT: balance is never negative + + // PRECONDITION: amount > 0 + // POSTCONDITION: balance decreased by amount OR error returned + withdraw(amount: Money): WithdrawResult { + if (amount.isNegativeOrZero()) { + return WithdrawResult.invalidAmount(); + } + + if (this.balance.isLessThan(amount)) { + return WithdrawResult.insufficientFunds(); + } + + this.balance = this.balance.minus(amount); + return WithdrawResult.success(this.balance); + } +} +``` + +--- + +## Composition Over Inheritance + +**Prefer composing objects over extending classes.** + +### Why Inheritance is Problematic: +- Tight coupling between parent and child +- Fragile base class problem +- Difficult to change parent without breaking children +- Forces "is-a" relationship that may not fit + +### When to Use Inheritance: +- True "is-a" relationship (rare) +- Framework requirements +- Template Method pattern (intentional) + +### Prefer Composition: +```typescript +// BAD: Inheritance +class PremiumUser extends User { + getDiscount(): number { return 20; } +} + +// GOOD: Composition +class User { + constructor(private discountPolicy: DiscountPolicy) {} + + getDiscount(): number { + return this.discountPolicy.calculate(); + } +} + +// Now discount behavior is pluggable +new User(new PremiumDiscount()); +new User(new StandardDiscount()); +new User(new NoDiscount()); +``` + +--- + +## The Law of Demeter (Principle of Least Knowledge) + +**Only talk to your immediate friends.** + +A method should only call: +1. Methods on `this` +2. Methods on parameters +3. Methods on objects it creates +4. Methods on its direct components + +```typescript +// BAD: Reaching through objects +order.getCustomer().getAddress().getCity(); + +// GOOD: Ask the immediate friend +order.getShippingCity(); +``` + +This reduces coupling - changes to `Address` don't ripple through all callers. + +--- + +## Encapsulation + +**Hide internal details, expose behavior.** + +### Levels of Encapsulation: +1. **Data** - private fields, no direct access +2. **Implementation** - how things work internally +3. **Type** - concrete class hidden behind interface +4. **Design** - architectural decisions hidden from clients + +```typescript +// BAD: Exposed internals +class Order { + public items: Item[] = []; + public total: number = 0; +} + +// Client can corrupt state +order.items.push(item); +order.total = -999; // Oops! + +// GOOD: Encapsulated +class Order { + private items: OrderItems; + private total: Money; + + addItem(item: Item): void { + this.items.add(item); + this.recalculateTotal(); + } + + getTotal(): Money { + return this.total; // Returns copy or immutable + } +} +``` + +--- + +## Polymorphism + +**Replace conditionals with types.** + +```typescript +// BAD: Type checking +function calculateShipping(method: string, value: number): number { + if (method === 'standard') return value < 50 ? 5 : 0; + if (method === 'express') return 15; + if (method === 'overnight') return 25; + throw new Error('Unknown method'); +} + +// GOOD: Polymorphism +interface ShippingMethod { + calculateCost(orderValue: number): number; +} + +class StandardShipping implements ShippingMethod { + calculateCost(orderValue: number): number { + return orderValue < 50 ? 5 : 0; + } +} + +class ExpressShipping implements ShippingMethod { + calculateCost(orderValue: number): number { + return 15; + } +} + +// Usage - no conditionals +function calculateShipping(method: ShippingMethod, value: number): number { + return method.calculateCost(value); +} +``` + +--- + +## Value Objects vs Entities + +### Value Objects +- Defined by their attributes (no identity) +- Immutable +- Comparable by value +- Examples: `Money`, `Email`, `Address`, `DateRange` + +```typescript +class Money { + constructor( + private readonly amount: number, + private readonly currency: string + ) {} + + equals(other: Money): boolean { + return this.amount === other.amount && + this.currency === other.currency; + } + + add(other: Money): Money { + if (this.currency !== other.currency) { + throw new CurrencyMismatch(); + } + return new Money(this.amount + other.amount, this.currency); + } +} +``` + +### Entities +- Have identity (survives attribute changes) +- Usually mutable (via methods) +- Comparable by identity +- Examples: `User`, `Order`, `Product` + +```typescript +class User { + constructor( + private readonly id: UserId, + private email: Email, + private name: Name + ) {} + + equals(other: User): boolean { + return this.id.equals(other.id); // Identity comparison + } + + changeEmail(newEmail: Email): void { + this.email = newEmail; // Still same user + } +} +``` + +--- + +## Aggregates + +A cluster of objects treated as a single unit for data changes. + +- One object is the **aggregate root** (entry point) +- External code only references the root +- Root enforces invariants for the entire cluster + +```typescript +// Order is the aggregate root +class Order { + private items: OrderItem[] = []; + + // All access through the root + addItem(product: Product, quantity: number): void { + const item = new OrderItem(product, quantity); + this.items.push(item); + this.validateTotal(); + } + + removeItem(itemId: ItemId): void { + this.items = this.items.filter(i => !i.id.equals(itemId)); + } + + // Root enforces invariants + private validateTotal(): void { + if (this.calculateTotal().exceeds(MAX_ORDER_VALUE)) { + throw new OrderTotalExceeded(); + } + } +} + +// BAD: Accessing items directly +order.items.push(new OrderItem(...)); // Bypasses validation! + +// GOOD: Through the root +order.addItem(product, 2); // Validation happens +``` diff --git a/.agents/skills/solid/references/solid-principles.md b/.agents/skills/solid/references/solid-principles.md new file mode 100644 index 0000000..4fef136 --- /dev/null +++ b/.agents/skills/solid/references/solid-principles.md @@ -0,0 +1,262 @@ +# SOLID Principles + +## Overview + +SOLID helps structure software to be flexible, maintainable, and testable. These principles reduce coupling and increase cohesion. + +## S - Single Responsibility Principle (SRP) + +> "A class should have one, and only one, reason to change." + +### Problem It Solves +God objects that do everything - hard to test, hard to change, hard to understand. + +### How to Apply +Each class handles ONE responsibility. If you find yourself saying "and" when describing what a class does, split it. + +```typescript +// BAD: Multiple responsibilities +class Order { + calculateTotal(): number { ... } + saveToDatabase(): void { ... } // Persistence + generateInvoice(): string { ... } // Presentation +} + +// GOOD: Single responsibility each +class Order { + private items: OrderItem[] = []; + + addItem(item: OrderItem): void { ... } + calculateTotal(): number { ... } +} + +class OrderRepository { + save(order: Order): Promise { ... } +} + +class InvoiceGenerator { + generate(order: Order): Invoice { ... } +} +``` + +### Detection Questions +- Does this class have multiple reasons to change? +- Can I describe it without using "and"? +- Would different stakeholders request changes to different parts? + +--- + +## O - Open/Closed Principle (OCP) + +> "Software entities should be open for extension but closed for modification." + +### Problem It Solves +Having to modify existing, tested code every time requirements change. Risk of breaking working features. + +### How to Apply +Design abstractions that allow new behavior through new classes, not edits to existing ones. + +```typescript +// BAD: Must modify to add new shipping +class ShippingCalculator { + calculate(type: string, value: number): number { + if (type === 'standard') return value < 50 ? 5 : 0; + if (type === 'express') return 15; + // Must add more ifs for new types! + } +} + +// GOOD: Open for extension +interface ShippingMethod { + calculateCost(orderValue: number): number; +} + +class StandardShipping implements ShippingMethod { + calculateCost(orderValue: number): number { + return orderValue < 50 ? 5 : 0; + } +} + +class ExpressShipping implements ShippingMethod { + calculateCost(orderValue: number): number { + return 15; + } +} + +// Add new shipping by creating new class, not modifying existing +class SameDayShipping implements ShippingMethod { + calculateCost(orderValue: number): number { + return 25; + } +} +``` + +### Architectural Insight +OCP at architecture level means: **design your codebase so new features are added by adding code, not changing existing code.** + +--- + +## L - Liskov Substitution Principle (LSP) + +> "Subtypes must be substitutable for their base types without altering program correctness." + +### Problem It Solves +Subclasses that break expectations, requiring type-checking and special cases. + +### How to Apply +Subclasses must honor the contract of the parent. If the parent returns positive numbers, subclasses cannot return negatives. + +```typescript +// BAD: Violates parent's contract +class DiscountPolicy { + getDiscount(value: number): number { + return 0; // Non-negative expected + } +} + +class WeirdDiscount extends DiscountPolicy { + getDiscount(value: number): number { + return -5; // Increases cost! Breaks expectations + } +} + +// GOOD: Enforces contract +class DiscountPolicy { + constructor(private discount: number) { + if (discount < 0) throw new Error("Discount must be non-negative"); + } + + getDiscount(): number { + return this.discount; + } +} +``` + +### Key Insight +This is why you can swap `InMemoryUserRepo` for `PostgresUserRepo` - they both honor the `UserRepo` interface contract. + +--- + +## I - Interface Segregation Principle (ISP) + +> "Clients should not be forced to depend on methods they do not use." + +### Problem It Solves +Fat interfaces that force partial implementations, empty methods, or throws. + +### How to Apply +Split large interfaces into smaller, cohesive ones. Clients depend only on what they need. + +```typescript +// BAD: Fat interface +interface WarehouseDevice { + printLabel(orderId: string): void; + scanBarcode(): string; + packageItem(orderId: string): void; +} + +class BasicPrinter implements WarehouseDevice { + printLabel(orderId: string): void { /* works */ } + scanBarcode(): string { throw new Error("Not supported"); } // Forced! + packageItem(orderId: string): void { throw new Error("Not supported"); } +} + +// GOOD: Segregated interfaces +interface LabelPrinter { + printLabel(orderId: string): void; +} + +interface BarcodeScanner { + scanBarcode(): string; +} + +interface ItemPackager { + packageItem(orderId: string): void; +} + +class BasicPrinter implements LabelPrinter { + printLabel(orderId: string): void { /* only what it does */ } +} +``` + +### Detection +If you see `throw new Error("Not implemented")` or empty method bodies, the interface is too fat. + +--- + +## D - Dependency Inversion Principle (DIP) + +> "High-level modules should not depend on low-level modules. Both should depend on abstractions." + +### Problem It Solves +Tight coupling to specific implementations (databases, APIs, frameworks). Hard to test, hard to swap. + +### How to Apply +Depend on interfaces, inject implementations. + +```typescript +// BAD: Direct dependency on concrete class +class OrderService { + private emailService = new SendGridEmailService(); // Locked in! + + confirmOrder(email: string): void { + this.emailService.send(email, "Order confirmed"); + } +} + +// GOOD: Depend on abstraction +interface EmailService { + send(to: string, message: string): void; +} + +class OrderService { + constructor(private emailService: EmailService) {} + + confirmOrder(email: string): void { + this.emailService.send(email, "Order confirmed"); + } +} + +// Now can inject any implementation +new OrderService(new SendGridEmailService()); +new OrderService(new SESEmailService()); +new OrderService(new MockEmailService()); // For tests! +``` + +### The Dependency Rule +Source code dependencies should point **inward** toward high-level policies (domain logic), never toward low-level details (infrastructure). + +``` +Infrastructure → Application → Domain + ↑ ↑ ↑ + (outer) (middle) (inner) + +Dependencies flow: outer → inner +Never: inner → outer +``` + +--- + +## Applying SOLID at Architecture Level + +These principles scale beyond classes: + +| Principle | Architecture Application | +|-----------|--------------------------| +| SRP | Each bounded context has one responsibility | +| OCP | New features = new modules, not edits to existing | +| LSP | Microservices with same contract are substitutable | +| ISP | Thin interfaces between services | +| DIP | High-level business logic doesn't know about databases/frameworks | + +--- + +## Quick Reference + +| Principle | One-Liner | Red Flag | +|-----------|-----------|----------| +| SRP | One reason to change | "This class handles X and Y and Z" | +| OCP | Add, don't modify | `if/else` chains for types | +| LSP | Subtypes are substitutable | Type-checking in calling code | +| ISP | Small, focused interfaces | Empty method implementations | +| DIP | Depend on abstractions | `new ConcreteClass()` in business logic | diff --git a/.agents/skills/solid/references/tdd.md b/.agents/skills/solid/references/tdd.md new file mode 100644 index 0000000..3316198 --- /dev/null +++ b/.agents/skills/solid/references/tdd.md @@ -0,0 +1,152 @@ +# Test-Driven Development + +## The Core Loop + +``` +RED → GREEN → REFACTOR → RED → ... +``` + +### RED Phase +Write a failing test that describes the behavior you want. The test should: +- Use domain language, not technical jargon +- Describe WHAT, not HOW +- Be a concrete example, not an abstract statement + +```typescript +// BAD: Abstract +it('can add numbers', () => { ... }); + +// GOOD: Concrete example +it('when adding 2 + 3, returns 5', () => { ... }); +``` + +### GREEN Phase +Write the **simplest possible code** to make the test pass. Two strategies: + +1. **Fake It** - Return a hardcoded value + ```typescript + add(a: number, b: number): number { + return 5; // Simplest thing! + } + ``` + +2. **Obvious Implementation** - If you know the solution + ```typescript + add(a: number, b: number): number { + return a + b; + } + ``` + +**Prefer Fake It** when learning or unsure. Let more tests drive the real implementation. + +### REFACTOR Phase +This is where **design happens**. Look for: +- Duplication (but wait for Rule of Three) +- Long methods to extract +- Poor names to improve +- Complex conditions to simplify + +## The Three Laws of TDD + +1. **No production code** without a failing test +2. **No more test code** than sufficient to fail (compilation failures count) +3. **No more production code** than sufficient to pass the one failing test + +## The Rule of Three + +**Only extract duplication when you see it THREE times.** + +Why? Wrong abstractions are worse than duplication. Wait for the pattern to emerge. + +```typescript +// Duplication #1 - Leave it +// Duplication #2 - Note it, leave it +// Duplication #3 - NOW extract it +``` + +## Triangulation + +Each new test "sculpts" the solution toward a general, robust implementation. + +Think of **degrees of freedom** - like a car that needs forward/back, left/right, and rotation. Each test carves out one degree of freedom until the implementation handles all cases. + +## Transformation Priority Premise + +When going from RED to GREEN, prefer simpler transformations: + +| Priority | Transformation | +|----------|----------------| +| 1 | {} → nil | +| 2 | nil → constant | +| 3 | constant → variable | +| 4 | unconditional → conditional | +| 5 | scalar → collection | +| 6 | statement → recursion | +| 7 | value → mutated value | + +Higher priority = simpler. Avoid jumping to complex transformations too early. + +## Arrange-Act-Assert + +Structure every test: + +```typescript +it('calculates total with discount', () => { + // ARRANGE - Set up the world + const order = new Order(); + order.addItem({ price: 100 }); + const discount = new PercentDiscount(10); + + // ACT - Execute the behavior + const total = order.calculateTotal(discount); + + // ASSERT - Verify the outcome + expect(total).toBe(90); +}); +``` + +## Writing Tests Backwards + +Sometimes it helps to write AAA in reverse: +1. Write the ASSERT first - what do you want to verify? +2. Write the ACT - what action produces that result? +3. Write the ARRANGE - what setup is needed? + +## Test Naming Principles + +- Use **behavior-driven names** with domain language +- Provide **concrete examples**, not abstract statements +- **One example per test** for easy debugging +- Avoid leaking implementation details + +```typescript +// BAD: Technical, implementation-focused +it('should set the data property to 1', () => { ... }); + +// GOOD: Behavior-focused, domain language +it('should recognize "mom" as a palindrome', () => { ... }); +``` + +## Classic vs Mockist TDD + +**Classic (Detroit/Chicago) TDD:** +- Test with real dependencies +- Higher confidence, slower tests +- Best for: Pure functions, integration tests + +**Mockist (London) TDD:** +- Mock external dependencies +- Faster tests, more isolated +- Best for: Classes with infrastructure dependencies + +Start with Classic TDD to learn the technique. Add mocks when testing code with databases, APIs, etc. + +## Common Mistakes + +1. **Writing code before tests** - Violates the fundamental principle +2. **Writing too much test** - Just enough to fail +3. **Writing too much code** - Just enough to pass +4. **Skipping refactor** - This is where design lives +5. **Testing implementation** - Test behavior, not how it's done +6. **Abstract test names** - Use concrete examples +7. **Extracting too early** - Wait for Rule of Three diff --git a/.agents/skills/solid/references/testing.md b/.agents/skills/solid/references/testing.md new file mode 100644 index 0000000..83d415f --- /dev/null +++ b/.agents/skills/solid/references/testing.md @@ -0,0 +1,396 @@ +# Testing Strategy + +## The Testing Pyramid + +``` + /\ + / \ E2E Tests (Few) + /----\ - Full system + / \ - Slow, brittle + /--------\ + / \ Integration Tests (Some) + /------------\ - Multiple components +/ \ - Medium speed +---------------- + Unit Tests (Many) + - Single unit + - Fast, isolated +``` + +## Test Types + +### Unit Tests + +Test ONE class or function in isolation. + +**Characteristics:** +- Fast (milliseconds) +- No external dependencies (mocked) +- Most of your tests should be unit tests + +```typescript +describe('Order', () => { + it('calculates total correctly', () => { + const order = new Order(); + order.addItem({ price: 100 }); + order.addItem({ price: 50 }); + + expect(order.calculateTotal()).toBe(150); + }); +}); +``` + +### Integration Tests + +Test multiple components together. + +**Characteristics:** +- Slower (may use real DB) +- Test boundaries between components +- Fewer than unit tests + +```typescript +describe('OrderService Integration', () => { + let db: Database; + let service: OrderService; + + beforeAll(async () => { + db = await Database.connect(); + service = new OrderService(new PostgresOrderRepo(db)); + }); + + it('saves and retrieves an order', async () => { + const order = Order.create({ customerId: '123' }); + await service.save(order); + + const retrieved = await service.findById(order.id); + expect(retrieved).toEqual(order); + }); +}); +``` + +### E2E / Acceptance Tests + +Test the entire system from user perspective. + +**Characteristics:** +- Slowest +- Most brittle (many moving parts) +- Test critical paths only + +```typescript +describe('Checkout Flow', () => { + it('user can complete purchase', async () => { + await page.goto('/products'); + await page.click('[data-testid="add-to-cart"]'); + await page.click('[data-testid="checkout"]'); + await page.fill('[name="card"]', '4242424242424242'); + await page.click('[data-testid="pay"]'); + + expect(await page.textContent('h1')).toBe('Order Confirmed'); + }); +}); +``` + +--- + +## Arrange-Act-Assert (AAA) + +Structure EVERY test this way: + +```typescript +it('applies discount to premium users', () => { + // ARRANGE - Set up the test world + const user = new User({ isPremium: true }); + const cart = new Cart(user); + cart.addItem({ price: 100 }); + + // ACT - Execute the behavior under test + const total = cart.calculateTotal(); + + // ASSERT - Verify the expected outcome + expect(total).toBe(80); // 20% discount +}); +``` + +### Writing AAA Backwards + +Sometimes easier to write in reverse: + +1. **Assert first** - What do you want to verify? +2. **Act** - What action produces that result? +3. **Arrange** - What setup is needed? + +--- + +## Test Naming + +### Bad: Abstract, Technical + +```typescript +it('should work correctly') +it('handles the edge case') +it('sets the data property') +``` + +### Good: Concrete Examples, Domain Language + +```typescript +it('calculates 20% discount for premium users') +it('returns error when cart is empty') +it('recognizes "racecar" as a palindrome') +``` + +### Format + +```typescript +// Option 1: should + behavior +it('should apply tax based on shipping state') + +// Option 2: when + then +it('when adding 2 + 3, then returns 5') + +// Option 3: Given-When-Then (for complex scenarios) +describe('given a premium user', () => { + describe('when they checkout', () => { + it('then they receive 20% discount', () => { ... }); + }); +}); +``` + +--- + +## Test Doubles + +### Dummy + +Object passed but never used. + +```typescript +const dummyLogger = {} as Logger; +new UserService(realRepo, dummyLogger); +``` + +### Stub + +Returns predefined values. + +```typescript +const stubRepo: UserRepo = { + findById: () => Promise.resolve(new User({ name: 'Test' })), + save: () => Promise.resolve(), +}; +``` + +### Spy + +Records how it was called. + +```typescript +const emailSpy = { + sentEmails: [] as string[], + send(to: string, message: string) { + this.sentEmails.push(to); + } +}; + +// Later +expect(emailSpy.sentEmails).toContain('user@example.com'); +``` + +### Mock + +Verifies expected interactions. + +```typescript +const mockRepo = jest.fn(); +mockRepo.save.mockResolvedValue(undefined); + +// After test +expect(mockRepo.save).toHaveBeenCalledWith(expectedUser); +``` + +### Fake + +Working implementation (simplified). + +```typescript +class InMemoryUserRepo implements UserRepo { + private users: Map = new Map(); + + async save(user: User): Promise { + this.users.set(user.id, user); + } + + async findById(id: string): Promise { + return this.users.get(id) || null; + } +} +``` + +--- + +## Testing Strategies by Layer + +### Domain Layer (Most Tests) + +- Unit tests with no mocks +- Test business rules, value objects, entities +- Fast, comprehensive + +```typescript +describe('Money', () => { + it('adds amounts with same currency', () => { + const a = Money.dollars(10); + const b = Money.dollars(20); + expect(a.add(b).equals(Money.dollars(30))).toBe(true); + }); + + it('throws when adding different currencies', () => { + const usd = Money.dollars(10); + const eur = Money.euros(10); + expect(() => usd.add(eur)).toThrow(CurrencyMismatch); + }); +}); +``` + +### Application Layer + +- Integration tests with mocked infrastructure +- Test use case orchestration + +```typescript +describe('CreateOrderUseCase', () => { + it('creates order and sends confirmation', async () => { + const orderRepo = new InMemoryOrderRepo(); + const emailService = { send: jest.fn() }; + const useCase = new CreateOrderUseCase(orderRepo, emailService); + + await useCase.execute({ customerId: '123', items: [...] }); + + expect(orderRepo.count()).toBe(1); + expect(emailService.send).toHaveBeenCalled(); + }); +}); +``` + +### Infrastructure Layer + +- Integration tests with real dependencies +- Test database, API integrations + +```typescript +describe('PostgresOrderRepo', () => { + let repo: PostgresOrderRepo; + + beforeAll(async () => { + repo = new PostgresOrderRepo(testDb); + }); + + it('persists and retrieves order', async () => { + const order = Order.create({ ... }); + await repo.save(order); + + const found = await repo.findById(order.id); + expect(found).toEqual(order); + }); +}); +``` + +--- + +## High-Value Integration Tests + +Focus integration tests on: + +1. **Boundaries** - Where systems meet +2. **Critical paths** - Money, security, core features +3. **Complex queries** - Database operations + +### Contract Tests + +Verify implementations match interfaces. + +```typescript +// Shared contract test +function testUserRepoContract(createRepo: () => UserRepo) { + describe('UserRepo Contract', () => { + let repo: UserRepo; + + beforeEach(() => { + repo = createRepo(); + }); + + it('saves and retrieves user', async () => { + const user = User.create({ name: 'Test' }); + await repo.save(user); + const found = await repo.findById(user.id); + expect(found).toEqual(user); + }); + + it('returns null for missing user', async () => { + const found = await repo.findById('nonexistent'); + expect(found).toBeNull(); + }); + }); +} + +// Apply to all implementations +testUserRepoContract(() => new InMemoryUserRepo()); +testUserRepoContract(() => new PostgresUserRepo(testDb)); +``` + +--- + +## Test Builders + +Create test objects easily. + +```typescript +class OrderBuilder { + private props: Partial = { + id: 'order-1', + customerId: 'cust-1', + items: [], + status: 'pending', + }; + + withId(id: string): OrderBuilder { + this.props.id = id; + return this; + } + + withItems(items: Item[]): OrderBuilder { + this.props.items = items; + return this; + } + + paid(): OrderBuilder { + this.props.status = 'paid'; + return this; + } + + build(): Order { + return Order.create(this.props as OrderProps); + } +} + +// Usage +const order = new OrderBuilder() + .withItems([{ sku: 'ABC', price: 100 }]) + .paid() + .build(); +``` + +--- + +## Common Testing Mistakes + +| Mistake | Problem | Solution | +|---------|---------|----------| +| Testing implementation | Brittle tests | Test behavior only | +| Too many mocks | Tests prove nothing | Use real objects when possible | +| Shared state | Flaky tests | Isolate each test | +| No assertions | False confidence | Always assert something meaningful | +| Testing trivial code | Wasted effort | Focus on logic and edge cases | +| Slow tests | Reduced feedback | Optimize, use unit tests | diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..a5bc8cb --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,33 @@ +name: Release + +on: + release: + types: [released] + +jobs: + release_image: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Docker + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm/v7 + push: true + tags: ghcr.io/taskiq-python/taskiq-admin:latest,ghcr.io/taskiq-python/taskiq-admin:${{ github.ref_name }} diff --git a/.gitignore b/.gitignore index daf5218..7b56edb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ *.db +dbschema.sql +*.db-shm +*.db-wal +.data # Nuxt dev/build outputs .output diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 0000000..cd874ec --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,13 @@ +/** + * @see https://prettier.io/docs/configuration + * @type {import("prettier").Config} + */ +const config = { + trailingComma: 'none', + tabWidth: 2, + semi: false, + singleQuote: true, + singleAttributePerLine: true +} + +module.exports = config diff --git a/docker/Dockerfile b/Dockerfile similarity index 71% rename from docker/Dockerfile rename to Dockerfile index 84fc1a2..c1239d8 100644 --- a/docker/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG NODE_VERSION=22.12.0 +ARG NODE_VERSION=22.14.0 FROM node:${NODE_VERSION}-slim AS build @@ -9,10 +9,13 @@ RUN corepack enable WORKDIR /app +ENV TASKIQ_ADMIN_DB_DRIVER=sqlite +ENV TASKIQ_ADMIN_DB_FILE_PATH=/tmp/taskiq-admin.db + # install dependencies COPY ./package.json /app/ COPY ./pnpm-lock.yaml /app/ -RUN pnpm install --shamefully-hoist +RUN pnpm install --frozen-lockfile # copy other files COPY . ./ @@ -33,8 +36,9 @@ COPY --from=build /app/entrypoint.sh /usr/app/entrypoint.sh EXPOSE 3000 ENV HOST=0.0.0.0 NODE_ENV=production -ENV DB_FILE_PATH=/usr/database/database.db -ENV BACKUP_FILE_PATH=/usr/database/backup.db +ENV TASKIQ_ADMIN_DB_DRIVER=sqlite +ENV TASKIQ_ADMIN_DB_FILE_PATH=/usr/database/database.db +ENV TASKIQ_ADMIN_BACKUP_FILE_PATH=/usr/database/backup.db RUN npm install dotenv diff --git a/README.md b/README.md index 963c355..86191f0 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,134 @@ ## Broker-agnostic admin panel for Taskiq -Standalone admin panel with all data stored in SQLite database - +Standalone admin panel with task results storage in SQLite or Postgres database - [Broker-agnostic admin panel for Taskiq](#broker-agnostic-admin-panel-for-taskiq) - [Previews](#previews) - [Usage](#usage) + - [Docker Compose Example](#docker-compose-example) + - [Running without Docker](#running-without-docker) + - [Task States](#task-states) - [Development](#development) ### Previews -Tasks Page | Task Details Page -:-------------------------:|:-------------------------: -![Alt text](./docs/images/preview1.png) | ![Alt text](./docs/images/preview2.png) + +| Tasks Page | Task Details Page | +| :-------------------------------------: | :-------------------------------------: | +| ![Alt text](./docs/images/preview1.png) | ![Alt text](./docs/images/preview2.png) | ### Usage -1) Add this middleware to your taskiq broker: +1. Import and connect the middleware to the broker: ```python -from typing import Any -from datetime import datetime, UTC - -import httpx -from taskiq import TaskiqMiddleware, TaskiqResult, TaskiqMessage - -TASKIQ_ADMIN_URL = "..." # or your env vars from .env -TASKIQ_ADMIN_API_TOKEN = "..." # or your env vars from .env - - -class TaskiqAdminMiddleware(TaskiqMiddleware): - async def pre_execute(self, message: TaskiqMessage): - """""" - - async with httpx.AsyncClient() as client: - await client.post( - headers={"access-token": TASKIQ_ADMIN_API_TOKEN}, - url=f"{TASKIQ_ADMIN_URL}/tasks/{message.task_id}/started", - json={ - "worker": "WIP", - "args": message.args, - "kwargs": message.kwargs, - "taskName": message.task_name, - "startedAt": datetime.now(UTC) - .replace(tzinfo=None) - .isoformat(), - }, - ) - - return super().pre_execute(message) - - async def post_execute( - self, - message: TaskiqMessage, - result: TaskiqResult[Any], - ): - """""" - - async with httpx.AsyncClient() as client: - await client.post( - headers={"access-token": TASKIQ_ADMIN_API_TOKEN}, - url=f"{TASKIQ_ADMIN_URL}/tasks/{message.task_id}/executed", - json={ - "error": result.error - if result.error is None - else repr(result.error), - "result": result.return_value, - "returnValue": result.return_value, - "executionTime": result.execution_time, - "finishedAt": datetime.now(UTC) - .replace(tzinfo=None) - .isoformat(), - }, - ) - - return super().post_execute(message, result) +... +from taskiq.middlewares.taskiq_admin_middleware import TaskiqAdminMiddleware + +broker = ( + RedisStreamBroker( + url=redis_url, + queue_name="my_lovely_queue", + ) + .with_result_backend(result_backend) + .with_middlewares( + TaskiqAdminMiddleware( + url="http://localhost:3000", # the url to your taskiq-admin instance + api_token="supersecret", # any secret enough string + taskiq_broker_name="mybroker", + ) + ) +) +... ``` -2) Pull the image from DockerHub: `docker pull artur10/taskiq-admin:latest` +2. Pull the image from GitHub Container Registry: `docker pull ghcr.io/taskiq-python/taskiq-admin:latest` + +3. Replace `TASKIQ_ADMIN_API_TOKEN` with any secret enough string and run: -3) Replace `ACCESS_TOKEN` with any secret enough string and run: ```bash docker run -d --rm \ -p "3000:3000" \ - -v ./taskiq-admin-data/:/usr/database/ \ - -e TASKIQ_ADMIN_API_TOKEN=supersecret \ - --name taskiq-admin \ - artur10/taskiq-admin:latest + -v "./taskiq-admin-data/:/usr/database/" \ + -e "TASKIQ_ADMIN_API_TOKEN=supersecret" \ + --name "taskiq-admin" \ + "ghcr.io/taskiq-python/taskiq-admin:latest" +``` + +4. Go to `http://localhost:3000/tasks` + +### Docker Compose Example + +```yaml +services: + queue: + build: + context: . + dockerfile: ./Dockerfile + container_name: my_queue + command: taskiq worker app.tasks.queue:broker --workers 1 --max-async-tasks 20 + environment: + - TASKIQ_ADMIN_URL=http://taskiq_admin:3000 + - TASKIQ_ADMIN_API_TOKEN=supersecret + depends_on: + - redis + - taskiq_admin + + taskiq_admin: + image: ghcr.io/taskiq-python/taskiq-admin:latest + container_name: taskiq_admin + ports: + - 3000:3000 + environment: + - TASKIQ_ADMIN_API_TOKEN=supersecret + volumes: + - admin_data:/usr/database/ + +volumes: + admin_data: +``` + +### Running without Docker + +1. `cp env-example .env`, enter `.env` file and fill in all needed variables +2. run `make dev` to run it locally in dev mode +3. run `make prod` to run it locally in prod mode + +Environment variables for DB setup: + +- `TASKIQ_ADMIN_DB_DRIVER`: required, one of `sqlite` or `postgres` +- `TASKIQ_ADMIN_DB_FILE_PATH`: required when `TASKIQ_ADMIN_DB_DRIVER=sqlite` +- `TASKIQ_ADMIN_DB_URL`: required when `TASKIQ_ADMIN_DB_DRIVER=postgres` + +#### Postgres and `pg_trgm` (optional) + +Task name search uses a case-insensitive substring match. On postgres it is backed by a +`pg_trgm` GIN index, which taskiq-admin creates on startup. + +This is a performance optimization, not a requirement: if the extension cannot be created, +search keeps returning the same results, it just does a sequential scan over the tasks table. +A warning is logged once at startup when that happens. + +`pg_trgm` ships with the standard `postgresql-contrib` package (included in the official +postgres Docker images) and is a trusted extension since postgres 13, so the database owner +can create it without superuser rights. If the role in `TASKIQ_ADMIN_DB_URL` is neither owner +nor superuser, create it once by hand: + +```sql +CREATE EXTENSION IF NOT EXISTS pg_trgm; ``` -4) Go to `http://localhost:3000/tasks` +### Task States + +Let's assume we have a task 'do_smth', there are all states it can embrace: + +1. `queued` - the task has been sent to the queue without an error +2. `running` - the task is grabbed by a worker and is being processed +3. `success` - the task is fully processed without any errors +4. `failure` - an error occured during the task processing +5. `abandoned` - taskiq-admin sets all 'running' tasks as 'abandoned' if there was a downtime between the time these tasks were in 'running' state and the time of next startup of taskiq-admin ### Development -1) Run `pnpm install` to install all dependencies -2) Run `pnpm db:push` to create the sqlite database if needed -3) Run `pnpm dev` to run the project \ No newline at end of file + +1. Run `pnpm install` to install all dependencies +2. Run `pnpm db:push` to create the sqlite database if needed +3. Run `pnpm dev` to run the project diff --git a/app/app.vue b/app/app.vue new file mode 100644 index 0000000..9b20194 --- /dev/null +++ b/app/app.vue @@ -0,0 +1,20 @@ + + + + diff --git a/app/assets/css/main.css b/app/assets/css/main.css new file mode 100644 index 0000000..e7fdcf4 --- /dev/null +++ b/app/assets/css/main.css @@ -0,0 +1,133 @@ +@import 'tailwindcss'; + +@custom-variant dark (&:is(.dark *)); + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.145 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.985 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.269 0 0); + --input: oklch(0.269 0 0); + --ring: oklch(0.439 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(0.269 0 0); + --sidebar-ring: oklch(0.439 0 0); +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + ::-webkit-scrollbar { + @apply w-2.5 h-2.5; + } + + ::-webkit-scrollbar-track { + @apply bg-transparent; + } + + ::-webkit-scrollbar-thumb { + @apply rounded-full bg-border border-[1px] border-transparent border-solid bg-clip-padding; + } +} diff --git a/app/components/header.vue b/app/components/header.vue new file mode 100644 index 0000000..f037af9 --- /dev/null +++ b/app/components/header.vue @@ -0,0 +1,48 @@ + + diff --git a/app/components/range-picker.vue b/app/components/range-picker.vue new file mode 100644 index 0000000..55d257d --- /dev/null +++ b/app/components/range-picker.vue @@ -0,0 +1,82 @@ + + + diff --git a/app/components/sortable-arrow.vue b/app/components/sortable-arrow.vue new file mode 100644 index 0000000..9ac7c02 --- /dev/null +++ b/app/components/sortable-arrow.vue @@ -0,0 +1,29 @@ + + + diff --git a/app/components/task-state.vue b/app/components/task-state.vue new file mode 100644 index 0000000..74aed96 --- /dev/null +++ b/app/components/task-state.vue @@ -0,0 +1,22 @@ + + diff --git a/app/components/tasks-table.vue b/app/components/tasks-table.vue new file mode 100644 index 0000000..3dca51a --- /dev/null +++ b/app/components/tasks-table.vue @@ -0,0 +1,204 @@ + + + diff --git a/app/components/theme.vue b/app/components/theme.vue new file mode 100644 index 0000000..4375f22 --- /dev/null +++ b/app/components/theme.vue @@ -0,0 +1,36 @@ + + + diff --git a/app/components/ui/button/Button.vue b/app/components/ui/button/Button.vue new file mode 100644 index 0000000..0e91bd2 --- /dev/null +++ b/app/components/ui/button/Button.vue @@ -0,0 +1,29 @@ + + + diff --git a/app/components/ui/button/index.ts b/app/components/ui/button/index.ts new file mode 100644 index 0000000..7779332 --- /dev/null +++ b/app/components/ui/button/index.ts @@ -0,0 +1,37 @@ +import type { VariantProps } from 'class-variance-authority' +import { cva } from 'class-variance-authority' + +export { default as Button } from './Button.vue' + +export const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: + 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: + 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50', + link: 'text-primary underline-offset-4 hover:underline' + }, + size: { + default: 'h-9 px-4 py-2 has-[>svg]:px-3', + sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5', + lg: 'h-10 rounded-md px-6 has-[>svg]:px-4', + icon: 'size-9', + 'icon-sm': 'size-8', + 'icon-lg': 'size-10' + } + }, + defaultVariants: { + variant: 'default', + size: 'default' + } + } +) +export type ButtonVariants = VariantProps diff --git a/app/components/ui/calendar/Calendar.vue b/app/components/ui/calendar/Calendar.vue new file mode 100644 index 0000000..dac3a3c --- /dev/null +++ b/app/components/ui/calendar/Calendar.vue @@ -0,0 +1,63 @@ + + + diff --git a/app/components/ui/calendar/CalendarCell.vue b/app/components/ui/calendar/CalendarCell.vue new file mode 100644 index 0000000..bc873ed --- /dev/null +++ b/app/components/ui/calendar/CalendarCell.vue @@ -0,0 +1,25 @@ + + + diff --git a/app/components/ui/calendar/CalendarCellTrigger.vue b/app/components/ui/calendar/CalendarCellTrigger.vue new file mode 100644 index 0000000..3a52b73 --- /dev/null +++ b/app/components/ui/calendar/CalendarCellTrigger.vue @@ -0,0 +1,41 @@ + + + diff --git a/app/components/ui/calendar/CalendarGrid.vue b/app/components/ui/calendar/CalendarGrid.vue new file mode 100644 index 0000000..4227b56 --- /dev/null +++ b/app/components/ui/calendar/CalendarGrid.vue @@ -0,0 +1,25 @@ + + + diff --git a/app/components/ui/calendar/CalendarGridBody.vue b/app/components/ui/calendar/CalendarGridBody.vue new file mode 100644 index 0000000..7b2bf41 --- /dev/null +++ b/app/components/ui/calendar/CalendarGridBody.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ui/calendar/CalendarGridHead.vue b/app/components/ui/calendar/CalendarGridHead.vue new file mode 100644 index 0000000..3ba322b --- /dev/null +++ b/app/components/ui/calendar/CalendarGridHead.vue @@ -0,0 +1,15 @@ + + + diff --git a/app/components/ui/calendar/CalendarGridRow.vue b/app/components/ui/calendar/CalendarGridRow.vue new file mode 100644 index 0000000..a6909d9 --- /dev/null +++ b/app/components/ui/calendar/CalendarGridRow.vue @@ -0,0 +1,24 @@ + + + diff --git a/app/components/ui/calendar/CalendarHeadCell.vue b/app/components/ui/calendar/CalendarHeadCell.vue new file mode 100644 index 0000000..ed9f523 --- /dev/null +++ b/app/components/ui/calendar/CalendarHeadCell.vue @@ -0,0 +1,25 @@ + + + diff --git a/app/components/ui/calendar/CalendarHeader.vue b/app/components/ui/calendar/CalendarHeader.vue new file mode 100644 index 0000000..efac13d --- /dev/null +++ b/app/components/ui/calendar/CalendarHeader.vue @@ -0,0 +1,25 @@ + + + diff --git a/app/components/ui/calendar/CalendarHeading.vue b/app/components/ui/calendar/CalendarHeading.vue new file mode 100644 index 0000000..f49bf3b --- /dev/null +++ b/app/components/ui/calendar/CalendarHeading.vue @@ -0,0 +1,32 @@ + + + diff --git a/app/components/ui/calendar/CalendarNextButton.vue b/app/components/ui/calendar/CalendarNextButton.vue new file mode 100644 index 0000000..71030ad --- /dev/null +++ b/app/components/ui/calendar/CalendarNextButton.vue @@ -0,0 +1,34 @@ + + + diff --git a/app/components/ui/calendar/CalendarPrevButton.vue b/app/components/ui/calendar/CalendarPrevButton.vue new file mode 100644 index 0000000..bfba161 --- /dev/null +++ b/app/components/ui/calendar/CalendarPrevButton.vue @@ -0,0 +1,34 @@ + + + diff --git a/app/components/ui/calendar/index.ts b/app/components/ui/calendar/index.ts new file mode 100644 index 0000000..5239a1b --- /dev/null +++ b/app/components/ui/calendar/index.ts @@ -0,0 +1,12 @@ +export { default as Calendar } from './Calendar.vue' +export { default as CalendarCell } from './CalendarCell.vue' +export { default as CalendarCellTrigger } from './CalendarCellTrigger.vue' +export { default as CalendarGrid } from './CalendarGrid.vue' +export { default as CalendarGridBody } from './CalendarGridBody.vue' +export { default as CalendarGridHead } from './CalendarGridHead.vue' +export { default as CalendarGridRow } from './CalendarGridRow.vue' +export { default as CalendarHeadCell } from './CalendarHeadCell.vue' +export { default as CalendarHeader } from './CalendarHeader.vue' +export { default as CalendarHeading } from './CalendarHeading.vue' +export { default as CalendarNextButton } from './CalendarNextButton.vue' +export { default as CalendarPrevButton } from './CalendarPrevButton.vue' diff --git a/app/components/ui/card/Card.vue b/app/components/ui/card/Card.vue new file mode 100644 index 0000000..9154a6a --- /dev/null +++ b/app/components/ui/card/Card.vue @@ -0,0 +1,22 @@ + + + diff --git a/app/components/ui/card/CardAction.vue b/app/components/ui/card/CardAction.vue new file mode 100644 index 0000000..c2beb20 --- /dev/null +++ b/app/components/ui/card/CardAction.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/card/CardContent.vue b/app/components/ui/card/CardContent.vue new file mode 100644 index 0000000..6bff4bc --- /dev/null +++ b/app/components/ui/card/CardContent.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/card/CardDescription.vue b/app/components/ui/card/CardDescription.vue new file mode 100644 index 0000000..2a0a755 --- /dev/null +++ b/app/components/ui/card/CardDescription.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/card/CardFooter.vue b/app/components/ui/card/CardFooter.vue new file mode 100644 index 0000000..1f3648d --- /dev/null +++ b/app/components/ui/card/CardFooter.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/card/CardHeader.vue b/app/components/ui/card/CardHeader.vue new file mode 100644 index 0000000..f693a6c --- /dev/null +++ b/app/components/ui/card/CardHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/card/CardTitle.vue b/app/components/ui/card/CardTitle.vue new file mode 100644 index 0000000..caa7e06 --- /dev/null +++ b/app/components/ui/card/CardTitle.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/card/index.ts b/app/components/ui/card/index.ts new file mode 100644 index 0000000..73d985f --- /dev/null +++ b/app/components/ui/card/index.ts @@ -0,0 +1,7 @@ +export { default as Card } from './Card.vue' +export { default as CardAction } from './CardAction.vue' +export { default as CardContent } from './CardContent.vue' +export { default as CardDescription } from './CardDescription.vue' +export { default as CardFooter } from './CardFooter.vue' +export { default as CardHeader } from './CardHeader.vue' +export { default as CardTitle } from './CardTitle.vue' diff --git a/app/components/ui/checkbox/Checkbox.vue b/app/components/ui/checkbox/Checkbox.vue new file mode 100644 index 0000000..58e42f2 --- /dev/null +++ b/app/components/ui/checkbox/Checkbox.vue @@ -0,0 +1,34 @@ + + + diff --git a/app/components/ui/checkbox/index.ts b/app/components/ui/checkbox/index.ts new file mode 100644 index 0000000..3391a85 --- /dev/null +++ b/app/components/ui/checkbox/index.ts @@ -0,0 +1 @@ +export { default as Checkbox } from "./Checkbox.vue" diff --git a/app/components/ui/dialog/Dialog.vue b/app/components/ui/dialog/Dialog.vue new file mode 100644 index 0000000..ade5260 --- /dev/null +++ b/app/components/ui/dialog/Dialog.vue @@ -0,0 +1,19 @@ + + + diff --git a/app/components/ui/dialog/DialogClose.vue b/app/components/ui/dialog/DialogClose.vue new file mode 100644 index 0000000..c5fae04 --- /dev/null +++ b/app/components/ui/dialog/DialogClose.vue @@ -0,0 +1,15 @@ + + + diff --git a/app/components/ui/dialog/DialogContent.vue b/app/components/ui/dialog/DialogContent.vue new file mode 100644 index 0000000..7f86b47 --- /dev/null +++ b/app/components/ui/dialog/DialogContent.vue @@ -0,0 +1,53 @@ + + + diff --git a/app/components/ui/dialog/DialogDescription.vue b/app/components/ui/dialog/DialogDescription.vue new file mode 100644 index 0000000..f52e655 --- /dev/null +++ b/app/components/ui/dialog/DialogDescription.vue @@ -0,0 +1,23 @@ + + + diff --git a/app/components/ui/dialog/DialogFooter.vue b/app/components/ui/dialog/DialogFooter.vue new file mode 100644 index 0000000..0a936e6 --- /dev/null +++ b/app/components/ui/dialog/DialogFooter.vue @@ -0,0 +1,15 @@ + + + diff --git a/app/components/ui/dialog/DialogHeader.vue b/app/components/ui/dialog/DialogHeader.vue new file mode 100644 index 0000000..bfc3c64 --- /dev/null +++ b/app/components/ui/dialog/DialogHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/dialog/DialogOverlay.vue b/app/components/ui/dialog/DialogOverlay.vue new file mode 100644 index 0000000..7790077 --- /dev/null +++ b/app/components/ui/dialog/DialogOverlay.vue @@ -0,0 +1,21 @@ + + + diff --git a/app/components/ui/dialog/DialogScrollContent.vue b/app/components/ui/dialog/DialogScrollContent.vue new file mode 100644 index 0000000..f2475db --- /dev/null +++ b/app/components/ui/dialog/DialogScrollContent.vue @@ -0,0 +1,59 @@ + + + diff --git a/app/components/ui/dialog/DialogTitle.vue b/app/components/ui/dialog/DialogTitle.vue new file mode 100644 index 0000000..860f01a --- /dev/null +++ b/app/components/ui/dialog/DialogTitle.vue @@ -0,0 +1,23 @@ + + + diff --git a/app/components/ui/dialog/DialogTrigger.vue b/app/components/ui/dialog/DialogTrigger.vue new file mode 100644 index 0000000..49667e9 --- /dev/null +++ b/app/components/ui/dialog/DialogTrigger.vue @@ -0,0 +1,15 @@ + + + diff --git a/app/components/ui/dialog/index.ts b/app/components/ui/dialog/index.ts new file mode 100644 index 0000000..6768b09 --- /dev/null +++ b/app/components/ui/dialog/index.ts @@ -0,0 +1,10 @@ +export { default as Dialog } from "./Dialog.vue" +export { default as DialogClose } from "./DialogClose.vue" +export { default as DialogContent } from "./DialogContent.vue" +export { default as DialogDescription } from "./DialogDescription.vue" +export { default as DialogFooter } from "./DialogFooter.vue" +export { default as DialogHeader } from "./DialogHeader.vue" +export { default as DialogOverlay } from "./DialogOverlay.vue" +export { default as DialogScrollContent } from "./DialogScrollContent.vue" +export { default as DialogTitle } from "./DialogTitle.vue" +export { default as DialogTrigger } from "./DialogTrigger.vue" diff --git a/app/components/ui/dropdown-menu/DropdownMenu.vue b/app/components/ui/dropdown-menu/DropdownMenu.vue new file mode 100644 index 0000000..e386052 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenu.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue b/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue new file mode 100644 index 0000000..09b6da3 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue @@ -0,0 +1,41 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuContent.vue b/app/components/ui/dropdown-menu/DropdownMenuContent.vue new file mode 100644 index 0000000..a4d4c15 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuContent.vue @@ -0,0 +1,39 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuGroup.vue b/app/components/ui/dropdown-menu/DropdownMenuGroup.vue new file mode 100644 index 0000000..c7eb308 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuGroup.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuItem.vue b/app/components/ui/dropdown-menu/DropdownMenuItem.vue new file mode 100644 index 0000000..76299c6 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuItem.vue @@ -0,0 +1,30 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuLabel.vue b/app/components/ui/dropdown-menu/DropdownMenuLabel.vue new file mode 100644 index 0000000..50987ab --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuLabel.vue @@ -0,0 +1,22 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue b/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue new file mode 100644 index 0000000..d205d0b --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue @@ -0,0 +1,22 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue b/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue new file mode 100644 index 0000000..d2a0e86 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue @@ -0,0 +1,42 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue b/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue new file mode 100644 index 0000000..a65c50c --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue @@ -0,0 +1,26 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue b/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue new file mode 100644 index 0000000..1bcbb88 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuSub.vue b/app/components/ui/dropdown-menu/DropdownMenuSub.vue new file mode 100644 index 0000000..7329bca --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuSub.vue @@ -0,0 +1,19 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue b/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue new file mode 100644 index 0000000..d199c91 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue @@ -0,0 +1,31 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue b/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue new file mode 100644 index 0000000..df93e3d --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue @@ -0,0 +1,30 @@ + + + diff --git a/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue b/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue new file mode 100644 index 0000000..7bc7339 --- /dev/null +++ b/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue @@ -0,0 +1,16 @@ + + + diff --git a/app/components/ui/dropdown-menu/index.ts b/app/components/ui/dropdown-menu/index.ts new file mode 100644 index 0000000..f488d39 --- /dev/null +++ b/app/components/ui/dropdown-menu/index.ts @@ -0,0 +1,16 @@ +export { default as DropdownMenu } from './DropdownMenu.vue' + +export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue' +export { default as DropdownMenuContent } from './DropdownMenuContent.vue' +export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue' +export { default as DropdownMenuItem } from './DropdownMenuItem.vue' +export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue' +export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue' +export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue' +export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue' +export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue' +export { default as DropdownMenuSub } from './DropdownMenuSub.vue' +export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue' +export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue' +export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue' +export { DropdownMenuPortal } from 'reka-ui' diff --git a/app/components/ui/input/Input.vue b/app/components/ui/input/Input.vue new file mode 100644 index 0000000..899535e --- /dev/null +++ b/app/components/ui/input/Input.vue @@ -0,0 +1,33 @@ + + + diff --git a/app/components/ui/input/index.ts b/app/components/ui/input/index.ts new file mode 100644 index 0000000..a691dd6 --- /dev/null +++ b/app/components/ui/input/index.ts @@ -0,0 +1 @@ +export { default as Input } from './Input.vue' diff --git a/app/components/ui/popover/Popover.vue b/app/components/ui/popover/Popover.vue new file mode 100644 index 0000000..69afa77 --- /dev/null +++ b/app/components/ui/popover/Popover.vue @@ -0,0 +1,18 @@ + + + diff --git a/app/components/ui/popover/PopoverAnchor.vue b/app/components/ui/popover/PopoverAnchor.vue new file mode 100644 index 0000000..e96a121 --- /dev/null +++ b/app/components/ui/popover/PopoverAnchor.vue @@ -0,0 +1,15 @@ + + + diff --git a/app/components/ui/popover/PopoverContent.vue b/app/components/ui/popover/PopoverContent.vue new file mode 100644 index 0000000..860280f --- /dev/null +++ b/app/components/ui/popover/PopoverContent.vue @@ -0,0 +1,49 @@ + + + diff --git a/app/components/ui/popover/PopoverTrigger.vue b/app/components/ui/popover/PopoverTrigger.vue new file mode 100644 index 0000000..5ff67df --- /dev/null +++ b/app/components/ui/popover/PopoverTrigger.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ui/popover/index.ts b/app/components/ui/popover/index.ts new file mode 100644 index 0000000..d724e78 --- /dev/null +++ b/app/components/ui/popover/index.ts @@ -0,0 +1,4 @@ +export { default as Popover } from './Popover.vue' +export { default as PopoverAnchor } from './PopoverAnchor.vue' +export { default as PopoverContent } from './PopoverContent.vue' +export { default as PopoverTrigger } from './PopoverTrigger.vue' diff --git a/app/components/ui/range-calendar/RangeCalendar.vue b/app/components/ui/range-calendar/RangeCalendar.vue new file mode 100644 index 0000000..fc37098 --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendar.vue @@ -0,0 +1,91 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarCell.vue b/app/components/ui/range-calendar/RangeCalendarCell.vue new file mode 100644 index 0000000..f49016b --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarCell.vue @@ -0,0 +1,25 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarCellTrigger.vue b/app/components/ui/range-calendar/RangeCalendarCellTrigger.vue new file mode 100644 index 0000000..f3385fe --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarCellTrigger.vue @@ -0,0 +1,43 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarGrid.vue b/app/components/ui/range-calendar/RangeCalendarGrid.vue new file mode 100644 index 0000000..aaa909e --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarGrid.vue @@ -0,0 +1,25 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarGridBody.vue b/app/components/ui/range-calendar/RangeCalendarGridBody.vue new file mode 100644 index 0000000..52b6d3a --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarGridBody.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarGridHead.vue b/app/components/ui/range-calendar/RangeCalendarGridHead.vue new file mode 100644 index 0000000..0fe054d --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarGridHead.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarGridRow.vue b/app/components/ui/range-calendar/RangeCalendarGridRow.vue new file mode 100644 index 0000000..b90eb24 --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarGridRow.vue @@ -0,0 +1,24 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarHeadCell.vue b/app/components/ui/range-calendar/RangeCalendarHeadCell.vue new file mode 100644 index 0000000..aa0c2f6 --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarHeadCell.vue @@ -0,0 +1,25 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarHeader.vue b/app/components/ui/range-calendar/RangeCalendarHeader.vue new file mode 100644 index 0000000..9427a56 --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarHeader.vue @@ -0,0 +1,25 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarHeading.vue b/app/components/ui/range-calendar/RangeCalendarHeading.vue new file mode 100644 index 0000000..27c24b2 --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarHeading.vue @@ -0,0 +1,32 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarNextButton.vue b/app/components/ui/range-calendar/RangeCalendarNextButton.vue new file mode 100644 index 0000000..2bd0908 --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarNextButton.vue @@ -0,0 +1,34 @@ + + + diff --git a/app/components/ui/range-calendar/RangeCalendarPrevButton.vue b/app/components/ui/range-calendar/RangeCalendarPrevButton.vue new file mode 100644 index 0000000..676ea0d --- /dev/null +++ b/app/components/ui/range-calendar/RangeCalendarPrevButton.vue @@ -0,0 +1,34 @@ + + + diff --git a/app/components/ui/range-calendar/index.ts b/app/components/ui/range-calendar/index.ts new file mode 100644 index 0000000..7ba1637 --- /dev/null +++ b/app/components/ui/range-calendar/index.ts @@ -0,0 +1,12 @@ +export { default as RangeCalendar } from './RangeCalendar.vue' +export { default as RangeCalendarCell } from './RangeCalendarCell.vue' +export { default as RangeCalendarCellTrigger } from './RangeCalendarCellTrigger.vue' +export { default as RangeCalendarGrid } from './RangeCalendarGrid.vue' +export { default as RangeCalendarGridBody } from './RangeCalendarGridBody.vue' +export { default as RangeCalendarGridHead } from './RangeCalendarGridHead.vue' +export { default as RangeCalendarGridRow } from './RangeCalendarGridRow.vue' +export { default as RangeCalendarHeadCell } from './RangeCalendarHeadCell.vue' +export { default as RangeCalendarHeader } from './RangeCalendarHeader.vue' +export { default as RangeCalendarHeading } from './RangeCalendarHeading.vue' +export { default as RangeCalendarNextButton } from './RangeCalendarNextButton.vue' +export { default as RangeCalendarPrevButton } from './RangeCalendarPrevButton.vue' diff --git a/app/components/ui/select/Select.vue b/app/components/ui/select/Select.vue new file mode 100644 index 0000000..dc1f83d --- /dev/null +++ b/app/components/ui/select/Select.vue @@ -0,0 +1,18 @@ + + + diff --git a/app/components/ui/select/SelectContent.vue b/app/components/ui/select/SelectContent.vue new file mode 100644 index 0000000..bde01cf --- /dev/null +++ b/app/components/ui/select/SelectContent.vue @@ -0,0 +1,55 @@ + + + diff --git a/app/components/ui/select/SelectGroup.vue b/app/components/ui/select/SelectGroup.vue new file mode 100644 index 0000000..4f36d92 --- /dev/null +++ b/app/components/ui/select/SelectGroup.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ui/select/SelectItem.vue b/app/components/ui/select/SelectItem.vue new file mode 100644 index 0000000..cddae64 --- /dev/null +++ b/app/components/ui/select/SelectItem.vue @@ -0,0 +1,45 @@ + + + diff --git a/app/components/ui/select/SelectItemText.vue b/app/components/ui/select/SelectItemText.vue new file mode 100644 index 0000000..cff32ac --- /dev/null +++ b/app/components/ui/select/SelectItemText.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ui/select/SelectLabel.vue b/app/components/ui/select/SelectLabel.vue new file mode 100644 index 0000000..7da0ce2 --- /dev/null +++ b/app/components/ui/select/SelectLabel.vue @@ -0,0 +1,16 @@ + + + diff --git a/app/components/ui/select/SelectScrollDownButton.vue b/app/components/ui/select/SelectScrollDownButton.vue new file mode 100644 index 0000000..37162fd --- /dev/null +++ b/app/components/ui/select/SelectScrollDownButton.vue @@ -0,0 +1,28 @@ + + + diff --git a/app/components/ui/select/SelectScrollUpButton.vue b/app/components/ui/select/SelectScrollUpButton.vue new file mode 100644 index 0000000..d80dacc --- /dev/null +++ b/app/components/ui/select/SelectScrollUpButton.vue @@ -0,0 +1,28 @@ + + + diff --git a/app/components/ui/select/SelectSeparator.vue b/app/components/ui/select/SelectSeparator.vue new file mode 100644 index 0000000..ab51b07 --- /dev/null +++ b/app/components/ui/select/SelectSeparator.vue @@ -0,0 +1,21 @@ + + + diff --git a/app/components/ui/select/SelectTrigger.vue b/app/components/ui/select/SelectTrigger.vue new file mode 100644 index 0000000..97c69a2 --- /dev/null +++ b/app/components/ui/select/SelectTrigger.vue @@ -0,0 +1,32 @@ + + + diff --git a/app/components/ui/select/SelectValue.vue b/app/components/ui/select/SelectValue.vue new file mode 100644 index 0000000..f198b96 --- /dev/null +++ b/app/components/ui/select/SelectValue.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ui/select/index.ts b/app/components/ui/select/index.ts new file mode 100644 index 0000000..31b9294 --- /dev/null +++ b/app/components/ui/select/index.ts @@ -0,0 +1,11 @@ +export { default as Select } from './Select.vue' +export { default as SelectContent } from './SelectContent.vue' +export { default as SelectGroup } from './SelectGroup.vue' +export { default as SelectItem } from './SelectItem.vue' +export { default as SelectItemText } from './SelectItemText.vue' +export { default as SelectLabel } from './SelectLabel.vue' +export { default as SelectScrollDownButton } from './SelectScrollDownButton.vue' +export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue' +export { default as SelectSeparator } from './SelectSeparator.vue' +export { default as SelectTrigger } from './SelectTrigger.vue' +export { default as SelectValue } from './SelectValue.vue' diff --git a/app/components/ui/skeleton/Skeleton.vue b/app/components/ui/skeleton/Skeleton.vue new file mode 100644 index 0000000..0dadcef --- /dev/null +++ b/app/components/ui/skeleton/Skeleton.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/skeleton/index.ts b/app/components/ui/skeleton/index.ts new file mode 100644 index 0000000..e5ce72c --- /dev/null +++ b/app/components/ui/skeleton/index.ts @@ -0,0 +1 @@ +export { default as Skeleton } from "./Skeleton.vue" diff --git a/app/components/ui/table/Table.vue b/app/components/ui/table/Table.vue new file mode 100644 index 0000000..669b0d4 --- /dev/null +++ b/app/components/ui/table/Table.vue @@ -0,0 +1,16 @@ + + + diff --git a/app/components/ui/table/TableBody.vue b/app/components/ui/table/TableBody.vue new file mode 100644 index 0000000..af688cb --- /dev/null +++ b/app/components/ui/table/TableBody.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/table/TableCaption.vue b/app/components/ui/table/TableCaption.vue new file mode 100644 index 0000000..e6ab397 --- /dev/null +++ b/app/components/ui/table/TableCaption.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/table/TableCell.vue b/app/components/ui/table/TableCell.vue new file mode 100644 index 0000000..841557d --- /dev/null +++ b/app/components/ui/table/TableCell.vue @@ -0,0 +1,22 @@ + + + diff --git a/app/components/ui/table/TableEmpty.vue b/app/components/ui/table/TableEmpty.vue new file mode 100644 index 0000000..3f6e0ff --- /dev/null +++ b/app/components/ui/table/TableEmpty.vue @@ -0,0 +1,37 @@ + + + diff --git a/app/components/ui/table/TableFooter.vue b/app/components/ui/table/TableFooter.vue new file mode 100644 index 0000000..8055c55 --- /dev/null +++ b/app/components/ui/table/TableFooter.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/table/TableHead.vue b/app/components/ui/table/TableHead.vue new file mode 100644 index 0000000..a2ca70e --- /dev/null +++ b/app/components/ui/table/TableHead.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/table/TableHeader.vue b/app/components/ui/table/TableHeader.vue new file mode 100644 index 0000000..0b0f481 --- /dev/null +++ b/app/components/ui/table/TableHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/table/TableRow.vue b/app/components/ui/table/TableRow.vue new file mode 100644 index 0000000..5befaef --- /dev/null +++ b/app/components/ui/table/TableRow.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/table/index.ts b/app/components/ui/table/index.ts new file mode 100644 index 0000000..2b4ce39 --- /dev/null +++ b/app/components/ui/table/index.ts @@ -0,0 +1,9 @@ +export { default as Table } from './Table.vue' +export { default as TableBody } from './TableBody.vue' +export { default as TableCaption } from './TableCaption.vue' +export { default as TableCell } from './TableCell.vue' +export { default as TableEmpty } from './TableEmpty.vue' +export { default as TableFooter } from './TableFooter.vue' +export { default as TableHead } from './TableHead.vue' +export { default as TableHeader } from './TableHeader.vue' +export { default as TableRow } from './TableRow.vue' diff --git a/app/components/ui/table/utils.ts b/app/components/ui/table/utils.ts new file mode 100644 index 0000000..d812d4b --- /dev/null +++ b/app/components/ui/table/utils.ts @@ -0,0 +1,9 @@ +import type { Updater } from '@tanstack/vue-table' +import type { Ref } from 'vue' + +export function valueUpdater>(updaterOrValue: T, ref: Ref) { + ref.value + = typeof updaterOrValue === 'function' + ? updaterOrValue(ref.value) + : updaterOrValue +} diff --git a/app/lib/utils.ts b/app/lib/utils.ts new file mode 100644 index 0000000..86cad5a --- /dev/null +++ b/app/lib/utils.ts @@ -0,0 +1,47 @@ +import dayjs from 'dayjs' +import utc from 'dayjs/plugin/utc.js' +import { type ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' +import type { TaskSelect } from '../../shared/db/schema' + +dayjs.extend(utc) + +export function formatDate(date: string, includeMilliseconds: boolean = false) { + let formatString = 'MMM D, YYYY HH:mm:ss' + if (includeMilliseconds) { + formatString += '.SSS' + } + return dayjs.utc(date).local().format(formatString) +} + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} + +export function limitText(text: string, length: number) { + if (text.length > length) { + return text.slice(0, length).trim() + '...' + } + return text +} + +export function formatReturnValue(task: TaskSelect) { + if (task.returnValue === null) { + return '...' + } else { + if (task.returnValue?.return_value) { + return task.returnValue.return_value + } + return 'null' + } +} + +// temporarily, while dishka hasn't fixed it's module naming bug +export function formatTaskName(taskName: string) { + if (taskName.includes(':')) { + const parts = taskName.split(':') + return parts[parts.length - 1] + } else { + return taskName + } +} diff --git a/app/pages/index.vue b/app/pages/index.vue new file mode 100644 index 0000000..f158c47 --- /dev/null +++ b/app/pages/index.vue @@ -0,0 +1,13 @@ + + diff --git a/app/pages/settings/index.vue b/app/pages/settings/index.vue new file mode 100644 index 0000000..a57062e --- /dev/null +++ b/app/pages/settings/index.vue @@ -0,0 +1,112 @@ + + + diff --git a/app/pages/tasks/[id].vue b/app/pages/tasks/[id].vue new file mode 100644 index 0000000..e01b40b --- /dev/null +++ b/app/pages/tasks/[id].vue @@ -0,0 +1,253 @@ + + + + + diff --git a/app/pages/tasks/index.vue b/app/pages/tasks/index.vue new file mode 100644 index 0000000..4a04424 --- /dev/null +++ b/app/pages/tasks/index.vue @@ -0,0 +1,336 @@ + + + diff --git a/components.json b/components.json new file mode 100644 index 0000000..01d407e --- /dev/null +++ b/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://shadcn-vue.com/schema.json", + "style": "new-york", + "typescript": true, + "tailwind": { + "config": "", + "css": "src/assets/css/main.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "composables": "@/composables", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/docs/images/preview1.png b/docs/images/preview1.png index 19bfc76..a07ba06 100644 Binary files a/docs/images/preview1.png and b/docs/images/preview1.png differ diff --git a/docs/images/preview2.png b/docs/images/preview2.png index 1fe7697..f555ce4 100644 Binary files a/docs/images/preview2.png and b/docs/images/preview2.png differ diff --git a/drizzle.config.ts b/drizzle.config.ts index 0c5cce0..9f18769 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,11 +1,39 @@ -import "dotenv/config" -import { defineConfig } from "drizzle-kit" +import 'dotenv/config' +import { defineConfig } from 'drizzle-kit' + +const dbDriver = process.env.TASKIQ_ADMIN_DB_DRIVER + +if (!dbDriver) { + throw new Error('Environment variable TASKIQ_ADMIN_DB_DRIVER is required') +} + +if (dbDriver !== 'sqlite' && dbDriver !== 'postgres') { + throw new Error( + 'Environment variable TASKIQ_ADMIN_DB_DRIVER must be "sqlite" or "postgres"' + ) +} + +const dbUrl = + dbDriver === 'sqlite' + ? process.env.TASKIQ_ADMIN_DB_FILE_PATH + : process.env.TASKIQ_ADMIN_DB_URL + +if (!dbUrl) { + throw new Error( + dbDriver === 'sqlite' + ? 'Environment variable TASKIQ_ADMIN_DB_FILE_PATH is required for sqlite driver' + : 'Environment variable TASKIQ_ADMIN_DB_URL is required for postgres driver' + ) +} export default defineConfig({ - out: "./drizzle", - schema: "./src/server/db/schema.ts", - dialect: "sqlite", + out: './drizzle', + schema: + dbDriver === 'sqlite' + ? './shared/db/schema.sqlite.ts' + : './shared/db/schema.postgres.ts', + dialect: dbDriver === 'sqlite' ? 'sqlite' : 'postgresql', dbCredentials: { - url: process.env.DB_FILE_PATH!, - }, + url: dbUrl + } }) diff --git a/env-example b/env-example new file mode 100644 index 0000000..ae3142d --- /dev/null +++ b/env-example @@ -0,0 +1,5 @@ +TASKIQ_ADMIN_DB_DRIVER=sqlite +TASKIQ_ADMIN_DB_FILE_PATH=database/database.db +TASKIQ_ADMIN_DB_URL=postgres://postgres:postgres@localhost:5432/taskiq_admin +TASKIQ_ADMIN_BACKUP_FILE_PATH=database/backup.db +TASKIQ_ADMIN_API_TOKEN=supersecret \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 0000000..a422114 --- /dev/null +++ b/makefile @@ -0,0 +1,25 @@ +MODE ?= dev + +ifneq (,$(wildcard ./.env)) + include .env + export +endif + +.PHONY: all dev prod install gen run build + +all: $(MODE) + +install: + pnpm install --frozen-lockfile + +gen: + pnpm run generate:sql + +dev: install gen + pnpm dev + +build: install gen + pnpm build + +prod: build + node .output/server/index.mjs diff --git a/nuxt.config.ts b/nuxt.config.ts index c5a0559..f36a6cc 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,9 +1,26 @@ +import tailwindcss from '@tailwindcss/vite' + export default defineNuxtConfig({ - compatibilityDate: "2024-11-01", + compatibilityDate: '2024-11-01', devtools: { enabled: true }, - srcDir: "src/", - modules: ["@nuxtjs/tailwindcss"], + css: ['~/assets/css/main.css'], + srcDir: 'app', + imports: { + autoImport: false + }, + vite: { + plugins: [tailwindcss()] + }, typescript: { - strict: true, + strict: true + }, + nitro: { + experimental: { + tasks: true + }, + scheduledTasks: { + '* * * * *': ['settings-dispatcher'] + } }, + modules: ['@nuxt/fonts'] }) diff --git a/package.json b/package.json index 4535631..0c45f5e 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,58 @@ { - "name": "nuxt-app", + "name": "taskiq-admin", "private": true, "type": "module", - "version": "1.3.0", + "version": "1.9.0", "scripts": { "build": "nuxt build", "dev": "nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview", "postinstall": "nuxt prepare", + "typecheck": "tsc --noEmit", + "test": "vitest --run", "db:push": "drizzle-kit push", - "generate:sql": "drizzle-kit export --sql | sed 's/CREATE TABLE/CREATE TABLE IF NOT EXISTS/g; s/CREATE INDEX/CREATE INDEX IF NOT EXISTS/g' > dbschema.sql" + "generate:sql": "drizzle-kit export --sql | sed 's/CREATE TABLE/CREATE TABLE IF NOT EXISTS/g; s/CREATE INDEX/CREATE INDEX IF NOT EXISTS/g' > dbschema.sql; sed -i '1s/^/PRAGMA journal_mode = WAL; PRAGMA synchronous = normal; PRAGMA journal_size_limit = 6144000;\\n/' dbschema.sql", + "generate:deprecated:sql": "drizzle-kit export --sql | sed 's/CREATE TABLE/CREATE TABLE IF NOT EXISTS/g; s/CREATE INDEX/CREATE INDEX IF NOT EXISTS/g' > dbschema.sql" }, "dependencies": { - "@vueuse/core": "^12.0.0", - "better-sqlite3": "^11.8.1", - "bootstrap": "^5.3.3", - "dayjs": "^1.11.13", - "dotenv": "^16.4.7", - "drizzle-orm": "^0.38.4", - "nuxt": "^3.15.2", - "vue": "^3.5.13", - "vue-router": "^4.5.0", - "zod": "^3.24.1" + "@internationalized/date": "^3.10.1", + "@nuxt/fonts": "0.12.1", + "@tailwindcss/vite": "^4.1.17", + "@tanstack/vue-table": "^8.21.3", + "@vueuse/core": "^14.1.0", + "better-sqlite3": "^12.11.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "dayjs": "^1.11.23", + "dotenv": "^17.2.3", + "drizzle-orm": "^0.45.1", + "lucide-vue-next": "^0.524.0", + "nuxt": "^4.2.2", + "pg": "^8.23.0", + "reka-ui": "^2.6.1", + "tailwind-merge": "^3.4.0", + "tailwindcss": "^4.1.17", + "tw-animate-css": "^1.4.0", + "vue": "^3.5.27", + "vue-router": "^4.6.4", + "vue-sonner": "^2.0.9", + "zod": "^4.3.5" }, "packageManager": "pnpm@8.7.6+sha1.a428b12202bc4f23b17e6dffe730734dae5728e2", "devDependencies": { - "@nuxtjs/tailwindcss": "^6.12.2", - "@types/better-sqlite3": "^7.6.12", - "drizzle-kit": "^0.30.2" + "@iconify-json/radix-icons": "^1.2.5", + "@iconify/vue": "^5.0.0", + "@nuxt/test-utils": "^3.23.0", + "@types/better-sqlite3": "^7.6.13", + "@types/pg": "^8.23.1", + "@vue/test-utils": "^2.4.6", + "drizzle-kit": "^0.31.8", + "happy-dom": "^18.0.1", + "playwright-core": "^1.57.0", + "prettier": "^3.7.3", + "tsx": "^4.21.0", + "typescript": "^5.9.3", + "vitest": "^3.2.4" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b48278..3228293 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5357 +1,4362 @@ -lockfileVersion: '9.0' +lockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -importers: - - .: - dependencies: - '@vueuse/core': - specifier: ^12.0.0 - version: 12.4.0(typescript@5.7.3) - better-sqlite3: - specifier: ^11.8.1 - version: 11.8.1 - bootstrap: - specifier: ^5.3.3 - version: 5.3.3(@popperjs/core@2.11.8) - dayjs: - specifier: ^1.11.13 - version: 1.11.13 - dotenv: - specifier: ^16.4.7 - version: 16.4.7 - drizzle-orm: - specifier: ^0.38.4 - version: 0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1) - nuxt: - specifier: ^3.15.2 - version: 3.15.2(@parcel/watcher@2.5.0)(@types/node@22.10.7)(better-sqlite3@11.8.1)(db0@0.2.1(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1)))(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1))(ioredis@5.4.2)(magicast@0.3.5)(rollup@4.30.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(yaml@2.7.0) - vue: - specifier: ^3.5.13 - version: 3.5.13(typescript@5.7.3) - vue-router: - specifier: ^4.5.0 - version: 4.5.0(vue@3.5.13(typescript@5.7.3)) - zod: - specifier: ^3.24.1 - version: 3.24.1 - devDependencies: - '@nuxtjs/tailwindcss': - specifier: ^6.12.2 - version: 6.13.1(magicast@0.3.5)(rollup@4.30.1) - '@types/better-sqlite3': - specifier: ^7.6.12 - version: 7.6.12 - drizzle-kit: - specifier: ^0.30.2 - version: 0.30.2 +dependencies: + '@internationalized/date': + specifier: ^3.10.1 + version: 3.10.1 + '@nuxt/fonts': + specifier: 0.12.1 + version: 0.12.1(vite@7.3.6) + '@tailwindcss/vite': + specifier: ^4.1.17 + version: 4.1.17(vite@7.3.6) + '@tanstack/vue-table': + specifier: ^8.21.3 + version: 8.21.3(vue@3.5.27) + '@vueuse/core': + specifier: ^14.1.0 + version: 14.1.0(vue@3.5.27) + better-sqlite3: + specifier: ^12.11.1 + version: 12.11.1 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + dayjs: + specifier: ^1.11.23 + version: 1.11.23 + dotenv: + specifier: ^17.2.3 + version: 17.2.3 + drizzle-orm: + specifier: ^0.45.1 + version: 0.45.1(@types/better-sqlite3@7.6.13)(@types/pg@8.23.1)(better-sqlite3@12.11.1)(pg@8.23.0) + lucide-vue-next: + specifier: ^0.524.0 + version: 0.524.0(vue@3.5.27) + nuxt: + specifier: ^4.2.2 + version: 4.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@vue/compiler-sfc@3.5.42)(better-sqlite3@12.11.1)(drizzle-orm@0.45.1)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.6) + pg: + specifier: ^8.23.0 + version: 8.23.0 + reka-ui: + specifier: ^2.6.1 + version: 2.6.1(typescript@5.9.3)(vue@3.5.27) + tailwind-merge: + specifier: ^3.4.0 + version: 3.4.0 + tailwindcss: + specifier: ^4.1.17 + version: 4.1.17 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + vue: + specifier: ^3.5.27 + version: 3.5.27(typescript@5.9.3) + vue-router: + specifier: ^4.6.4 + version: 4.6.4(vue@3.5.27) + vue-sonner: + specifier: ^2.0.9 + version: 2.0.9(nuxt@4.2.2) + zod: + specifier: ^4.3.5 + version: 4.3.5 + +devDependencies: + '@iconify-json/radix-icons': + specifier: ^1.2.5 + version: 1.2.5 + '@iconify/vue': + specifier: ^5.0.0 + version: 5.0.0(vue@3.5.27) + '@nuxt/test-utils': + specifier: ^3.23.0 + version: 3.23.0(@vue/test-utils@2.4.6)(happy-dom@18.0.1)(playwright-core@1.57.0)(typescript@5.9.3)(vitest@3.2.4) + '@types/better-sqlite3': + specifier: ^7.6.13 + version: 7.6.13 + '@types/pg': + specifier: ^8.23.1 + version: 8.23.1 + '@vue/test-utils': + specifier: ^2.4.6 + version: 2.4.6 + drizzle-kit: + specifier: ^0.31.8 + version: 0.31.8 + happy-dom: + specifier: ^18.0.1 + version: 18.0.1 + playwright-core: + specifier: ^1.57.0 + version: 1.57.0 + prettier: + specifier: ^3.7.3 + version: 3.7.3 + tsx: + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.4(happy-dom@18.0.1)(tsx@4.21.0) packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - - '@antfu/utils@0.7.10': - resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} - - '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + /@babel/code-frame@7.28.6: + resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: false - '@babel/compat-data@7.26.5': - resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==} + /@babel/compat-data@7.28.6: + resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} engines: {node: '>=6.9.0'} + dev: false - '@babel/core@7.26.0': - resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + /@babel/core@7.28.6: + resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/template': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false - '@babel/generator@7.26.5': - resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==} + /@babel/generator@7.28.6: + resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + dev: false - '@babel/helper-annotate-as-pure@7.25.9': - resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + /@babel/helper-annotate-as-pure@7.27.3: + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.6 + dev: false - '@babel/helper-compilation-targets@7.26.5': - resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} + /@babel/helper-compilation-targets@7.28.6: + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: false - '@babel/helper-create-class-features-plugin@7.25.9': - resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} + /@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.28.6): + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.28.6) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.6 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/helper-globals@7.28.0: + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + dev: false - '@babel/helper-member-expression-to-functions@7.25.9': - resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + /@babel/helper-member-expression-to-functions@7.28.5: + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + transitivePeerDependencies: + - supports-color + dev: false - '@babel/helper-module-imports@7.25.9': - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + /@babel/helper-module-imports@7.28.6: + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + transitivePeerDependencies: + - supports-color + dev: false - '@babel/helper-module-transforms@7.26.0': - resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + /@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6): + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.6 + transitivePeerDependencies: + - supports-color + dev: false - '@babel/helper-optimise-call-expression@7.25.9': - resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + /@babel/helper-optimise-call-expression@7.27.1: + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.6 + dev: false - '@babel/helper-plugin-utils@7.26.5': - resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} + /@babel/helper-plugin-utils@7.28.6: + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} + dev: false - '@babel/helper-replace-supers@7.26.5': - resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==} + /@babel/helper-replace-supers@7.28.6(@babel/core@7.28.6): + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.28.6 + transitivePeerDependencies: + - supports-color + dev: false - '@babel/helper-skip-transparent-expression-wrappers@7.25.9': - resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + /@babel/helper-skip-transparent-expression-wrappers@7.27.1: + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + transitivePeerDependencies: + - supports-color + dev: false - '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + /@babel/helper-string-parser@7.27.1: + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + /@babel/helper-string-parser@7.29.7: + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} + dev: false - '@babel/helper-validator-option@7.25.9': - resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + /@babel/helper-validator-identifier@7.28.5: + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.26.0': - resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + /@babel/helper-validator-identifier@7.29.7: + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} + dev: false - '@babel/parser@7.26.5': - resolution: {integrity: sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-proposal-decorators@7.25.9': - resolution: {integrity: sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==} + /@babel/helper-validator-option@7.27.1: + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + dev: false - '@babel/plugin-syntax-decorators@7.25.9': - resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==} + /@babel/helpers@7.28.6: + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.28.6 + dev: false - '@babel/plugin-syntax-import-attributes@7.26.0': - resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@babel/parser@7.28.5: + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.28.5 - '@babel/plugin-syntax-import-meta@7.10.4': - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@babel/parser@7.28.6: + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.28.6 + + /@babel/parser@7.29.8: + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.29.8 + dev: false - '@babel/plugin-syntax-jsx@7.25.9': - resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + /@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.28.6): + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + dev: false - '@babel/plugin-syntax-typescript@7.25.9': - resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + /@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.28.6): + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + dev: false - '@babel/plugin-transform-typescript@7.26.5': - resolution: {integrity: sha512-GJhPO0y8SD5EYVCy2Zr+9dSZcEgaSmq5BLR0Oc25TOEhC+ba49vUAGZFjy8v79z9E1mdldq4x9d1xgh4L1d5dQ==} + /@babel/plugin-transform-typescript@7.28.6(@babel/core@7.28.6): + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.28.6) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) + transitivePeerDependencies: + - supports-color + dev: false - '@babel/standalone@7.26.6': - resolution: {integrity: sha512-h1mkoNFYCqDkS+vTLGzsQYvp1v1qbuugk4lOtb/oyjArZ+EtreAaxcSYg3rSIzWZRQOjx4iqGe7A8NRYIMSTTw==} + /@babel/template@7.28.6: + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + dev: false - '@babel/template@7.25.9': - resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + /@babel/traverse@7.28.6: + resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.6 + '@babel/template': 7.28.6 + '@babel/types': 7.28.6 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + dev: false - '@babel/traverse@7.26.5': - resolution: {integrity: sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==} + /@babel/types@7.28.5: + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 - '@babel/types@7.26.5': - resolution: {integrity: sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==} + /@babel/types@7.28.6: + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 - '@cloudflare/kv-asset-handler@0.3.4': - resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} - engines: {node: '>=16.13'} + /@babel/types@7.29.8: + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + dev: false - '@csstools/selector-resolve-nested@3.0.0': - resolution: {integrity: sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==} - engines: {node: '>=18'} + /@bomb.sh/tab@0.0.11(citty@0.1.6): + resolution: {integrity: sha512-RSqyreeicYBALcMaNxIUJTBknftXsyW45VRq5gKDNwKroh0Re5SDoWwXZaphb+OTEzVdpm/BA8Uq6y0P+AtVYw==} + hasBin: true peerDependencies: - postcss-selector-parser: ^7.0.0 + cac: ^6.7.14 + citty: ^0.1.6 + commander: ^13.1.0 + peerDependenciesMeta: + cac: + optional: true + citty: + optional: true + commander: + optional: true + dependencies: + citty: 0.1.6 + dev: false - '@csstools/selector-specificity@5.0.0': - resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + /@capsizecss/unpack@3.0.1: + resolution: {integrity: sha512-8XqW8xGn++Eqqbz3e9wKuK7mxryeRjs4LOHLxbh2lwKeSbuNR4NFifDZT4KzvjU6HMOPbiNTsWpniK5EJfTWkg==} engines: {node: '>=18'} - peerDependencies: - postcss-selector-parser: ^7.0.0 + dependencies: + fontkit: 2.0.4 + dev: false + + /@clack/core@1.0.0-alpha.7: + resolution: {integrity: sha512-3vdh6Ar09D14rVxJZIm3VQJkU+ZOKKT5I5cC0cOVazy70CNyYYjiwRj9unwalhESndgxx6bGc/m6Hhs4EKF5XQ==} + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + /@clack/prompts@1.0.0-alpha.9: + resolution: {integrity: sha512-sKs0UjiHFWvry4SiRfBi5Qnj0C/6AYx8aKkFPZQSuUZXgAram25ZDmhQmP7vj1aFyLpfHWtLQjWvOvcat0TOLg==} + dependencies: + '@clack/core': 1.0.0-alpha.7 + picocolors: 1.1.1 + sisteransi: 1.0.5 + + /@cloudflare/kv-asset-handler@0.4.2: + resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} + engines: {node: '>=18.0.0'} + dev: false - '@drizzle-team/brocli@0.10.2': + /@drizzle-team/brocli@0.10.2: resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + dev: true + + /@dxup/nuxt@0.2.2: + resolution: {integrity: sha512-RNpJjDZs9+JcT9N87AnOuHsNM75DEd58itADNd/s1LIF6BZbTLZV0xxilJZb55lntn4TYvscTaXLCBX2fq9CXg==} + dependencies: + '@dxup/unimport': 0.1.2 + '@nuxt/kit': 4.2.2(magicast@0.5.1) + chokidar: 4.0.3 + pathe: 2.0.3 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - magicast + dev: false - '@esbuild-kit/core-utils@3.3.2': + /@dxup/unimport@0.1.2: + resolution: {integrity: sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==} + dev: false + + /@emnapi/core@1.11.3: + resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} + dependencies: + '@emnapi/wasi-threads': 1.2.3 + tslib: 2.8.1 + dev: false + optional: true + + /@emnapi/runtime@1.11.3: + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + dependencies: + tslib: 2.8.1 + dev: false + optional: true + + /@emnapi/wasi-threads@1.2.3: + resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + dependencies: + tslib: 2.8.1 + dev: false + optional: true + + /@esbuild-kit/core-utils@3.3.2: resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' + dependencies: + esbuild: 0.18.20 + source-map-support: 0.5.21 + dev: true - '@esbuild-kit/esm-loader@2.6.5': + /@esbuild-kit/esm-loader@2.6.5: resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} deprecated: 'Merged into tsx: https://tsx.is' + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.10.0 + dev: true - '@esbuild/aix-ppc64@0.19.12': - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} + /@esbuild/aix-ppc64@0.25.12: + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] + requiresBuild: true + optional: true - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} + /@esbuild/aix-ppc64@0.27.0: + resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + optional: true + + /@esbuild/aix-ppc64@0.27.2: + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] + requiresBuild: true + dev: false + optional: true - '@esbuild/aix-ppc64@0.24.2': - resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + /@esbuild/aix-ppc64@0.28.2: + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + requiresBuild: true + dev: false + optional: true - '@esbuild/android-arm64@0.18.20': + /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm64@0.19.12': - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} + /@esbuild/android-arm64@0.25.12: + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} cpu: [arm64] os: [android] + requiresBuild: true + optional: true - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} + /@esbuild/android-arm64@0.27.0: + resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/android-arm64@0.27.2: + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} cpu: [arm64] os: [android] + requiresBuild: true + dev: false + optional: true - '@esbuild/android-arm64@0.24.2': - resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + /@esbuild/android-arm64@0.28.2: + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} engines: {node: '>=18'} cpu: [arm64] os: [android] + requiresBuild: true + dev: false + optional: true - '@esbuild/android-arm@0.18.20': + /@esbuild/android-arm@0.18.20: resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm@0.19.12': - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} + /@esbuild/android-arm@0.25.12: + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} cpu: [arm] os: [android] + requiresBuild: true + optional: true - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} + /@esbuild/android-arm@0.27.0: + resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/android-arm@0.27.2: + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} cpu: [arm] os: [android] + requiresBuild: true + dev: false + optional: true - '@esbuild/android-arm@0.24.2': - resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + /@esbuild/android-arm@0.28.2: + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} engines: {node: '>=18'} cpu: [arm] os: [android] + requiresBuild: true + dev: false + optional: true - '@esbuild/android-x64@0.18.20': + /@esbuild/android-x64@0.18.20: resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} cpu: [x64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-x64@0.19.12': - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} + /@esbuild/android-x64@0.25.12: + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} cpu: [x64] os: [android] + requiresBuild: true + optional: true - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} + /@esbuild/android-x64@0.27.0: + resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/android-x64@0.27.2: + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} cpu: [x64] os: [android] + requiresBuild: true + dev: false + optional: true - '@esbuild/android-x64@0.24.2': - resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + /@esbuild/android-x64@0.28.2: + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} engines: {node: '>=18'} cpu: [x64] os: [android] + requiresBuild: true + dev: false + optional: true - '@esbuild/darwin-arm64@0.18.20': + /@esbuild/darwin-arm64@0.18.20: resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-arm64@0.19.12': - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} + /@esbuild/darwin-arm64@0.25.12: + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] + requiresBuild: true + optional: true - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} + /@esbuild/darwin-arm64@0.27.0: + resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] + requiresBuild: true + optional: true + + /@esbuild/darwin-arm64@0.27.2: + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true - '@esbuild/darwin-arm64@0.24.2': - resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + /@esbuild/darwin-arm64@0.28.2: + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: false + optional: true - '@esbuild/darwin-x64@0.18.20': + /@esbuild/darwin-x64@0.18.20: resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.25.12: + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true - '@esbuild/darwin-x64@0.19.12': - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} + /@esbuild/darwin-x64@0.27.0: + resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] + requiresBuild: true + optional: true - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} + /@esbuild/darwin-x64@0.27.2: + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: false + optional: true - '@esbuild/darwin-x64@0.24.2': - resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + /@esbuild/darwin-x64@0.28.2: + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: false + optional: true - '@esbuild/freebsd-arm64@0.18.20': + /@esbuild/freebsd-arm64@0.18.20: resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-arm64@0.19.12': - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} + /@esbuild/freebsd-arm64@0.25.12: + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + optional: true + + /@esbuild/freebsd-arm64@0.27.0: + resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + requiresBuild: true + optional: true - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} + /@esbuild/freebsd-arm64@0.27.2: + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/freebsd-arm64@0.24.2': - resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + /@esbuild/freebsd-arm64@0.28.2: + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/freebsd-x64@0.18.20': + /@esbuild/freebsd-x64@0.18.20: resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-x64@0.19.12': - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} + /@esbuild/freebsd-x64@0.25.12: + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] + requiresBuild: true + optional: true - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} + /@esbuild/freebsd-x64@0.27.0: + resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + optional: true + + /@esbuild/freebsd-x64@0.27.2: + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/freebsd-x64@0.24.2': - resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + /@esbuild/freebsd-x64@0.28.2: + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-arm64@0.18.20': + /@esbuild/linux-arm64@0.18.20: resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm64@0.19.12': - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} + /@esbuild/linux-arm64@0.25.12: + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} + /@esbuild/linux-arm64@0.27.0: + resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-arm64@0.27.2: + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-arm64@0.24.2': - resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + /@esbuild/linux-arm64@0.28.2: + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-arm@0.18.20': + /@esbuild/linux-arm@0.18.20: resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm@0.19.12': - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} + /@esbuild/linux-arm@0.25.12: + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} + /@esbuild/linux-arm@0.27.0: + resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-arm@0.27.2: + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-arm@0.24.2': - resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + /@esbuild/linux-arm@0.28.2: + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} engines: {node: '>=18'} cpu: [arm] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-ia32@0.18.20': + /@esbuild/linux-ia32@0.18.20: resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ia32@0.19.12': - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} + /@esbuild/linux-ia32@0.25.12: + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} + /@esbuild/linux-ia32@0.27.0: + resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ia32@0.27.2: + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-ia32@0.24.2': - resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + /@esbuild/linux-ia32@0.28.2: + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-loong64@0.18.20': + /@esbuild/linux-loong64@0.18.20: resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-loong64@0.19.12': - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} + /@esbuild/linux-loong64@0.25.12: + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} + /@esbuild/linux-loong64@0.27.0: + resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-loong64@0.27.2: + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-loong64@0.24.2': - resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + /@esbuild/linux-loong64@0.28.2: + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-mips64el@0.18.20': + /@esbuild/linux-mips64el@0.18.20: resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-mips64el@0.19.12': - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} + /@esbuild/linux-mips64el@0.25.12: + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} + /@esbuild/linux-mips64el@0.27.0: + resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-mips64el@0.27.2: + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-mips64el@0.24.2': - resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + /@esbuild/linux-mips64el@0.28.2: + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-ppc64@0.18.20': + /@esbuild/linux-ppc64@0.18.20: resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ppc64@0.19.12': - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} + /@esbuild/linux-ppc64@0.25.12: + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} + /@esbuild/linux-ppc64@0.27.0: + resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ppc64@0.27.2: + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-ppc64@0.24.2': - resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + /@esbuild/linux-ppc64@0.28.2: + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-riscv64@0.18.20': + /@esbuild/linux-riscv64@0.18.20: resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-riscv64@0.19.12': - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} + /@esbuild/linux-riscv64@0.25.12: + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-riscv64@0.27.0: + resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} + /@esbuild/linux-riscv64@0.27.2: + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-riscv64@0.24.2': - resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + /@esbuild/linux-riscv64@0.28.2: + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-s390x@0.18.20': + /@esbuild/linux-s390x@0.18.20: resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-s390x@0.19.12': - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} + /@esbuild/linux-s390x@0.25.12: + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} + /@esbuild/linux-s390x@0.27.0: + resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-s390x@0.27.2: + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-s390x@0.24.2': - resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + /@esbuild/linux-s390x@0.28.2: + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-x64@0.18.20': + /@esbuild/linux-x64@0.18.20: resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-x64@0.19.12': - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} + /@esbuild/linux-x64@0.25.12: + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} cpu: [x64] os: [linux] + requiresBuild: true + optional: true - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} + /@esbuild/linux-x64@0.27.0: + resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-x64@0.27.2: + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} cpu: [x64] os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/linux-x64@0.24.2': - resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + /@esbuild/linux-x64@0.28.2: + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/netbsd-arm64@0.25.12: + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + requiresBuild: true + optional: true - '@esbuild/netbsd-arm64@0.24.2': - resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + /@esbuild/netbsd-arm64@0.27.0: + resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + requiresBuild: true + optional: true + + /@esbuild/netbsd-arm64@0.27.2: + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/netbsd-arm64@0.28.2: + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/netbsd-x64@0.18.20': + /@esbuild/netbsd-x64@0.18.20: resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-x64@0.19.12': - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} + /@esbuild/netbsd-x64@0.25.12: + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] + requiresBuild: true + optional: true - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} + /@esbuild/netbsd-x64@0.27.0: + resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + optional: true + + /@esbuild/netbsd-x64@0.27.2: + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/netbsd-x64@0.24.2': - resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + /@esbuild/netbsd-x64@0.28.2: + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/openbsd-arm64@0.25.12: + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + optional: true + + /@esbuild/openbsd-arm64@0.27.0: + resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + optional: true + + /@esbuild/openbsd-arm64@0.27.2: + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/openbsd-arm64@0.24.2': - resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + /@esbuild/openbsd-arm64@0.28.2: + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/openbsd-x64@0.18.20': + /@esbuild/openbsd-x64@0.18.20: resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-x64@0.19.12': - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} + /@esbuild/openbsd-x64@0.25.12: + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] + requiresBuild: true + optional: true - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} + /@esbuild/openbsd-x64@0.27.0: + resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + optional: true + + /@esbuild/openbsd-x64@0.27.2: + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: false + optional: true - '@esbuild/openbsd-x64@0.24.2': - resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + /@esbuild/openbsd-x64@0.28.2: + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/openharmony-arm64@0.25.12: + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + optional: true + + /@esbuild/openharmony-arm64@0.27.0: + resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + optional: true + + /@esbuild/openharmony-arm64@0.27.2: + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: false + optional: true + + /@esbuild/openharmony-arm64@0.28.2: + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: false + optional: true - '@esbuild/sunos-x64@0.18.20': + /@esbuild/sunos-x64@0.18.20: resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + requiresBuild: true + dev: true + optional: true - '@esbuild/sunos-x64@0.19.12': - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} + /@esbuild/sunos-x64@0.25.12: + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] + requiresBuild: true + optional: true - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} + /@esbuild/sunos-x64@0.27.0: + resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + requiresBuild: true + optional: true + + /@esbuild/sunos-x64@0.27.2: + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] + requiresBuild: true + dev: false + optional: true - '@esbuild/sunos-x64@0.24.2': - resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + /@esbuild/sunos-x64@0.28.2: + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + requiresBuild: true + dev: false + optional: true - '@esbuild/win32-arm64@0.18.20': + /@esbuild/win32-arm64@0.18.20: resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-arm64@0.19.12': - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} + /@esbuild/win32-arm64@0.25.12: + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] + requiresBuild: true + optional: true - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} + /@esbuild/win32-arm64@0.27.0: + resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] + requiresBuild: true + optional: true + + /@esbuild/win32-arm64@0.27.2: + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true - '@esbuild/win32-arm64@0.24.2': - resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + /@esbuild/win32-arm64@0.28.2: + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: false + optional: true - '@esbuild/win32-ia32@0.18.20': + /@esbuild/win32-ia32@0.18.20: resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.25.12: + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true - '@esbuild/win32-ia32@0.19.12': - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} + /@esbuild/win32-ia32@0.27.0: + resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] + requiresBuild: true + optional: true - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} + /@esbuild/win32-ia32@0.27.2: + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: false + optional: true - '@esbuild/win32-ia32@0.24.2': - resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + /@esbuild/win32-ia32@0.28.2: + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: false + optional: true - '@esbuild/win32-x64@0.18.20': + /@esbuild/win32-x64@0.18.20: resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-x64@0.19.12': - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} + /@esbuild/win32-x64@0.25.12: + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} cpu: [x64] os: [win32] + requiresBuild: true + optional: true - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} + /@esbuild/win32-x64@0.27.0: + resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==} + engines: {node: '>=18'} cpu: [x64] os: [win32] + requiresBuild: true + optional: true - '@esbuild/win32-x64@0.24.2': - resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + /@esbuild/win32-x64@0.27.2: + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] + requiresBuild: true + dev: false + optional: true - '@ioredis/commands@1.2.0': - resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} + /@esbuild/win32-x64@0.28.2: + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true - '@isaacs/fs-minipass@4.0.1': - resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} - engines: {node: '>=18.0.0'} + /@floating-ui/core@1.6.9: + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + dependencies: + '@floating-ui/utils': 0.2.9 + dev: false - '@jridgewell/gen-mapping@0.3.8': - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} + /@floating-ui/dom@1.6.13: + resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + dependencies: + '@floating-ui/core': 1.6.9 + '@floating-ui/utils': 0.2.9 + dev: false - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + /@floating-ui/utils@0.2.9: + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + dev: false - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} + /@floating-ui/vue@1.1.6(vue@3.5.27): + resolution: {integrity: sha512-XFlUzGHGv12zbgHNk5FN2mUB7ROul3oG2ENdTpWdE+qMFxyNxWSRmsoyhiEnpmabNm6WnUvR1OvJfUfN4ojC1A==} + dependencies: + '@floating-ui/dom': 1.6.13 + '@floating-ui/utils': 0.2.9 + vue-demi: 0.14.10(vue@3.5.27) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false - '@jridgewell/source-map@0.3.6': - resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + /@iconify-json/radix-icons@1.2.5: + resolution: {integrity: sha512-HkUt+ydCivK/S/aFsgaiZRvs7zDEcO07PKkuEuu2EFBWCuC+Pi1mDdXPX0U3qjRr7JknmnoR4sAg53C+Ig35ow==} + dependencies: + '@iconify/types': 2.0.0 + dev: true - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + /@iconify/types@2.0.0: + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + dev: true - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + /@iconify/vue@5.0.0(vue@3.5.27): + resolution: {integrity: sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg==} + peerDependencies: + vue: '>=3' + dependencies: + '@iconify/types': 2.0.0 + vue: 3.5.27(typescript@5.9.3) + dev: true - '@koa/router@12.0.2': - resolution: {integrity: sha512-sYcHglGKTxGF+hQ6x67xDfkE9o+NhVlRHBqq6gLywaMc6CojK/5vFZByphdonKinYlMLkEkacm+HEse9HzwgTA==} - engines: {node: '>= 12'} + /@internationalized/date@3.10.1: + resolution: {integrity: sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA==} + dependencies: + '@swc/helpers': 0.5.15 + dev: false - '@kwsites/file-exists@1.1.1': - resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + /@internationalized/number@3.6.0: + resolution: {integrity: sha512-PtrRcJVy7nw++wn4W2OuePQQfTqDzfusSuY1QTtui4wa7r+rGVtR75pO8CyKvHvzyQYi3Q1uO5sY0AsB4e65Bw==} + dependencies: + '@swc/helpers': 0.5.15 + dev: false - '@kwsites/promise-deferred@1.1.1': - resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + /@ioredis/commands@1.5.0: + resolution: {integrity: sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==} + dev: false - '@mapbox/node-pre-gyp@2.0.0-rc.0': - resolution: {integrity: sha512-nhSMNprz3WmeRvd8iUs5JqkKr0Ncx46JtPxM3AhXes84XpSJfmIwKeWXRpsr53S7kqPkQfPhzrMFUxSNb23qSA==} - engines: {node: '>=18'} - hasBin: true + /@isaacs/balanced-match@4.0.1: + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + dev: false - '@netlify/functions@2.8.2': - resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==} - engines: {node: '>=14.0.0'} + /@isaacs/brace-expansion@5.0.0: + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/balanced-match': 4.0.1 + dev: false - '@netlify/node-cookies@0.1.0': - resolution: {integrity: sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==} - engines: {node: ^14.16.0 || >=16.0.0} + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 - '@netlify/serverless-functions-api@1.26.1': - resolution: {integrity: sha512-q3L9i3HoNfz0SGpTIS4zTcKBbRkxzCRpd169eyiTuk3IwcPC3/85mzLHranlKo2b+HYT0gu37YxGB45aD8A3Tw==} + /@isaacs/fs-minipass@4.0.1: + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} + dependencies: + minipass: 7.1.2 + dev: false - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + /@jridgewell/gen-mapping@0.3.13: + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@nuxt/cli@3.20.0': - resolution: {integrity: sha512-TmQPjIHXJFPTssPMMFuLF48nr9cm6ctaNwrnhDFl4xLunfLR4rrMJNJAQhepWyukg970ZgokZVbUYMqf6eCnTQ==} - engines: {node: ^16.10.0 || >=18.0.0} - hasBin: true - - '@nuxt/devalue@2.0.2': - resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==} - - '@nuxt/devtools-kit@1.7.0': - resolution: {integrity: sha512-+NgZ2uP5BuneqvQbe7EdOEaFEDy8762c99pLABtn7/Ur0ExEsQJMP7pYjjoTfKubhBqecr5Vo9yHkPBj1eHulQ==} - peerDependencies: - vite: '*' - - '@nuxt/devtools-wizard@1.7.0': - resolution: {integrity: sha512-86Gd92uEw0Dh2ErIYT9TMIrMOISE96fCRN4rxeryTvyiowQOsyrbkCeMNYrEehoRL+lohoyK6iDmFajadPNwWQ==} - hasBin: true - - '@nuxt/devtools@1.7.0': - resolution: {integrity: sha512-uvnjt5Zowkz7tZmnks2cGreg1XZIiSyVzQ2MYiRXACodlXcwJ0dpUS3WTxu8BR562K+772oRdvKie9AQlyZUgg==} - hasBin: true - peerDependencies: - vite: '*' - - '@nuxt/kit@3.15.2': - resolution: {integrity: sha512-nxiPJVz2fICcyBKlN5pL1IgZVejyArulREsS5HvAk07hijlYuZ5toRM8soLt51VQNpFd/PedL+Z1AlYu/bQCYQ==} - engines: {node: '>=18.0.0'} - - '@nuxt/schema@3.15.2': - resolution: {integrity: sha512-cTHGbLTbrQ83B+7Mh0ggc5MzIp74o8KciA0boCiBJyK5uImH9QQNK6VgfwRWcTD5sj3WNKiIB1luOMom3LHgVw==} - engines: {node: ^14.18.0 || >=16.10.0} - - '@nuxt/telemetry@2.6.4': - resolution: {integrity: sha512-2Lgdn07Suraly5dSfVQ4ttBQBMtmjvCTGKGUHpc1UyH87HT9xCm3KLFO0UcVQ8+LNYCgoOaK7lq9qDJOfBfZ5A==} - engines: {node: '>=18.20.5'} - hasBin: true - - '@nuxt/vite-builder@3.15.2': - resolution: {integrity: sha512-YtP6hIOKhqa1JhX0QzuULpA84lseO76bv5OqJzUl7yoaykhOkZjkEk9c20hamtMdoxhVeUAXGZJCsp9Ivjfb3g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0.0} - peerDependencies: - vue: ^3.3.4 - - '@nuxtjs/tailwindcss@6.13.1': - resolution: {integrity: sha512-atL2SaPsxLfMTlXUQvr1UpDYdz6ocNOhH35H+t7M++g4r79QiQScJ7XuyyMR9AyBN19lkPA3nw7NXxazXmYxlA==} - - '@parcel/watcher-android-arm64@2.5.0': - resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [android] - - '@parcel/watcher-darwin-arm64@2.5.0': - resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [darwin] - - '@parcel/watcher-darwin-x64@2.5.0': - resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [darwin] - - '@parcel/watcher-freebsd-x64@2.5.0': - resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [freebsd] - - '@parcel/watcher-linux-arm-glibc@2.5.0': - resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm-musl@2.5.0': - resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm64-glibc@2.5.0': - resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-arm64-musl@2.5.0': - resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-x64-glibc@2.5.0': - resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-linux-x64-musl@2.5.0': - resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-wasm@2.5.0': - resolution: {integrity: sha512-Z4ouuR8Pfggk1EYYbTaIoxc+Yv4o7cGQnH0Xy8+pQ+HbiW+ZnwhcD2LPf/prfq1nIWpAxjOkQ8uSMFWMtBLiVQ==} - engines: {node: '>= 10.0.0'} - bundledDependencies: - - napi-wasm - - '@parcel/watcher-win32-arm64@2.5.0': - resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] - - '@parcel/watcher-win32-ia32@2.5.0': - resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==} - engines: {node: '>= 10.0.0'} - cpu: [ia32] - os: [win32] - - '@parcel/watcher-win32-x64@2.5.0': - resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [win32] - - '@parcel/watcher@2.5.0': - resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==} - engines: {node: '>= 10.0.0'} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@polka/url@1.0.0-next.28': - resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} - - '@popperjs/core@2.11.8': - resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - - '@redocly/ajv@8.11.2': - resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} - - '@redocly/config@0.20.1': - resolution: {integrity: sha512-TYiTDtuItiv95YMsrRxyCs1HKLrDPtTvpaD3+kDKXBnFDeJuYKZ+eHXpCr6YeN4inxfVBs7DLhHsQcs9srddyQ==} - - '@redocly/openapi-core@1.27.2': - resolution: {integrity: sha512-qVrDc27DHpeO2NRCMeRdb4299nijKQE3BY0wrA+WUHlOLScorIi/y7JzammLk22IaTvjR9Mv9aTAdjE1aUwJnA==} - engines: {node: '>=14.19.0', npm: '>=7.0.0'} - - '@rollup/plugin-alias@5.1.1': - resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-commonjs@28.0.2': - resolution: {integrity: sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==} - engines: {node: '>=16.0.0 || 14 >= 14.17'} - peerDependencies: - rollup: ^2.68.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-inject@5.0.5': - resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-json@6.1.0': - resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-node-resolve@15.3.1': - resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.78.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-replace@6.0.2': - resolution: {integrity: sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/pluginutils@5.1.4': - resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/rollup-android-arm-eabi@4.30.1': - resolution: {integrity: sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.30.1': - resolution: {integrity: sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.30.1': - resolution: {integrity: sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.30.1': - resolution: {integrity: sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.30.1': - resolution: {integrity: sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.30.1': - resolution: {integrity: sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.30.1': - resolution: {integrity: sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.30.1': - resolution: {integrity: sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.30.1': - resolution: {integrity: sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.30.1': - resolution: {integrity: sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loongarch64-gnu@4.30.1': - resolution: {integrity: sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.30.1': - resolution: {integrity: sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.30.1': - resolution: {integrity: sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.30.1': - resolution: {integrity: sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.30.1': - resolution: {integrity: sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.30.1': - resolution: {integrity: sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.30.1': - resolution: {integrity: sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.30.1': - resolution: {integrity: sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.30.1': - resolution: {integrity: sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==} - cpu: [x64] - os: [win32] - - '@sindresorhus/merge-streams@2.3.0': - resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} - engines: {node: '>=18'} - - '@trysound/sax@0.2.0': - resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} - engines: {node: '>=10.13.0'} - - '@types/better-sqlite3@7.6.12': - resolution: {integrity: sha512-fnQmj8lELIj7BSrZQAdBMHEHX8OZLYIHXqAKT1O7tDfLxaINzf00PMjw22r3N/xXh0w/sGHlO6SVaCQ2mj78lg==} - - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - - '@types/http-proxy@1.17.15': - resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==} - - '@types/node@22.10.7': - resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==} - - '@types/parse-path@7.0.3': - resolution: {integrity: sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==} - - '@types/resolve@1.20.2': - resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - - '@types/web-bluetooth@0.0.20': - resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} - - '@unhead/dom@1.11.18': - resolution: {integrity: sha512-zQuJUw/et9zYEV0SZWTDX23IgurwMaXycAuxt4L6OgNL0T4TWP3a0J/Vm3Q02hmdNo/cPKeVBrwBdnFUXjGU4w==} - - '@unhead/schema@1.11.18': - resolution: {integrity: sha512-a3TA/OJCRdfbFhcA3Hq24k1ZU1o9szicESrw8DZcGyQFacHnh84mVgnyqSkMnwgCmfN4kvjSiTBlLEHS6+wATw==} - - '@unhead/shared@1.11.18': - resolution: {integrity: sha512-OsupRQRxJqqnuKiL1Guqipjbl7MndD5DofvmGa3PFGu2qNPmOmH2mxGFjRBBgq2XxY1KalIHl/2I9HV6gbK8cw==} - - '@unhead/ssr@1.11.18': - resolution: {integrity: sha512-uaHPz0RRAb18yKeCmHyHk5QKWRk/uHpOrqSbhRXTOhbrd3Ur3gGTVaAoyUoRYKGPU5B5/pyHh3TfLw0LkfrH1A==} - - '@unhead/vue@1.11.18': - resolution: {integrity: sha512-Jfi7t/XNBnlcauP9UTH3VHBcS69G70ikFd2e5zdgULLDRWpOlLs1sSTH1V2juNptc93DOk9RQfC5jLWbLcivFw==} - peerDependencies: - vue: '>=2.7 || >=3' - - '@vercel/nft@0.27.10': - resolution: {integrity: sha512-zbaF9Wp/NsZtKLE4uVmL3FyfFwlpDyuymQM1kPbeT0mVOHKDQQNjnnfslB3REg3oZprmNFJuh3pkHBk2qAaizg==} - engines: {node: '>=16'} - hasBin: true - - '@vitejs/plugin-vue-jsx@4.1.1': - resolution: {integrity: sha512-uMJqv/7u1zz/9NbWAD3XdjaY20tKTf17XVfQ9zq4wY1BjsB/PjpJPMe2xiG39QpP4ZdhYNhm4Hvo66uJrykNLA==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.0.0 - - '@vitejs/plugin-vue@5.2.1': - resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.2.25 - - '@vue-macros/common@1.16.0': - resolution: {integrity: sha512-n4S769GM4WXBSTt+YvG172f3FpmVKTQAD+OxhwpnPSTzSgETCho+wzfK6TpDiet5SR8moT6tNFwzQ/IUkexhHA==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - peerDependenciesMeta: - vue: - optional: true - - '@vue/babel-helper-vue-transform-on@1.2.5': - resolution: {integrity: sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==} - - '@vue/babel-plugin-jsx@1.2.5': - resolution: {integrity: sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - peerDependenciesMeta: - '@babel/core': - optional: true - - '@vue/babel-plugin-resolve-type@1.2.5': - resolution: {integrity: sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@vue/compiler-core@3.5.13': - resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} - - '@vue/compiler-dom@3.5.13': - resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} - - '@vue/compiler-sfc@3.5.13': - resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} - - '@vue/compiler-ssr@3.5.13': - resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} - - '@vue/devtools-api@6.6.4': - resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - - '@vue/devtools-core@7.6.8': - resolution: {integrity: sha512-8X4roysTwzQ94o7IobjVcOd1aZF5iunikrMrHPI2uUdigZCi2kFTQc7ffYiFiTNaLElCpjOhCnM7bo7aK1yU7A==} - peerDependencies: - vue: ^3.0.0 - - '@vue/devtools-kit@7.6.8': - resolution: {integrity: sha512-JhJ8M3sPU+v0P2iZBF2DkdmR9L0dnT5RXJabJqX6o8KtFs3tebdvfoXV2Dm3BFuqeECuMJIfF1aCzSt+WQ4wrw==} - - '@vue/devtools-shared@7.7.0': - resolution: {integrity: sha512-jtlQY26R5thQxW9YQTpXbI0HoK0Wf9Rd4ekidOkRvSy7ChfK0kIU6vvcBtjj87/EcpeOSK49fZAicaFNJcoTcQ==} - - '@vue/reactivity@3.5.13': - resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} - - '@vue/runtime-core@3.5.13': - resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} - - '@vue/runtime-dom@3.5.13': - resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} - - '@vue/server-renderer@3.5.13': - resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} - peerDependencies: - vue: 3.5.13 - - '@vue/shared@3.5.13': - resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} - - '@vueuse/core@12.4.0': - resolution: {integrity: sha512-XnjQYcJwCsyXyIafyA6SvyN/OBtfPnjvJmbxNxQjCcyWD198urwm5TYvIUUyAxEAN0K7HJggOgT15cOlWFyLeA==} - - '@vueuse/metadata@12.4.0': - resolution: {integrity: sha512-AhPuHs/qtYrKHUlEoNO6zCXufu8OgbR8S/n2oMw1OQuBQJ3+HOLQ+EpvXs+feOlZMa0p8QVvDWNlmcJJY8rW2g==} - - '@vueuse/shared@12.4.0': - resolution: {integrity: sha512-9yLgbHVIF12OSCojnjTIoZL1+UA10+O4E1aD6Hpfo/DKVm5o3SZIwz6CupqGy3+IcKI8d6Jnl26EQj/YucnW0Q==} - - abbrev@2.0.0: - resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - - acorn-import-attributes@1.9.5: - resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} - peerDependencies: - acorn: ^8 - - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} - engines: {node: '>=0.4.0'} - hasBin: true - - agent-base@7.1.3: - resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} - engines: {node: '>= 14'} - - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - archiver-utils@5.0.2: - resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} - engines: {node: '>= 14'} - - archiver@7.0.1: - resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} - engines: {node: '>= 14'} - - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - ast-kit@1.4.0: - resolution: {integrity: sha512-BlGeOw73FDsX7z0eZE/wuuafxYoek2yzNJ6l6A1nsb4+z/p87TOPbHaWuN53kFKNuUXiCQa2M+xLF71IqQmRSw==} - engines: {node: '>=16.14.0'} - - ast-walker-scope@0.6.2: - resolution: {integrity: sha512-1UWOyC50xI3QZkRuDj6PqDtpm1oHWtYs+NQGwqL/2R11eN3Q81PHAHPM0SWW3BNQm53UDwS//Jv8L4CCVLM1bQ==} - engines: {node: '>=16.14.0'} - - async-sema@3.1.1: - resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} - - async@2.6.4: - resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} - - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - - at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - - autoprefixer@10.4.20: - resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - - b4a@1.6.7: - resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - bare-events@2.5.4: - resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - better-sqlite3@11.8.1: - resolution: {integrity: sha512-9BxNaBkblMjhJW8sMRZxnxVTRgbRmssZW0Oxc1MPBTfiR+WW21e2Mk4qu8CzrcZb1LwPCnFsfDEzq+SNcBU8eg==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - - birpc@0.2.19: - resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - - bootstrap@5.3.3: - resolution: {integrity: sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==} - peerDependencies: - '@popperjs/core': ^2.11.8 - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.24.4: - resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - buffer-crc32@1.0.0: - resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} - engines: {node: '>=8.0.0'} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - bundle-name@4.1.0: - resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} - engines: {node: '>=18'} - - c12@2.0.1: - resolution: {integrity: sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==} - peerDependencies: - magicast: ^0.3.5 - peerDependenciesMeta: - magicast: - optional: true - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - cache-content-type@1.0.1: - resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==} - engines: {node: '>= 6.0.0'} - - call-bind-apply-helpers@1.0.1: - resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} - engines: {node: '>= 0.4'} - - call-bound@1.0.3: - resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} - engines: {node: '>= 0.4'} - - camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - - caniuse-api@3.0.0: - resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - - caniuse-lite@1.0.30001695: - resolution: {integrity: sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - change-case@5.4.4: - resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - - chownr@3.0.0: - resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} - engines: {node: '>=18'} - - citty@0.1.6: - resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - - clipboardy@4.0.0: - resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} - engines: {node: '>=18'} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - cluster-key-slot@1.1.2: - resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} - engines: {node: '>=0.10.0'} - - co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - colord@2.9.3: - resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} - - colorette@1.4.0: - resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - - commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - - commander@6.2.1: - resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} - engines: {node: '>= 6'} - - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} - - commander@8.3.0: - resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} - engines: {node: '>= 12'} - - commondir@1.0.1: - resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - - compatx@0.1.8: - resolution: {integrity: sha512-jcbsEAR81Bt5s1qOFymBufmCbXCXbk0Ql+K5ouj6gCyx2yHlu6AgmGIi9HxfKixpUDO5bCFJUHQ5uM6ecbTebw==} - - compress-commons@6.0.2: - resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} - engines: {node: '>= 14'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - - consola@3.4.0: - resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} - engines: {node: ^14.18.0 || >=16.10.0} - - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie-es@1.2.2: - resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} - - cookies@0.9.1: - resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} - engines: {node: '>= 0.8'} - - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - - crc32-stream@6.0.0: - resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} - engines: {node: '>= 14'} - - croner@9.0.0: - resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} - engines: {node: '>=18.0'} - - cronstrue@2.53.0: - resolution: {integrity: sha512-CkAcaI94xL8h6N7cGxgXfR5D7oV2yVtDzB9vMZP8tIgPyEv/oc/7nq9rlk7LMxvc3N+q6LKZmNLCVxJRpyEg8A==} - hasBin: true - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - crossws@0.3.1: - resolution: {integrity: sha512-HsZgeVYaG+b5zA+9PbIPGq4+J/CJynJuearykPsXx4V/eMhyQ5EDVg3Ak2FBZtVXCiOLu/U7IiwDHTr9MA+IKw==} - - css-declaration-sorter@7.2.0: - resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} - engines: {node: ^14 || ^16 || >=18} - peerDependencies: - postcss: ^8.0.9 - - css-select@5.1.0: - resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} - - css-tree@2.2.1: - resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - - css-tree@2.3.1: - resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - - css-what@6.1.0: - resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} - engines: {node: '>= 6'} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - cssnano-preset-default@7.0.6: - resolution: {integrity: sha512-ZzrgYupYxEvdGGuqL+JKOY70s7+saoNlHSCK/OGn1vB2pQK8KSET8jvenzItcY+kA7NoWvfbb/YhlzuzNKjOhQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - cssnano-utils@5.0.0: - resolution: {integrity: sha512-Uij0Xdxc24L6SirFr25MlwC2rCFX6scyUmuKpzI+JQ7cyqDEwD42fJ0xfB3yLfOnRDU5LKGgjQ9FA6LYh76GWQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - cssnano@7.0.6: - resolution: {integrity: sha512-54woqx8SCbp8HwvNZYn68ZFAepuouZW4lTwiMVnBErM3VkO7/Sd4oTOt3Zz3bPx3kxQ36aISppyXj2Md4lg8bw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - csso@5.0.5: - resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - - dayjs@1.11.13: - resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - - db0@0.2.1: - resolution: {integrity: sha512-BWSFmLaCkfyqbSEZBQINMVNjCVfrogi7GQ2RSy1tmtfK9OXlsup6lUMwLsqSD7FbAjD04eWFdXowSHHUp6SE/Q==} - peerDependencies: - '@electric-sql/pglite': '*' - '@libsql/client': '*' - better-sqlite3: '*' - drizzle-orm: '*' - mysql2: '*' - peerDependenciesMeta: - '@electric-sql/pglite': - optional: true - '@libsql/client': - optional: true - better-sqlite3: - optional: true - drizzle-orm: - optional: true - mysql2: - optional: true - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - deep-equal@1.0.1: - resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - default-browser-id@5.0.0: - resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} - engines: {node: '>=18'} - - default-browser@5.2.1: - resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} - engines: {node: '>=18'} - - define-lazy-prop@2.0.0: - resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} - engines: {node: '>=8'} - - define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} - - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - - delegates@1.0.0: - resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - - denque@2.1.0: - resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} - engines: {node: '>=0.10'} - - depd@1.1.2: - resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} - engines: {node: '>= 0.6'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - destr@2.0.3: - resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} - - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: '>=8'} - - devalue@5.1.1: - resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} - - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - - diff@7.0.0: - resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} - engines: {node: '>=0.3.1'} - - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - - dot-prop@9.0.0: - resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} - engines: {node: '>=18'} - - dotenv@16.4.7: - resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} - engines: {node: '>=12'} - - drizzle-kit@0.30.2: - resolution: {integrity: sha512-vhdLrxWA32WNVF77NabpSnX7pQBornx64VDQDmKddRonOB2Xe/yY4glQ7rECoa+ogqcQNo7VblLUbeBK6Zn9Ow==} - hasBin: true - - drizzle-orm@0.38.4: - resolution: {integrity: sha512-s7/5BpLKO+WJRHspvpqTydxFob8i1vo2rEx4pY6TGY7QSMuUfWUuzaY0DIpXCkgHOo37BaFC+SJQb99dDUXT3Q==} - peerDependencies: - '@aws-sdk/client-rds-data': '>=3' - '@cloudflare/workers-types': '>=4' - '@electric-sql/pglite': '>=0.2.0' - '@libsql/client': '>=0.10.0' - '@libsql/client-wasm': '>=0.10.0' - '@neondatabase/serverless': '>=0.10.0' - '@op-engineering/op-sqlite': '>=2' - '@opentelemetry/api': ^1.4.1 - '@planetscale/database': '>=1' - '@prisma/client': '*' - '@tidbcloud/serverless': '*' - '@types/better-sqlite3': '*' - '@types/pg': '*' - '@types/react': '>=18' - '@types/sql.js': '*' - '@vercel/postgres': '>=0.8.0' - '@xata.io/client': '*' - better-sqlite3: '>=7' - bun-types: '*' - expo-sqlite: '>=14.0.0' - knex: '*' - kysely: '*' - mysql2: '>=2' - pg: '>=8' - postgres: '>=3' - prisma: '*' - react: '>=18' - sql.js: '>=1' - sqlite3: '>=5' - peerDependenciesMeta: - '@aws-sdk/client-rds-data': - optional: true - '@cloudflare/workers-types': - optional: true - '@electric-sql/pglite': - optional: true - '@libsql/client': - optional: true - '@libsql/client-wasm': - optional: true - '@neondatabase/serverless': - optional: true - '@op-engineering/op-sqlite': - optional: true - '@opentelemetry/api': - optional: true - '@planetscale/database': - optional: true - '@prisma/client': - optional: true - '@tidbcloud/serverless': - optional: true - '@types/better-sqlite3': - optional: true - '@types/pg': - optional: true - '@types/react': - optional: true - '@types/sql.js': - optional: true - '@vercel/postgres': - optional: true - '@xata.io/client': - optional: true - better-sqlite3: - optional: true - bun-types: - optional: true - expo-sqlite: - optional: true - knex: - optional: true - kysely: - optional: true - mysql2: - optional: true - pg: - optional: true - postgres: - optional: true - prisma: - optional: true - react: - optional: true - sql.js: - optional: true - sqlite3: - optional: true - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - duplexer@0.1.2: - resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - electron-to-chromium@1.5.83: - resolution: {integrity: sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - - enhanced-resolve@5.18.0: - resolution: {integrity: sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==} - engines: {node: '>=10.13.0'} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - error-stack-parser-es@0.1.5: - resolution: {integrity: sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==} - - errx@0.1.0: - resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-module-lexer@1.6.0: - resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - esbuild-register@3.6.0: - resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} - peerDependencies: - esbuild: '>=0.12 <1' - - esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.24.2: - resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - - execa@7.2.0: - resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} - engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} - - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} - - externality@1.0.2: - resolution: {integrity: sha512-LyExtJWKxtgVzmgtEHyQtLFpw1KFhQphF9nTG8TpAIVkiI/xQ3FJh75tRFLYl4hkn7BNIIdLJInuDAavX35pMw==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-fifo@1.3.2: - resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-npm-meta@0.2.2: - resolution: {integrity: sha512-E+fdxeaOQGo/CMWc9f4uHFfgUPJRAu7N3uB8GBvB3SDPAIWJK4GKyYhkAGFq+GYrcbKNfQIz5VVQyJnDuPPCrg==} - - fastq@1.18.0: - resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} - - fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - flatted@3.3.2: - resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} - - foreground-child@3.3.0: - resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} - engines: {node: '>=14'} - - fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - - fs-extra@11.3.0: - resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} - engines: {node: '>=14.14'} - - fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - fuse.js@7.0.0: - resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==} - engines: {node: '>=10'} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-intrinsic@1.2.7: - resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} - engines: {node: '>= 0.4'} - - get-port-please@3.1.2: - resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} - - giget@1.2.3: - resolution: {integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==} - hasBin: true - - git-config-path@2.0.0: - resolution: {integrity: sha512-qc8h1KIQbJpp+241id3GuAtkdyJ+IK+LIVtkiFTRKRrmddDzs3SI9CvP1QYmWBFvm1I/PWRwj//of8bgAc0ltA==} - engines: {node: '>=4'} - - git-up@8.0.0: - resolution: {integrity: sha512-uBI8Zdt1OZlrYfGcSVroLJKgyNNXlgusYFzHk614lTasz35yg2PVpL1RMy0LOO2dcvF9msYW3pRfUSmafZNrjg==} - - git-url-parse@16.0.0: - resolution: {integrity: sha512-Y8iAF0AmCaqXc6a5GYgPQW9ESbncNLOL+CeQAJRhmWUOmnPkKpBYeWYp4mFd3LA5j53CdGDdslzX12yEBVHQQg==} - - github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - global-directory@4.0.1: - resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} - engines: {node: '>=18'} - - globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - - globby@14.0.2: - resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} - engines: {node: '>=18'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - gzip-size@7.0.0: - resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - h3@1.13.1: - resolution: {integrity: sha512-u/z6Z4YY+ANZ05cRRfsFJadTBrNA6e3jxdU+AN5UCbZSZEUwgHiwjvUEe0k1NoQmAvQmETwr+xB5jd7mhCJuIQ==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - hookable@5.5.3: - resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} - - html-tags@3.3.1: - resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} - engines: {node: '>=8'} - - http-assert@1.5.0: - resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==} - engines: {node: '>= 0.8'} - - http-errors@1.6.3: - resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} - engines: {node: '>= 0.6'} - - http-errors@1.8.1: - resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} - engines: {node: '>= 0.6'} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - http-shutdown@1.2.2: - resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - httpxy@0.1.6: - resolution: {integrity: sha512-GxJLI6oJZ3NbJl/vDlPmTCtP4WHwboNhGLHOcgf/3ia1QC5sdLglWbRHZwQjzjPuiCyw7MWwpwbsUfRDQlOdeg==} - - human-signals@4.3.1: - resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} - engines: {node: '>=14.18.0'} - - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.3: - resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} - engines: {node: '>= 4'} - - image-meta@0.2.1: - resolution: {integrity: sha512-K6acvFaelNxx8wc2VjbIzXKDVB0Khs0QT35U6NkGfTdCmjLNcO2945m7RFNR9/RPVFm48hq7QPzK8uGH18HCGw==} - - impound@0.2.0: - resolution: {integrity: sha512-gXgeSyp9Hf7qG2/PLKmywHXyQf2xFrw+mJGpoj9DsAB9L7/MIKn+DeEx98UryWXdmbv8wUUPdcQof6qXnZoCGg==} - - index-to-position@0.1.2: - resolution: {integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==} - engines: {node: '>=18'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.3: - resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - ini@4.1.1: - resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - ioredis@5.4.2: - resolution: {integrity: sha512-0SZXGNGZ+WzISQ67QDyZ2x0+wVxjjUndtD8oSeik/4ajifeiRufed8fCb8QW8VMyi4MXcS+UO1k/0NGhvq1PAg==} - engines: {node: '>=12.22.0'} - - iron-webcrypto@1.2.1: - resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - - is-installed-globally@1.0.0: - resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} - engines: {node: '>=18'} - - is-module@1.0.0: - resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-path-inside@4.0.0: - resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} - engines: {node: '>=12'} - - is-reference@1.2.1: - resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-ssh@1.4.0: - resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} - - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} - engines: {node: '>=16'} - - is64bit@2.0.0: - resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==} - engines: {node: '>=18'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} - hasBin: true - - jiti@2.4.2: - resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} - hasBin: true - - js-levenshtein@1.1.6: - resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} - engines: {node: '>=0.10.0'} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - - keygrip@1.1.0: - resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} - engines: {node: '>= 0.6'} - - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - - klona@2.0.6: - resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} - engines: {node: '>= 8'} - - knitwork@1.2.0: - resolution: {integrity: sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==} - - koa-compose@4.1.0: - resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==} - - koa-convert@2.0.0: - resolution: {integrity: sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==} - engines: {node: '>= 10'} - - koa-send@5.0.1: - resolution: {integrity: sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==} - engines: {node: '>= 8'} - - koa-static@5.0.0: - resolution: {integrity: sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==} - engines: {node: '>= 7.6.0'} - - koa@2.15.3: - resolution: {integrity: sha512-j/8tY9j5t+GVMLeioLaxweJiKUayFhlGqNTzf2ZGwL0ZCQijd2RLHK0SLW5Tsko8YyyqCZC2cojIb0/s62qTAg==} - engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4} - - kolorist@1.8.0: - resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} - - launch-editor@2.9.1: - resolution: {integrity: sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==} - - lazystream@1.0.1: - resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} - engines: {node: '>= 0.6.3'} - - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - listhen@1.9.0: - resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==} - hasBin: true - - local-pkg@0.5.1: - resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} - engines: {node: '>=14'} - - local-pkg@1.0.0: - resolution: {integrity: sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==} - engines: {node: '>=14'} - - lodash.defaults@4.2.0: - resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} - - lodash.isarguments@3.1.0: - resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} - - lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - - lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - magic-string-ast@0.7.0: - resolution: {integrity: sha512-686fgAHaJY7wLTFEq7nnKqeQrhqmXB19d1HnqT35Ci7BN6hbAYLZUezTQ062uUHM7ggZEQlqJ94Ftls+KDXU8Q==} - engines: {node: '>=16.14.0'} - - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - - magicast@0.3.5: - resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mdn-data@2.0.28: - resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} - - mdn-data@2.0.30: - resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} - - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - - mime@4.0.6: - resolution: {integrity: sha512-4rGt7rvQHBbaSOF9POGkk1ocRP16Md1x36Xma8sz8h8/vfCUI2OtEIeCqe4Ofes853x4xDoPiFLIT47J5fI/7A==} - engines: {node: '>=16'} - hasBin: true - - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - - minizlib@3.0.1: - resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} - engines: {node: '>= 18'} - - mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - - mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - mkdirp@3.0.1: - resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} - engines: {node: '>=10'} - hasBin: true - - mlly@1.7.4: - resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} - - mrmime@2.0.0: - resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} - engines: {node: '>=10'} - - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - - nanoid@3.3.8: - resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - nanoid@5.0.9: - resolution: {integrity: sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==} - engines: {node: ^18 || >=20} - hasBin: true - - nanotar@0.1.1: - resolution: {integrity: sha512-AiJsGsSF3O0havL1BydvI4+wR76sKT+okKRwWIaK96cZUnXqH0uNBOsHlbwZq3+m2BR1VKqHDVudl3gO4mYjpQ==} - - napi-build-utils@1.0.2: - resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} - - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - - nitropack@2.10.4: - resolution: {integrity: sha512-sJiG/MIQlZCVSw2cQrFG1H6mLeSqHlYfFerRjLKz69vUfdu0EL2l0WdOxlQbzJr3mMv/l4cOlCCLzVRzjzzF/g==} - engines: {node: ^16.11.0 || >=17.0.0} - hasBin: true - peerDependencies: - xml2js: ^0.6.2 - peerDependenciesMeta: - xml2js: - optional: true - - node-abi@3.73.0: - resolution: {integrity: sha512-z8iYzQGBu35ZkTQ9mtR8RqugJZ9RCLn8fv3d7LsgDBzOijGQP3RdKTX4LA7LXw03ZhU5z0l4xfhIMgSES31+cg==} - engines: {node: '>=10'} - - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - - node-fetch-native@1.6.4: - resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} - engines: {node: '>= 6.13.0'} - - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true - - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - - nopt@8.0.0: - resolution: {integrity: sha512-1L/fTJ4UmV/lUxT2Uf006pfZKTvAgCF+chz+0OgBHO8u2Z67pE7AaAUUj7CJy0lXqHmymUvGFt6NE9R3HER0yw==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - nuxt@3.15.2: - resolution: {integrity: sha512-1EiQ5wYYVhgkRyaMCyuc4R5lhJtOPJTdOe3LwYNbIol3pmcO1urhNDNKfhiy9zdcA3G14zzN0W/+TqXXidchRw==} - engines: {node: ^18.20.5 || ^20.9.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@parcel/watcher': ^2.1.0 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - peerDependenciesMeta: - '@parcel/watcher': - optional: true - '@types/node': - optional: true - - nypm@0.3.12: - resolution: {integrity: sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA==} - engines: {node: ^14.16.0 || >=16.10.0} - hasBin: true - - nypm@0.4.1: - resolution: {integrity: sha512-1b9mihliBh8UCcKtcGRu//G50iHpjxIQVUqkdhPT/SDVE7KdJKoHXLS0heuYTQCx95dFqiyUbXZB9r8ikn+93g==} - engines: {node: ^14.16.0 || >=16.10.0} - hasBin: true - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} - - ofetch@1.4.1: - resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} - - ohash@1.1.4: - resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - - only@0.0.2: - resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==} - - open@10.1.0: - resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} - engines: {node: '>=18'} - - open@7.4.2: - resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} - engines: {node: '>=8'} - - open@8.4.2: - resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} - engines: {node: '>=12'} - - openapi-typescript@7.5.2: - resolution: {integrity: sha512-W/QXuQz0Fa3bGY6LKoqTCgrSX+xI/ST+E5RXo2WBmp3WwgXCWKDJPHv5GZmElF4yLCccnqYsakBDOJikHZYGRw==} - hasBin: true - peerDependencies: - typescript: ^5.x - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - package-manager-detector@0.2.8: - resolution: {integrity: sha512-ts9KSdroZisdvKMWVAVCXiKqnqNfXz4+IbrBG8/BWx/TR5le+jfenvoBuIZ6UWM9nz47W7AbD9qYfAwfWMIwzA==} - - packrup@0.1.2: - resolution: {integrity: sha512-ZcKU7zrr5GlonoS9cxxrb5HVswGnyj6jQvwFBa6p5VFw7G71VAHcUKL5wyZSU/ECtPM/9gacWxy2KFQKt1gMNA==} - - parse-git-config@3.0.0: - resolution: {integrity: sha512-wXoQGL1D+2COYWCD35/xbiKma1Z15xvZL8cI25wvxzled58V51SJM04Urt/uznS900iQor7QO04SgdfT/XlbuA==} - engines: {node: '>=8'} - - parse-json@8.1.0: - resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==} - engines: {node: '>=18'} - - parse-path@7.0.0: - resolution: {integrity: sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==} - - parse-url@9.2.0: - resolution: {integrity: sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==} - engines: {node: '>=14.13.0'} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - path-to-regexp@6.3.0: - resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - - path-type@5.0.0: - resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} - engines: {node: '>=12'} - - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - - pathe@2.0.2: - resolution: {integrity: sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==} - - perfect-debounce@1.0.0: - resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - - pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} - - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - portfinder@1.0.32: - resolution: {integrity: sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==} - engines: {node: '>= 0.12.0'} - - postcss-calc@10.1.0: - resolution: {integrity: sha512-uQ/LDGsf3mgsSUEXmAt3VsCSHR3aKqtEIkmB+4PhzYwRYOW5MZs/GhCCFpsOtJJkP6EC6uGipbrnaTjqaJZcJw==} - engines: {node: ^18.12 || ^20.9 || >=22.0} - peerDependencies: - postcss: ^8.4.38 - - postcss-colormin@7.0.2: - resolution: {integrity: sha512-YntRXNngcvEvDbEjTdRWGU606eZvB5prmHG4BF0yLmVpamXbpsRJzevyy6MZVyuecgzI2AWAlvFi8DAeCqwpvA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-convert-values@7.0.4: - resolution: {integrity: sha512-e2LSXPqEHVW6aoGbjV9RsSSNDO3A0rZLCBxN24zvxF25WknMPpX8Dm9UxxThyEbaytzggRuZxaGXqaOhxQ514Q==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-discard-comments@7.0.3: - resolution: {integrity: sha512-q6fjd4WU4afNhWOA2WltHgCbkRhZPgQe7cXF74fuVB/ge4QbM9HEaOIzGSiMvM+g/cOsNAUGdf2JDzqA2F8iLA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-discard-duplicates@7.0.1: - resolution: {integrity: sha512-oZA+v8Jkpu1ct/xbbrntHRsfLGuzoP+cpt0nJe5ED2FQF8n8bJtn7Bo28jSmBYwqgqnqkuSXJfSUEE7if4nClQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-discard-empty@7.0.0: - resolution: {integrity: sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-discard-overridden@7.0.0: - resolution: {integrity: sha512-GmNAzx88u3k2+sBTZrJSDauR0ccpE24omTQCVmaTTZFz1du6AasspjaUPMJ2ud4RslZpoFKyf+6MSPETLojc6w==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.0.0 - - postcss-js@4.0.1: - resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.4.21 - - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - - postcss-merge-longhand@7.0.4: - resolution: {integrity: sha512-zer1KoZA54Q8RVHKOY5vMke0cCdNxMP3KBfDerjH/BYHh4nCIh+1Yy0t1pAEQF18ac/4z3OFclO+ZVH8azjR4A==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-merge-rules@7.0.4: - resolution: {integrity: sha512-ZsaamiMVu7uBYsIdGtKJ64PkcQt6Pcpep/uO90EpLS3dxJi6OXamIobTYcImyXGoW0Wpugh7DSD3XzxZS9JCPg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-minify-font-values@7.0.0: - resolution: {integrity: sha512-2ckkZtgT0zG8SMc5aoNwtm5234eUx1GGFJKf2b1bSp8UflqaeFzR50lid4PfqVI9NtGqJ2J4Y7fwvnP/u1cQog==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-minify-gradients@7.0.0: - resolution: {integrity: sha512-pdUIIdj/C93ryCHew0UgBnL2DtUS3hfFa5XtERrs4x+hmpMYGhbzo6l/Ir5de41O0GaKVpK1ZbDNXSY6GkXvtg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-minify-params@7.0.2: - resolution: {integrity: sha512-nyqVLu4MFl9df32zTsdcLqCFfE/z2+f8GE1KHPxWOAmegSo6lpV2GNy5XQvrzwbLmiU7d+fYay4cwto1oNdAaQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-minify-selectors@7.0.4: - resolution: {integrity: sha512-JG55VADcNb4xFCf75hXkzc1rNeURhlo7ugf6JjiiKRfMsKlDzN9CXHZDyiG6x/zGchpjQS+UAgb1d4nqXqOpmA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 - - postcss-nesting@13.0.1: - resolution: {integrity: sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==} - engines: {node: '>=18'} - peerDependencies: - postcss: ^8.4 - - postcss-normalize-charset@7.0.0: - resolution: {integrity: sha512-ABisNUXMeZeDNzCQxPxBCkXexvBrUHV+p7/BXOY+ulxkcjUZO0cp8ekGBwvIh2LbCwnWbyMPNJVtBSdyhM2zYQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-display-values@7.0.0: - resolution: {integrity: sha512-lnFZzNPeDf5uGMPYgGOw7v0BfB45+irSRz9gHQStdkkhiM0gTfvWkWB5BMxpn0OqgOQuZG/mRlZyJxp0EImr2Q==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-positions@7.0.0: - resolution: {integrity: sha512-I0yt8wX529UKIGs2y/9Ybs2CelSvItfmvg/DBIjTnoUSrPxSV7Z0yZ8ShSVtKNaV/wAY+m7bgtyVQLhB00A1NQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-repeat-style@7.0.0: - resolution: {integrity: sha512-o3uSGYH+2q30ieM3ppu9GTjSXIzOrRdCUn8UOMGNw7Af61bmurHTWI87hRybrP6xDHvOe5WlAj3XzN6vEO8jLw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-string@7.0.0: - resolution: {integrity: sha512-w/qzL212DFVOpMy3UGyxrND+Kb0fvCiBBujiaONIihq7VvtC7bswjWgKQU/w4VcRyDD8gpfqUiBQ4DUOwEJ6Qg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-timing-functions@7.0.0: - resolution: {integrity: sha512-tNgw3YV0LYoRwg43N3lTe3AEWZ66W7Dh7lVEpJbHoKOuHc1sLrzMLMFjP8SNULHaykzsonUEDbKedv8C+7ej6g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-unicode@7.0.2: - resolution: {integrity: sha512-ztisabK5C/+ZWBdYC+Y9JCkp3M9qBv/XFvDtSw0d/XwfT3UaKeW/YTm/MD/QrPNxuecia46vkfEhewjwcYFjkg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-url@7.0.0: - resolution: {integrity: sha512-+d7+PpE+jyPX1hDQZYG+NaFD+Nd2ris6r8fPTBAjE8z/U41n/bib3vze8x7rKs5H1uEw5ppe9IojewouHk0klQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-whitespace@7.0.0: - resolution: {integrity: sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-ordered-values@7.0.1: - resolution: {integrity: sha512-irWScWRL6nRzYmBOXReIKch75RRhNS86UPUAxXdmW/l0FcAsg0lvAXQCby/1lymxn/o0gVa6Rv/0f03eJOwHxw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-reduce-initial@7.0.2: - resolution: {integrity: sha512-pOnu9zqQww7dEKf62Nuju6JgsW2V0KRNBHxeKohU+JkHd/GAH5uvoObqFLqkeB2n20mr6yrlWDvo5UBU5GnkfA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-reduce-transforms@7.0.0: - resolution: {integrity: sha512-pnt1HKKZ07/idH8cpATX/ujMbtOGhUfE+m8gbqwJE05aTaNw8gbo34a2e3if0xc0dlu75sUOiqvwCGY3fzOHew==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} - - postcss-selector-parser@7.0.0: - resolution: {integrity: sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==} - engines: {node: '>=4'} - - postcss-svgo@7.0.1: - resolution: {integrity: sha512-0WBUlSL4lhD9rA5k1e5D8EN5wCEyZD6HJk0jIvRxl+FDVOMlJ7DePHYWGGVc5QRqrJ3/06FTXM0bxjmJpmTPSA==} - engines: {node: ^18.12.0 || ^20.9.0 || >= 18} - peerDependencies: - postcss: ^8.4.31 - - postcss-unique-selectors@7.0.3: - resolution: {integrity: sha512-J+58u5Ic5T1QjP/LDV9g3Cx4CNOgB5vz+kM6+OxHHhFACdcDeKhBXjQmB7fnIZM12YSTvsL0Opwco83DmacW2g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - - postcss@8.5.1: - resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} - engines: {node: ^10 || ^12 || >=14} - - prebuild-install@7.1.2: - resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} - engines: {node: '>=10'} - hasBin: true - - pretty-bytes@6.1.1: - resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} - engines: {node: ^14.13.1 || >=16.0.0} - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - - protocols@2.0.1: - resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} - - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - queue-tick@1.0.1: - resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} - - radix3@1.1.2: - resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - rc9@2.1.2: - resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - readdir-glob@1.1.3: - resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - readdirp@4.1.1: - resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} - engines: {node: '>= 14.18.0'} - - redis-errors@1.2.0: - resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} - engines: {node: '>=4'} - - redis-parser@3.0.0: - resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} - engines: {node: '>=4'} - - replace-in-file@6.3.5: - resolution: {integrity: sha512-arB9d3ENdKva2fxRnSjwBEXfK1npgyci7ZZuwysgAp7ORjHSyxz6oqIjTEv8R0Ydl4Ll7uOAZXL4vbkhGIizCg==} - engines: {node: '>=10'} - hasBin: true - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve-path@1.4.0: - resolution: {integrity: sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==} - engines: {node: '>= 0.8'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - - rimraf@5.0.10: - resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} - hasBin: true - - rollup-plugin-visualizer@5.14.0: - resolution: {integrity: sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - rolldown: 1.x - rollup: 2.x || 3.x || 4.x - peerDependenciesMeta: - rolldown: - optional: true - rollup: - optional: true - - rollup@4.30.1: - resolution: {integrity: sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - run-applescript@7.0.0: - resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} - engines: {node: '>=18'} - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - scule@1.3.0: - resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} - engines: {node: '>=10'} - hasBin: true - - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - - serve-placeholder@2.0.2: - resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==} - - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - - setprototypeof@1.1.0: - resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.2: - resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} - engines: {node: '>= 0.4'} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - - simple-git@3.27.0: - resolution: {integrity: sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==} - - sirv@3.0.0: - resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} - engines: {node: '>=18'} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - slash@5.1.0: - resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} - engines: {node: '>=14.16'} - - smob@1.5.0: - resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} - - speakingurl@14.0.1: - resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} - engines: {node: '>=0.10.0'} - - standard-as-callback@2.1.0: - resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} - - statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - std-env@3.8.0: - resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} - - streamx@2.21.1: - resolution: {integrity: sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - strip-literal@2.1.1: - resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} - - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} - - stylehacks@7.0.4: - resolution: {integrity: sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - superjson@2.2.2: - resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} - engines: {node: '>=16'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@9.4.0: - resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} - engines: {node: '>=12'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - svg-tags@1.0.0: - resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} - - svgo@3.3.2: - resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} - engines: {node: '>=14.0.0'} - hasBin: true - - system-architecture@0.1.0: - resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} - engines: {node: '>=18'} - - tailwind-config-viewer@2.0.4: - resolution: {integrity: sha512-icvcmdMmt9dphvas8wL40qttrHwAnW3QEN4ExJ2zICjwRsPj7gowd1cOceaWG3IfTuM/cTNGQcx+bsjMtmV+cw==} - engines: {node: '>=13'} - hasBin: true - peerDependencies: - tailwindcss: 1 || 2 || 2.0.1-compat || 3 - - tailwindcss@3.4.17: - resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} - engines: {node: '>=14.0.0'} - hasBin: true - - tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} - - tar-fs@2.1.2: - resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} - - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} - - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - - tar@7.4.3: - resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} - engines: {node: '>=18'} - - terser@5.37.0: - resolution: {integrity: sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==} - engines: {node: '>=10'} - hasBin: true - - text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} - - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - - tinyglobby@0.2.10: - resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} - engines: {node: '>=12.0.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - totalist@3.0.1: - resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} - engines: {node: '>=6'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - - tsscmp@1.0.6: - resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} - engines: {node: '>=0.6.x'} - - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - - type-fest@4.32.0: - resolution: {integrity: sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw==} - engines: {node: '>=16'} - - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - - typescript@5.7.3: - resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} - - ultrahtml@1.5.3: - resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==} - - uncrypto@0.1.3: - resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - - unctx@2.4.1: - resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==} - - undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - - unenv@1.10.0: - resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==} - - unhead@1.11.18: - resolution: {integrity: sha512-TWgGUoZMpYe2yJwY6jZ0/9kpQT18ygr2h5lI6cUXdfD9UzDc0ytM9jGaleSYkj9guJWXkk7izYBnzJvxl8mRvQ==} - - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} - engines: {node: '>=18'} - - unimport@3.14.6: - resolution: {integrity: sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - unplugin-vue-router@0.10.9: - resolution: {integrity: sha512-DXmC0GMcROOnCmN56GRvi1bkkG1BnVs4xJqNvucBUeZkmB245URvtxOfbo3H6q4SOUQQbLPYWd6InzvjRh363A==} - peerDependencies: - vue-router: ^4.4.0 - peerDependenciesMeta: - vue-router: - optional: true - - unplugin@1.16.1: - resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} - engines: {node: '>=14.0.0'} - - unplugin@2.0.0-beta.1: - resolution: {integrity: sha512-2qzQo5LN2DmUZXkWDHvGKLF5BP0WN+KthD6aPnPJ8plRBIjv4lh5O07eYcSxgO2znNw9s4MNhEO1sB+JDllDbQ==} - engines: {node: '>=18.12.0'} - - unplugin@2.1.2: - resolution: {integrity: sha512-Q3LU0e4zxKfRko1wMV2HmP8lB9KWislY7hxXpxd+lGx0PRInE4vhMBVEZwpdVYHvtqzhSrzuIfErsob6bQfCzw==} - engines: {node: '>=18.12.0'} - - unstorage@1.14.4: - resolution: {integrity: sha512-1SYeamwuYeQJtJ/USE1x4l17LkmQBzg7deBJ+U9qOBoHo15d1cDxG4jM31zKRgF7pG0kirZy4wVMX6WL6Zoscg==} - peerDependencies: - '@azure/app-configuration': ^1.8.0 - '@azure/cosmos': ^4.2.0 - '@azure/data-tables': ^13.3.0 - '@azure/identity': ^4.5.0 - '@azure/keyvault-secrets': ^4.9.0 - '@azure/storage-blob': ^12.26.0 - '@capacitor/preferences': ^6.0.3 - '@deno/kv': '>=0.8.4' - '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 - '@planetscale/database': ^1.19.0 - '@upstash/redis': ^1.34.3 - '@vercel/blob': '>=0.27.0' - '@vercel/kv': ^1.0.1 - aws4fetch: ^1.0.20 - db0: '>=0.2.1' - idb-keyval: ^6.2.1 - ioredis: ^5.4.2 - uploadthing: ^7.4.1 - peerDependenciesMeta: - '@azure/app-configuration': - optional: true - '@azure/cosmos': - optional: true - '@azure/data-tables': - optional: true - '@azure/identity': - optional: true - '@azure/keyvault-secrets': - optional: true - '@azure/storage-blob': - optional: true - '@capacitor/preferences': - optional: true - '@deno/kv': - optional: true - '@netlify/blobs': - optional: true - '@planetscale/database': - optional: true - '@upstash/redis': - optional: true - '@vercel/blob': - optional: true - '@vercel/kv': - optional: true - aws4fetch: - optional: true - db0: - optional: true - idb-keyval: - optional: true - ioredis: - optional: true - uploadthing: - optional: true - - untun@0.1.3: - resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} - hasBin: true - - untyped@1.5.2: - resolution: {integrity: sha512-eL/8PlhLcMmlMDtNPKhyyz9kEBDS3Uk4yMu/ewlkT2WFbtzScjHWPJLdQLmaGPUKjXzwe9MumOtOgc4Fro96Kg==} - hasBin: true - - unwasm@0.3.9: - resolution: {integrity: sha512-LDxTx/2DkFURUd+BU1vUsF/moj0JsoTvl+2tcg2AUOiEzVturhGGx17/IMgGvKUYdZwr33EJHtChCJuhu9Ouvg==} - - update-browserslist-db@1.1.2: - resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uqr@0.1.2: - resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} - - uri-js-replace@1.0.1: - resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} - - urlpattern-polyfill@8.0.2: - resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - vite-hot-client@0.2.4: - resolution: {integrity: sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==} - peerDependencies: - vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 - - vite-node@2.1.8: - resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - - vite-plugin-checker@0.8.0: - resolution: {integrity: sha512-UA5uzOGm97UvZRTdZHiQVYFnd86AVn8EVaD4L3PoVzxH+IZSfaAw14WGFwX9QS23UW3lV/5bVKZn6l0w+q9P0g==} - engines: {node: '>=14.16'} - peerDependencies: - '@biomejs/biome': '>=1.7' - eslint: '>=7' - meow: ^9.0.0 - optionator: ^0.9.1 - stylelint: '>=13' - typescript: '*' - vite: '>=2.0.0' - vls: '*' - vti: '*' - vue-tsc: ~2.1.6 - peerDependenciesMeta: - '@biomejs/biome': - optional: true - eslint: - optional: true - meow: - optional: true - optionator: - optional: true - stylelint: - optional: true - typescript: - optional: true - vls: - optional: true - vti: - optional: true - vue-tsc: - optional: true - - vite-plugin-inspect@0.8.9: - resolution: {integrity: sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==} - engines: {node: '>=14'} - peerDependencies: - '@nuxt/kit': '*' - vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.1 - peerDependenciesMeta: - '@nuxt/kit': - optional: true - - vite-plugin-vue-inspector@5.3.1: - resolution: {integrity: sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==} - peerDependencies: - vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 - - vite@5.4.11: - resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true + /@jridgewell/remapping@2.3.5: + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - vite@6.0.7: - resolution: {integrity: sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} - vscode-jsonrpc@6.0.0: - resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} - engines: {node: '>=8.0.0 || >=10.0.0'} + /@jridgewell/source-map@0.3.11: + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + dev: false - vscode-languageclient@7.0.0: - resolution: {integrity: sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==} - engines: {vscode: ^1.52.0} + /@jridgewell/sourcemap-codec@1.5.5: + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - vscode-languageserver-protocol@3.16.0: - resolution: {integrity: sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==} + /@jridgewell/trace-mapping@0.3.31: + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - vscode-languageserver-textdocument@1.0.12: - resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + /@kwsites/file-exists@1.1.1: + resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + dev: false - vscode-languageserver-types@3.16.0: - resolution: {integrity: sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==} + /@kwsites/promise-deferred@1.1.1: + resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + dev: false - vscode-languageserver@7.0.0: - resolution: {integrity: sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==} + /@mapbox/node-pre-gyp@2.0.3: + resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} + engines: {node: '>=18'} hasBin: true + dependencies: + consola: 3.4.2 + detect-libc: 2.1.2 + https-proxy-agent: 7.0.6 + node-fetch: 2.7.0 + nopt: 8.1.0 + semver: 7.7.3 + tar: 7.5.4 + transitivePeerDependencies: + - encoding + - supports-color + dev: false - vscode-uri@3.0.8: - resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} - - vue-bundle-renderer@2.1.1: - resolution: {integrity: sha512-+qALLI5cQncuetYOXp4yScwYvqh8c6SMXee3B+M7oTZxOgtESP0l4j/fXdEJoZ+EdMxkGWIj+aSEyjXkOdmd7g==} - - vue-devtools-stub@0.1.0: - resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} - - vue-router@4.5.0: - resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==} - peerDependencies: - vue: ^3.2.0 + /@napi-rs/lzma-linux-x64-gnu@1.5.1: + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true - vue@3.5.13: - resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + /@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3): + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + requiresBuild: true peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - webpack-virtual-modules@0.6.2: - resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@tybys/wasm-util': 0.10.3 + dev: false + optional: true - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} - hasBin: true - - which@3.0.1: - resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - hasBin: true - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yallist@5.0.0: - resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} - engines: {node: '>=18'} - - yaml-ast-parser@0.0.43: - resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} - - yaml@2.7.0: - resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} - engines: {node: '>= 14'} - hasBin: true - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - ylru@1.4.0: - resolution: {integrity: sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==} - engines: {node: '>= 4.0.0'} - - zhead@2.2.4: - resolution: {integrity: sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==} - - zip-stream@6.0.1: - resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} - engines: {node: '>= 14'} - - zod@3.24.1: - resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} - -snapshots: - - '@alloc/quick-lru@5.2.0': {} - - '@ampproject/remapping@2.3.0': dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: false - '@antfu/utils@0.7.10': {} + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: false - '@babel/code-frame@7.26.2': + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} dependencies: - '@babel/helper-validator-identifier': 7.25.9 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.26.5': {} + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + dev: false - '@babel/core@7.26.0': + /@nuxt/cli@3.32.0: + resolution: {integrity: sha512-n2f3SRjPlhthPvo2qWjLRRiTrUtB6WFwg0BGsvtqcqZVeQpNEU371zuKWBaFrWgqDZHV1r/aD9jrVCo+C8Pmrw==} + engines: {node: ^16.10.0 || >=18.0.0} + hasBin: true dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.5 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helpers': 7.26.0 - '@babel/parser': 7.26.5 - '@babel/template': 7.25.9 - '@babel/traverse': 7.26.5 - '@babel/types': 7.26.5 - convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@9.4.0) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 + '@bomb.sh/tab': 0.0.11(citty@0.1.6) + '@clack/prompts': 1.0.0-alpha.9 + c12: 3.3.3(magicast@0.5.1) + citty: 0.1.6 + confbox: 0.2.2 + consola: 3.4.2 + copy-paste: 2.2.0 + debug: 4.4.3 + defu: 6.1.4 + exsolve: 1.0.8 + fuse.js: 7.1.0 + giget: 2.0.0 + jiti: 2.6.1 + listhen: 1.9.0 + nypm: 0.6.2 + ofetch: 1.5.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + scule: 1.3.0 + semver: 7.7.3 + srvx: 0.10.1 + std-env: 3.10.0 + tinyexec: 1.0.2 + ufo: 1.6.1 + youch: 4.1.0-beta.13 transitivePeerDependencies: + - cac + - commander + - magicast - supports-color + dev: false - '@babel/generator@7.26.5': - dependencies: - '@babel/parser': 7.26.5 - '@babel/types': 7.26.5 - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.1.0 + /@nuxt/devalue@2.0.2: + resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==} + dev: false - '@babel/helper-annotate-as-pure@7.25.9': + /@nuxt/devtools-kit@3.1.1(magicast@0.5.1)(vite@7.3.6): + resolution: {integrity: sha512-sjiKFeDCOy1SyqezSgyV4rYNfQewC64k/GhOsuJgRF+wR2qr6KTVhO6u2B+csKs74KrMrnJprQBgud7ejvOXAQ==} + peerDependencies: + vite: '>=6.0' dependencies: - '@babel/types': 7.26.5 + '@nuxt/kit': 4.2.1(magicast@0.5.1) + execa: 8.0.1 + vite: 7.3.6(tsx@4.21.0) + transitivePeerDependencies: + - magicast + dev: false - '@babel/helper-compilation-targets@7.26.5': + /@nuxt/devtools-wizard@3.1.1: + resolution: {integrity: sha512-6UORjapNKko2buv+3o57DQp69n5Z91TeJ75qdtNKcTvOfCTJrO78Ew0nZSgMMGrjbIJ4pFsHQEqXfgYLw3pNxg==} + hasBin: true dependencies: - '@babel/compat-data': 7.26.5 - '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.4 - lru-cache: 5.1.1 - semver: 6.3.1 + consola: 3.4.2 + diff: 8.0.2 + execa: 8.0.1 + magicast: 0.5.1 + pathe: 2.0.3 + pkg-types: 2.3.0 + prompts: 2.4.2 + semver: 7.7.3 + dev: false - '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': + /@nuxt/devtools@3.1.1(vite@7.3.6)(vue@3.5.27): + resolution: {integrity: sha512-UG8oKQqcSyzwBe1l0z24zypmwn6FLW/HQMHK/F/gscUU5LeMHzgBhLPD+cuLlDvwlGAbifexWNMsS/I7n95KlA==} + hasBin: true + peerDependencies: + '@vitejs/devtools': '*' + vite: '>=6.0' + peerDependenciesMeta: + '@vitejs/devtools': + optional: true dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/traverse': 7.26.5 - semver: 6.3.1 + '@nuxt/devtools-kit': 3.1.1(magicast@0.5.1)(vite@7.3.6) + '@nuxt/devtools-wizard': 3.1.1 + '@nuxt/kit': 4.2.2(magicast@0.5.1) + '@vue/devtools-core': 8.0.5(vite@7.3.6)(vue@3.5.27) + '@vue/devtools-kit': 8.0.5 + birpc: 2.8.0 + consola: 3.4.2 + destr: 2.0.5 + error-stack-parser-es: 1.0.5 + execa: 8.0.1 + fast-npm-meta: 0.4.7 + get-port-please: 3.2.0 + hookable: 5.5.3 + image-meta: 0.2.2 + is-installed-globally: 1.0.0 + launch-editor: 2.12.0 + local-pkg: 1.1.2 + magicast: 0.5.1 + nypm: 0.6.2 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + semver: 7.7.3 + simple-git: 3.30.0 + sirv: 3.0.2 + structured-clone-es: 1.0.0 + tinyglobby: 0.2.15 + vite: 7.3.6(tsx@4.21.0) + vite-plugin-inspect: 11.3.3(@nuxt/kit@4.2.2)(vite@7.3.6) + vite-plugin-vue-tracer: 1.1.3(vite@7.3.6)(vue@3.5.27) + which: 5.0.0 + ws: 8.18.3 transitivePeerDependencies: + - bufferutil - supports-color + - utf-8-validate + - vue + dev: false - '@babel/helper-member-expression-to-functions@7.25.9': + /@nuxt/fonts@0.12.1(vite@7.3.6): + resolution: {integrity: sha512-ALajI/HE+uqqL/PWkWwaSUm1IdpyGPbP3mYGy2U1l26/o4lUZBxjFaduMxaZ85jS5yQeJfCu2eEHANYFjAoujQ==} dependencies: - '@babel/traverse': 7.26.5 - '@babel/types': 7.26.5 + '@nuxt/devtools-kit': 3.1.1(magicast@0.5.1)(vite@7.3.6) + '@nuxt/kit': 4.2.1(magicast@0.5.1) + consola: 3.4.2 + css-tree: 3.1.0 + defu: 6.1.4 + esbuild: 0.25.12 + fontaine: 0.7.0 + fontless: 0.1.0(vite@7.3.6) + h3: 1.15.4 + jiti: 2.6.1 + magic-regexp: 0.10.0 + magic-string: 0.30.21 + node-fetch-native: 1.6.7 + ohash: 2.0.11 + pathe: 2.0.3 + sirv: 3.0.2 + tinyglobby: 0.2.15 + ufo: 1.6.1 + unifont: 0.6.0 + unplugin: 2.3.10 + unstorage: 1.17.2 transitivePeerDependencies: - - supports-color + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - magicast + - uploadthing + - vite + dev: false - '@babel/helper-module-imports@7.25.9': + /@nuxt/kit@3.20.2: + resolution: {integrity: sha512-laqfmMcWWNV1FsVmm1+RQUoGY8NIJvCRl0z0K8ikqPukoEry0LXMqlQ+xaf8xJRvoH2/78OhZmsEEsUBTXipcw==} + engines: {node: '>=18.12.0'} dependencies: - '@babel/traverse': 7.26.5 - '@babel/types': 7.26.5 + c12: 3.3.3(magicast@0.5.1) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.8 + ignore: 7.0.5 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.3.0 + mlly: 1.8.0 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 2.1.2 + scule: 1.3.0 + semver: 7.7.3 + tinyglobby: 0.2.15 + ufo: 1.6.1 + unctx: 2.5.0 + untyped: 2.0.0 transitivePeerDependencies: - - supports-color + - magicast - '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + /@nuxt/kit@4.2.1(magicast@0.5.1): + resolution: {integrity: sha512-lLt8KLHyl7IClc3RqRpRikz15eCfTRlAWL9leVzPyg5N87FfKE/7EWgWvpiL/z4Tf3dQCIqQb88TmHE0JTIDvA==} + engines: {node: '>=18.12.0'} dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.26.5 + c12: 3.3.2(magicast@0.5.1) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.8 + ignore: 7.0.5 + jiti: 2.6.1 + klona: 2.0.6 + mlly: 1.8.0 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 2.1.2 + scule: 1.3.0 + semver: 7.7.3 + tinyglobby: 0.2.15 + ufo: 1.6.1 + unctx: 2.4.1 + untyped: 2.0.0 transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.25.9': - dependencies: - '@babel/types': 7.26.5 - - '@babel/helper-plugin-utils@7.26.5': {} + - magicast + dev: false - '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.0)': + /@nuxt/kit@4.2.2(magicast@0.5.1): + resolution: {integrity: sha512-ZAgYBrPz/yhVgDznBNdQj2vhmOp31haJbO0I0iah/P9atw+OHH7NJLUZ3PK+LOz/0fblKTN1XJVSi8YQ1TQ0KA==} + engines: {node: '>=18.12.0'} dependencies: - '@babel/core': 7.26.0 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/traverse': 7.26.5 + c12: 3.3.2(magicast@0.5.1) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.8 + ignore: 7.0.5 + jiti: 2.6.1 + klona: 2.0.6 + mlly: 1.8.0 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 2.1.2 + scule: 1.3.0 + semver: 7.7.3 + tinyglobby: 0.2.15 + ufo: 1.6.1 + unctx: 2.4.1 + untyped: 2.0.0 transitivePeerDependencies: - - supports-color + - magicast + dev: false - '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + /@nuxt/nitro-server@4.2.2(better-sqlite3@12.11.1)(drizzle-orm@0.45.1)(nuxt@4.2.2)(typescript@5.9.3): + resolution: {integrity: sha512-lDITf4n5bHQ6a5MO7pvkpdQbPdWAUgSvztSHCfui/3ioLZsM2XntlN02ue6GSoh3oV9H4xSB3qGa+qlSjgxN0A==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + nuxt: ^4.2.2 dependencies: - '@babel/traverse': 7.26.5 - '@babel/types': 7.26.5 + '@nuxt/devalue': 2.0.2 + '@nuxt/kit': 4.2.2(magicast@0.5.1) + '@unhead/vue': 2.0.19(vue@3.5.27) + '@vue/shared': 3.5.25 + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + devalue: 5.6.2 + errx: 0.1.0 + escape-string-regexp: 5.0.0 + exsolve: 1.0.8 + h3: 1.15.4 + impound: 1.0.0 + klona: 2.0.6 + mocked-exports: 0.1.1 + nitropack: 2.13.1(better-sqlite3@12.11.1)(drizzle-orm@0.45.1) + nuxt: 4.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@vue/compiler-sfc@3.5.42)(better-sqlite3@12.11.1)(drizzle-orm@0.45.1)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.6) + pathe: 2.0.3 + pkg-types: 2.3.0 + radix3: 1.1.2 + std-env: 3.10.0 + ufo: 1.6.1 + unctx: 2.4.1 + unstorage: 1.17.4(db0@0.3.4)(ioredis@5.9.2) + vue: 3.5.27(typescript@5.9.3) + vue-bundle-renderer: 2.2.0 + vue-devtools-stub: 0.1.0 transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - better-sqlite3 + - db0 + - drizzle-orm + - encoding + - idb-keyval + - ioredis + - magicast + - mysql2 + - react-native-b4a + - rolldown + - sqlite3 - supports-color + - typescript + - uploadthing + - xml2js + dev: false - '@babel/helper-string-parser@7.25.9': {} - - '@babel/helper-validator-identifier@7.25.9': {} - - '@babel/helper-validator-option@7.25.9': {} - - '@babel/helpers@7.26.0': - dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.5 - - '@babel/parser@7.26.5': + /@nuxt/schema@4.2.2: + resolution: {integrity: sha512-lW/1MNpO01r5eR/VoeanQio8Lg4QpDklMOHa4mBHhhPNlBO1qiRtVYzjcnNdun3hujGauRaO9khGjv93Z5TZZA==} + engines: {node: ^14.18.0 || >=16.10.0} dependencies: - '@babel/types': 7.26.5 + '@vue/shared': 3.5.25 + defu: 6.1.4 + pathe: 2.0.3 + pkg-types: 2.3.0 + std-env: 3.10.0 + dev: false - '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.0)': + /@nuxt/telemetry@2.6.6: + resolution: {integrity: sha512-Zh4HJLjzvm3Cq9w6sfzIFyH9ozK5ePYVfCUzzUQNiZojFsI2k1QkSBrVI9BGc6ArKXj/O6rkI6w7qQ+ouL8Cag==} + engines: {node: '>=18.12.0'} + hasBin: true dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.0) + '@nuxt/kit': 3.20.2 + citty: 0.1.6 + consola: 3.4.2 + destr: 2.0.5 + dotenv: 16.6.1 + git-url-parse: 16.0.1 + is-docker: 3.0.0 + ofetch: 1.5.1 + package-manager-detector: 1.1.0 + pathe: 2.0.3 + rc9: 2.1.2 + std-env: 3.10.0 transitivePeerDependencies: - - supports-color - - '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.26.5 - - '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.26.5 - - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.26.5 - - '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.26.5 - - '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.26.5 + - magicast + dev: false - '@babel/plugin-transform-typescript@7.26.5(@babel/core@7.26.0)': + /@nuxt/test-utils@3.23.0(@vue/test-utils@2.4.6)(happy-dom@18.0.1)(playwright-core@1.57.0)(typescript@5.9.3)(vitest@3.2.4): + resolution: {integrity: sha512-NZKWSwvfIiTO2qhMoJHVbUQLgJMe96J9ccLhPPqN5+a/XzISZ027LG9wWVp1tC5oB0qQ3eUDhrxmq6Lj8EQLMQ==} + engines: {node: ^20.11.1 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@cucumber/cucumber': ^10.3.1 || >=11.0.0 + '@jest/globals': ^29.5.0 || >=30.0.0 + '@playwright/test': ^1.43.1 + '@testing-library/vue': ^7.0.0 || ^8.0.1 + '@vitest/ui': '*' + '@vue/test-utils': ^2.4.2 + happy-dom: '*' + jsdom: '*' + playwright-core: ^1.43.1 + vitest: ^3.2.0 + peerDependenciesMeta: + '@cucumber/cucumber': + optional: true + '@jest/globals': + optional: true + '@playwright/test': + optional: true + '@testing-library/vue': + optional: true + '@vitest/ui': + optional: true + '@vue/test-utils': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + playwright-core: + optional: true + vitest: + optional: true dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@clack/prompts': 1.0.0-alpha.9 + '@nuxt/kit': 3.20.2 + '@vue/test-utils': 2.4.6 + c12: 3.3.3(magicast@0.5.1) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + estree-walker: 3.0.3 + exsolve: 1.0.8 + fake-indexeddb: 6.2.5 + get-port-please: 3.2.0 + h3: 1.15.4 + h3-next: /h3@2.0.1-rc.29 + happy-dom: 18.0.1 + local-pkg: 1.1.2 + magic-string: 0.30.21 + node-fetch-native: 1.6.7 + node-mock-http: 1.0.4 + nypm: 0.6.4 + ofetch: 1.5.1 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + playwright-core: 1.57.0 + radix3: 1.1.2 + scule: 1.3.0 + std-env: 3.10.0 + tinyexec: 1.0.2 + ufo: 1.6.1 + unplugin: 2.3.11 + vitest: 3.2.4(happy-dom@18.0.1)(tsx@4.21.0) + vitest-environment-nuxt: 1.0.1(@vue/test-utils@2.4.6)(happy-dom@18.0.1)(playwright-core@1.57.0)(typescript@5.9.3)(vitest@3.2.4) + vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - - supports-color - - '@babel/standalone@7.26.6': {} - - '@babel/template@7.25.9': - dependencies: - '@babel/code-frame': 7.26.2 - '@babel/parser': 7.26.5 - '@babel/types': 7.26.5 + - crossws + - magicast + - ocache + - typescript + dev: true - '@babel/traverse@7.26.5': + /@nuxt/vite-builder@4.2.2(nuxt@4.2.2)(tsx@4.21.0)(typescript@5.9.3)(vue@3.5.27): + resolution: {integrity: sha512-Bot8fpJNtHZrM4cS1iSR7bEAZ1mFLAtJvD/JOSQ6kT62F4hSFWfMubMXOwDkLK2tnn3bnAdSqGy1nLNDBCahpQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + nuxt: 4.2.2 + rolldown: ^1.0.0-beta.38 + vue: ^3.3.4 + peerDependenciesMeta: + rolldown: + optional: true dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.5 - '@babel/parser': 7.26.5 - '@babel/template': 7.25.9 - '@babel/types': 7.26.5 - debug: 4.4.0(supports-color@9.4.0) - globals: 11.12.0 + '@nuxt/kit': 4.2.2(magicast@0.5.1) + '@rollup/plugin-replace': 6.0.3(rollup@4.55.2) + '@vitejs/plugin-vue': 6.0.3(vite@7.3.1)(vue@3.5.27) + '@vitejs/plugin-vue-jsx': 5.1.3(vite@7.3.1)(vue@3.5.27) + autoprefixer: 10.4.23(postcss@8.5.6) + consola: 3.4.2 + cssnano: 7.1.2(postcss@8.5.6) + defu: 6.1.4 + esbuild: 0.27.2 + escape-string-regexp: 5.0.0 + exsolve: 1.0.8 + get-port-please: 3.2.0 + h3: 1.15.4 + jiti: 2.6.1 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.0 + mocked-exports: 0.1.1 + nuxt: 4.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@vue/compiler-sfc@3.5.42)(better-sqlite3@12.11.1)(drizzle-orm@0.45.1)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.6) + pathe: 2.0.3 + pkg-types: 2.3.0 + postcss: 8.5.6 + rollup-plugin-visualizer: 6.0.5(rollup@4.55.2) + seroval: 1.4.2 + std-env: 3.10.0 + ufo: 1.6.1 + unenv: 2.0.0-rc.24 + vite: 7.3.1(jiti@2.6.1)(tsx@4.21.0) + vite-node: 5.3.0(jiti@2.6.1)(tsx@4.21.0) + vite-plugin-checker: 0.12.0(typescript@5.9.3)(vite@7.3.1) + vue: 3.5.27(typescript@5.9.3) + vue-bundle-renderer: 2.2.0 transitivePeerDependencies: + - '@biomejs/biome' + - '@types/node' + - eslint + - less + - lightningcss + - magicast + - meow + - optionator + - oxlint + - rollup + - sass + - sass-embedded + - stylelint + - stylus + - sugarss - supports-color + - terser + - tsx + - typescript + - vls + - vti + - vue-tsc + - yaml + dev: false - '@babel/types@7.26.5': - dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + /@one-ini/wasm@0.1.1: + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + dev: true - '@cloudflare/kv-asset-handler@0.3.4': - dependencies: - mime: 3.0.0 + /@oxc-minify/binding-android-arm64@0.102.0: + resolution: {integrity: sha512-pknM+ttJTwRr7ezn1v5K+o2P4RRjLAzKI10bjVDPybwWQ544AZW6jxm7/YDgF2yUbWEV9o7cAQPkIUOmCiW8vg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true - '@csstools/selector-resolve-nested@3.0.0(postcss-selector-parser@7.0.0)': - dependencies: - postcss-selector-parser: 7.0.0 + /@oxc-minify/binding-darwin-arm64@0.102.0: + resolution: {integrity: sha512-BDLiH41ZctNND38+GCEL3ZxFn9j7qMZJLrr6SLWMt8xlG4Sl64xTkZ0zeUy4RdVEatKKZdrRIhFZ2e5wPDQT6Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true - '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.0.0)': - dependencies: - postcss-selector-parser: 7.0.0 + /@oxc-minify/binding-darwin-x64@0.102.0: + resolution: {integrity: sha512-AcB8ZZ711w4hTDhMfMHNjT2d+hekTQ2XmNSUBqJdXB+a2bJbE50UCRq/nxXl44zkjaQTit3lcQbFvhk2wwKcpw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true - '@drizzle-team/brocli@0.10.2': {} + /@oxc-minify/binding-freebsd-x64@0.102.0: + resolution: {integrity: sha512-UlLEN9mR5QaviYVMWZQsN9DgAH3qyV67XUXDEzSrbVMLsqHsVHhFU8ZIeO0fxWTQW/cgpvldvKp9/+RdrggqWw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true - '@esbuild-kit/core-utils@3.3.2': - dependencies: - esbuild: 0.18.20 - source-map-support: 0.5.21 + /@oxc-minify/binding-linux-arm-gnueabihf@0.102.0: + resolution: {integrity: sha512-CWyCwedZrUt47n56/RwHSwKXxVI3p98hB0ntLaBNeH5qjjBujs9uOh4bQ0aAlzUWunT77b3/Y+xcQnmV42HN4A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild-kit/esm-loader@2.6.5': - dependencies: - '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.8.1 + /@oxc-minify/binding-linux-arm64-gnu@0.102.0: + resolution: {integrity: sha512-W/DCw+Ys8rXj4j38ylJ2l6Kvp6SV+eO5SUWA11imz7yCWntNL001KJyGQ9PJNUFHg0jbxe3yqm4M50v6miWzeA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@esbuild/aix-ppc64@0.19.12': + /@oxc-minify/binding-linux-arm64-musl@0.102.0: + resolution: {integrity: sha512-DyH/t/zSZHuX4Nn239oBteeMC4OP7B13EyXWX18Qg8aJoZ+lZo90WPGOvhP04zII33jJ7di+vrtAUhsX64lp+A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/aix-ppc64@0.21.5': + /@oxc-minify/binding-linux-riscv64-gnu@0.102.0: + resolution: {integrity: sha512-CMvzrmOg+Gs44E7TRK/IgrHYp+wwVJxVV8niUrDR2b3SsrCO3NQz5LI+7bM1qDbWnuu5Cl1aiitoMfjRY61dSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/aix-ppc64@0.24.2': + /@oxc-minify/binding-linux-s390x-gnu@0.102.0: + resolution: {integrity: sha512-tZWr6j2s0ddm9MTfWTI3myaAArg9GDy4UgvpF00kMQAjLcGUNhEEQbB9Bd9KtCvDQzaan8HQs0GVWUp+DWrymw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/android-arm64@0.18.20': + /@oxc-minify/binding-linux-x64-gnu@0.102.0: + resolution: {integrity: sha512-0YEKmAIun1bS+Iy5Shx6WOTSj3GuilVuctJjc5/vP8/EMTZ/RI8j0eq0Mu3UFPoT/bMULL3MBXuHuEIXmq7Ddg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/android-arm64@0.19.12': + /@oxc-minify/binding-linux-x64-musl@0.102.0: + resolution: {integrity: sha512-Ew4QDpEsXoV+pG5+bJpheEy3GH436GBe6ASPB0X27Hh9cQ2gb1NVZ7cY7xJj68+fizwS/PtT8GHoG3uxyH17Pg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/android-arm64@0.21.5': + /@oxc-minify/binding-openharmony-arm64@0.102.0: + resolution: {integrity: sha512-wYPXS8IOu/sXiP3CGHJNPzZo4hfPAwJKevcFH2syvU2zyqUxym7hx6smfcK/mgJBiX7VchwArdGRwrEQKcBSaQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: false optional: true - '@esbuild/android-arm64@0.24.2': + /@oxc-minify/binding-wasm32-wasi@0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3): + resolution: {integrity: sha512-52SepCb9e+8cVisGa9S/F14K8PxW0AnbV1j4KEYi8uwfkUIxeDNKRHVHzPoBXNrr0yxW0EHLn/3i8J7a2YCpWw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + requiresBuild: true + dependencies: + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + dev: false optional: true - '@esbuild/android-arm@0.18.20': + /@oxc-minify/binding-win32-arm64-msvc@0.102.0: + resolution: {integrity: sha512-kLs6H1y6sDBKcIimkNwu5th28SLkyvFpHNxdLtCChda0KIGeIXNSiupy5BqEutY+VlWJivKT1OV3Ev3KC5Euzg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/android-arm@0.19.12': + /@oxc-minify/binding-win32-x64-msvc@0.102.0: + resolution: {integrity: sha512-XdyJZdSMN8rbBXH10CrFuU+Q9jIP2+MnxHmNzjK4+bldbTI1UxqwjUMS9bKVC5VCaIEZhh8IE8x4Vf8gmCgrKQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/android-arm@0.21.5': + /@oxc-parser/binding-android-arm64@0.102.0: + resolution: {integrity: sha512-pD2if3w3cxPvYbsBSTbhxAYGDaG6WVwnqYG0mYRQ142D6SJ6BpNs7YVQrqpRA2AJQCmzaPP5TRp/koFLebagfQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false optional: true - '@esbuild/android-arm@0.24.2': + /@oxc-parser/binding-darwin-arm64@0.102.0: + resolution: {integrity: sha512-RzMN6f6MrjjpQC2Dandyod3iOscofYBpHaTecmoRRbC5sJMwsurkqUMHzoJX9F6IM87kn8m/JcClnoOfx5Sesw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/android-x64@0.18.20': + /@oxc-parser/binding-darwin-x64@0.102.0: + resolution: {integrity: sha512-Sr2/3K6GEcejY+HgWp5HaxRPzW5XHe9IfGKVn9OhLt8fzVLnXbK5/GjXj7JjMCNKI3G3ZPZDG2Dgm6CX3MaHCA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/android-x64@0.19.12': + /@oxc-parser/binding-freebsd-x64@0.102.0: + resolution: {integrity: sha512-s9F2N0KJCGEpuBW6ChpFfR06m2Id9ReaHSl8DCca4HvFNt8SJFPp8fq42n2PZy68rtkremQasM0JDrK2BoBeBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false optional: true - '@esbuild/android-x64@0.21.5': + /@oxc-parser/binding-linux-arm-gnueabihf@0.102.0: + resolution: {integrity: sha512-zRCIOWzLbqhfY4g8KIZDyYfO2Fl5ltxdQI1v2GlePj66vFWRl8cf4qcBGzxKfsH3wCZHAhmWd1Ht59mnrfH/UQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/android-x64@0.24.2': + /@oxc-parser/binding-linux-arm64-gnu@0.102.0: + resolution: {integrity: sha512-5n5RbHgfjulRhKB0pW5p0X/NkQeOpI4uI9WHgIZbORUDATGFC8yeyPA6xYGEs+S3MyEAFxl4v544UEIWwqAgsA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/darwin-arm64@0.18.20': + /@oxc-parser/binding-linux-arm64-musl@0.102.0: + resolution: {integrity: sha512-/XWcmglH/VJ4yKAGTLRgPKSSikh3xciNxkwGiURt8dS30b+3pwc4ZZmudMu0tQ3mjSu0o7V9APZLMpbHK8Bp5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/darwin-arm64@0.19.12': + /@oxc-parser/binding-linux-riscv64-gnu@0.102.0: + resolution: {integrity: sha512-2jtIq4nswvy6xdqv1ndWyvVlaRpS0yqomLCvvHdCFx3pFXo5Aoq4RZ39kgvFWrbAtpeYSYeAGFnwgnqjx9ftdw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/darwin-arm64@0.21.5': + /@oxc-parser/binding-linux-s390x-gnu@0.102.0: + resolution: {integrity: sha512-Yp6HX/574mvYryiqj0jNvNTJqo4pdAsNP2LPBTxlDQ1cU3lPd7DUA4MQZadaeLI8+AGB2Pn50mPuPyEwFIxeFg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/darwin-arm64@0.24.2': + /@oxc-parser/binding-linux-x64-gnu@0.102.0: + resolution: {integrity: sha512-R4b0xZpDRhoNB2XZy0kLTSYm0ZmWeKjTii9fcv1Mk3/SIGPrrglwt4U6zEtwK54Dfi4Bve5JnQYduigR/gyDzw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/darwin-x64@0.18.20': + /@oxc-parser/binding-linux-x64-musl@0.102.0: + resolution: {integrity: sha512-xM5A+03Ti3jvWYZoqaBRS3lusvnvIQjA46Fc9aBE/MHgvKgHSkrGEluLWg/33QEwBwxupkH25Pxc1yu97oZCtg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/darwin-x64@0.19.12': + /@oxc-parser/binding-openharmony-arm64@0.102.0: + resolution: {integrity: sha512-AieLlsliblyaTFq7Iw9Nc618tgwV02JT4fQ6VIUd/3ZzbluHIHfPjIXa6Sds+04krw5TvCS8lsegtDYAyzcyhg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: false optional: true - '@esbuild/darwin-x64@0.21.5': + /@oxc-parser/binding-wasm32-wasi@0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3): + resolution: {integrity: sha512-w6HRyArs1PBb9rDsQSHlooe31buUlUI2iY8sBzp62jZ1tmvaJo9EIVTQlRNDkwJmk9DF9uEyIJ82EkZcCZTs9A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + requiresBuild: true + dependencies: + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + dev: false optional: true - '@esbuild/darwin-x64@0.24.2': + /@oxc-parser/binding-win32-arm64-msvc@0.102.0: + resolution: {integrity: sha512-pqP5UuLiiFONQxqGiUFMdsfybaK1EOK4AXiPlvOvacLaatSEPObZGpyCkAcj9aZcvvNwYdeY9cxGM9IT3togaA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/freebsd-arm64@0.18.20': + /@oxc-parser/binding-win32-x64-msvc@0.102.0: + resolution: {integrity: sha512-ntMcL35wuLR1A145rLSmm7m7j8JBZGkROoB9Du0KFIFcfi/w1qk75BdCeiTl3HAKrreAnuhW3QOGs6mJhntowA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/freebsd-arm64@0.19.12': - optional: true + /@oxc-project/types@0.102.0: + resolution: {integrity: sha512-8Skrw405g+/UJPKWJ1twIk3BIH2nXdiVlVNtYT23AXVwpsd79es4K+KYt06Fbnkc5BaTvk/COT2JuCLYdwnCdA==} + dev: false - '@esbuild/freebsd-arm64@0.21.5': + /@oxc-transform/binding-android-arm64@0.102.0: + resolution: {integrity: sha512-JLBT7EiExsGmB6LuBBnm6qTfg0rLSxBU+F7xjqy6UXYpL7zhqelGJL7IAq6Pu5UYFT55zVlXXmgzLOXQfpQjXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false optional: true - '@esbuild/freebsd-arm64@0.24.2': + /@oxc-transform/binding-darwin-arm64@0.102.0: + resolution: {integrity: sha512-xmsBCk/NwE0khy8h6wLEexiS5abCp1ZqJUNHsAovJdGgIW21oGwhiC3VYg1vNLbq+zEXwOHuphVuNEYfBwyNTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/freebsd-x64@0.18.20': + /@oxc-transform/binding-darwin-x64@0.102.0: + resolution: {integrity: sha512-EhBsiq8hSd5BRjlWACB9MxTUiZT2He1s1b3tRP8k3lB8ZTt6sXnDXIWhxRmmM0h//xe6IJ2HuMlbvjXPo/tATg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/freebsd-x64@0.19.12': + /@oxc-transform/binding-freebsd-x64@0.102.0: + resolution: {integrity: sha512-eujvuYf0x7BFgKyFecbXUa2JBEXT4Ss6vmyrrhVdN07jaeJRiobaKAmeNXBkanoWL2KQLELJbSBgs1ykWYTkzg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false optional: true - '@esbuild/freebsd-x64@0.21.5': + /@oxc-transform/binding-linux-arm-gnueabihf@0.102.0: + resolution: {integrity: sha512-2x7Ro356PHBVp1SS/dOsHBSnrfs5MlPYwhdKg35t6qixt2bv1kzEH0tDmn4TNEbdjOirmvOXoCTEWUvh8A4f4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/freebsd-x64@0.24.2': + /@oxc-transform/binding-linux-arm64-gnu@0.102.0: + resolution: {integrity: sha512-Rz/RbPvT4QwcHKIQ/cOt6Lwl4c7AhK2b6whZfyL6oJ7Uz8UiVl1BCwk8thedrB5h+FEykmaPHoriW1hmBev60g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-arm64@0.18.20': + /@oxc-transform/binding-linux-arm64-musl@0.102.0: + resolution: {integrity: sha512-I08iWABrN7zakn3wuNIBWY3hALQGsDLPQbZT1mXws7tyiQqJNGe49uS0/O50QhX3KXj+mbRGsmjVXLXGJE1CVQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-arm64@0.19.12': + /@oxc-transform/binding-linux-riscv64-gnu@0.102.0: + resolution: {integrity: sha512-9+SYW1ARAF6Oj/82ayoqKRe8SI7O1qvzs3Y0kijvhIqAaaZWcFRjI5DToyWRAbnzTtHlMcSllZLXNYdmxBjFxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-arm64@0.21.5': + /@oxc-transform/binding-linux-s390x-gnu@0.102.0: + resolution: {integrity: sha512-HV9nTyQw0TTKYPu+gBhaJBioomiM9O4LcGXi+s5IylCGG6imP0/U13q/9xJnP267QFmiWWqnnSFcv0QAWCyh8A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-arm64@0.24.2': + /@oxc-transform/binding-linux-x64-gnu@0.102.0: + resolution: {integrity: sha512-4wcZ08mmdFk8OjsnglyeYGu5PW3TDh87AmcMOi7tZJ3cpJjfzwDfY27KTEUx6G880OpjAiF36OFSPwdKTKgp2g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-arm@0.18.20': + /@oxc-transform/binding-linux-x64-musl@0.102.0: + resolution: {integrity: sha512-rUHZSZBw0FUnUgOhL/Rs7xJz9KjH2eFur/0df6Lwq/isgJc/ggtBtFoZ+y4Fb8ON87a3Y2gS2LT7SEctX0XdPQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-arm@0.19.12': + /@oxc-transform/binding-openharmony-arm64@0.102.0: + resolution: {integrity: sha512-98y4tccTQ/pA+r2KA/MEJIZ7J8TNTJ4aCT4rX8kWK4pGOko2YsfY3Ru9DVHlLDwmVj7wP8Z4JNxdBrAXRvK+0g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-arm@0.21.5': + /@oxc-transform/binding-wasm32-wasi@0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3): + resolution: {integrity: sha512-M6myOXxHty3L2TJEB1NlJPtQm0c0LmivAxcGv/+DSDadOoB/UnOUbjM8W2Utlh5IYS9ARSOjqHtBiPYLWJ15XA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + requiresBuild: true + dependencies: + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + dev: false optional: true - '@esbuild/linux-arm@0.24.2': + /@oxc-transform/binding-win32-arm64-msvc@0.102.0: + resolution: {integrity: sha512-jzaA1lLiMXiJs4r7E0BHRxTPiwAkpoCfSNRr8npK/SqL4UQE4cSz3WDTX5wJWRrN2U+xqsDGefeYzH4reI8sgw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-ia32@0.18.20': + /@oxc-transform/binding-win32-x64-msvc@0.102.0: + resolution: {integrity: sha512-eYOm6mch+1cP9qlNkMdorfBFY8aEOxY/isqrreLmEWqF/hyXA0SbLKDigTbvh3JFKny/gXlHoCKckqfua4cwtg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-ia32@0.19.12': + /@parcel/watcher-android-arm64@2.5.4: + resolution: {integrity: sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-ia32@0.21.5': + /@parcel/watcher-darwin-arm64@2.5.4: + resolution: {integrity: sha512-kphKy377pZiWpAOyTgQYPE5/XEKVMaj6VUjKT5VkNyUJlr2qZAn8gIc7CPzx+kbhvqHDT9d7EqdOqRXT6vk0zw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-ia32@0.24.2': + /@parcel/watcher-darwin-x64@2.5.4: + resolution: {integrity: sha512-UKaQFhCtNJW1A9YyVz3Ju7ydf6QgrpNQfRZ35wNKUhTQ3dxJ/3MULXN5JN/0Z80V/KUBDGa3RZaKq1EQT2a2gg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-loong64@0.18.20': + /@parcel/watcher-freebsd-x64@2.5.4: + resolution: {integrity: sha512-Dib0Wv3Ow/m2/ttvLdeI2DBXloO7t3Z0oCp4bAb2aqyqOjKPPGrg10pMJJAQ7tt8P4V2rwYwywkDhUia/FgS+Q==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-loong64@0.19.12': + /@parcel/watcher-linux-arm-glibc@2.5.4: + resolution: {integrity: sha512-I5Vb769pdf7Q7Sf4KNy8Pogl/URRCKu9ImMmnVKYayhynuyGYMzuI4UOWnegQNa2sGpsPSbzDsqbHNMyeyPCgw==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-loong64@0.21.5': + /@parcel/watcher-linux-arm-musl@2.5.4: + resolution: {integrity: sha512-kGO8RPvVrcAotV4QcWh8kZuHr9bXi9a3bSZw7kFarYR0+fGliU7hd/zevhjw8fnvIKG3J9EO5G6sXNGCSNMYPQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-loong64@0.24.2': + /@parcel/watcher-linux-arm64-glibc@2.5.4: + resolution: {integrity: sha512-KU75aooXhqGFY2W5/p8DYYHt4hrjHZod8AhcGAmhzPn/etTa+lYCDB2b1sJy3sWJ8ahFVTdy+EbqSBvMx3iFlw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-mips64el@0.18.20': + /@parcel/watcher-linux-arm64-musl@2.5.4: + resolution: {integrity: sha512-Qx8uNiIekVutnzbVdrgSanM+cbpDD3boB1f8vMtnuG5Zau4/bdDbXyKwIn0ToqFhIuob73bcxV9NwRm04/hzHQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-mips64el@0.19.12': + /@parcel/watcher-linux-x64-glibc@2.5.4: + resolution: {integrity: sha512-UYBQvhYmgAv61LNUn24qGQdjtycFBKSK3EXr72DbJqX9aaLbtCOO8+1SkKhD/GNiJ97ExgcHBrukcYhVjrnogA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-mips64el@0.21.5': + /@parcel/watcher-linux-x64-musl@2.5.4: + resolution: {integrity: sha512-YoRWCVgxv8akZrMhdyVi6/TyoeeMkQ0PGGOf2E4omODrvd1wxniXP+DBynKoHryStks7l+fDAMUBRzqNHrVOpg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-mips64el@0.24.2': - optional: true + /@parcel/watcher-wasm@2.5.4: + resolution: {integrity: sha512-9Cn7GFQevsvKjUKIP4lh7MNwak6z9e1DcOK0g9sJc8O8qRAbnet8uBNg0mMRY+MU+z3a6EEl9u9bhSFKhx5kCw==} + engines: {node: '>= 10.0.0'} + dependencies: + is-glob: 4.0.3 + napi-wasm: 1.1.3 + picomatch: 4.0.3 + dev: false + bundledDependencies: + - napi-wasm - '@esbuild/linux-ppc64@0.18.20': + /@parcel/watcher-win32-arm64@2.5.4: + resolution: {integrity: sha512-iby+D/YNXWkiQNYcIhg8P5hSjzXEHaQrk2SLrWOUD7VeC4Ohu0WQvmV+HDJokZVJ2UjJ4AGXW3bx7Lls9Ln4TQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-ppc64@0.19.12': + /@parcel/watcher-win32-ia32@2.5.4: + resolution: {integrity: sha512-vQN+KIReG0a2ZDpVv8cgddlf67J8hk1WfZMMP7sMeZmJRSmEax5xNDNWKdgqSe2brOKTQQAs3aCCUal2qBHAyg==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-ppc64@0.21.5': + /@parcel/watcher-win32-x64@2.5.4: + resolution: {integrity: sha512-3A6efb6BOKwyw7yk9ro2vus2YTt2nvcd56AuzxdMiVOxL9umDyN5PKkKfZ/gZ9row41SjVmTVQNWQhaRRGpOKw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@esbuild/linux-ppc64@0.24.2': + /@parcel/watcher@2.5.4: + resolution: {integrity: sha512-WYa2tUVV5HiArWPB3ydlOc4R2ivq0IDrlqhMi3l7mVsFEXNcTfxYFPIHXHXIh/ca/y/V5N4E1zecyxdIBjYnkQ==} + engines: {node: '>= 10.0.0'} + requiresBuild: true + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.3 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.4 + '@parcel/watcher-darwin-arm64': 2.5.4 + '@parcel/watcher-darwin-x64': 2.5.4 + '@parcel/watcher-freebsd-x64': 2.5.4 + '@parcel/watcher-linux-arm-glibc': 2.5.4 + '@parcel/watcher-linux-arm-musl': 2.5.4 + '@parcel/watcher-linux-arm64-glibc': 2.5.4 + '@parcel/watcher-linux-arm64-musl': 2.5.4 + '@parcel/watcher-linux-x64-glibc': 2.5.4 + '@parcel/watcher-linux-x64-musl': 2.5.4 + '@parcel/watcher-win32-arm64': 2.5.4 + '@parcel/watcher-win32-ia32': 2.5.4 + '@parcel/watcher-win32-x64': 2.5.4 + dev: false + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true optional: true - '@esbuild/linux-riscv64@0.18.20': - optional: true + /@polka/url@1.0.0-next.28: + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + dev: false - '@esbuild/linux-riscv64@0.19.12': - optional: true + /@poppinss/colors@4.1.6: + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + dependencies: + kleur: 4.1.5 + dev: false - '@esbuild/linux-riscv64@0.21.5': - optional: true + /@poppinss/dumper@0.6.5: + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + dev: false - '@esbuild/linux-riscv64@0.24.2': - optional: true + /@poppinss/exception@1.2.3: + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + dev: false - '@esbuild/linux-s390x@0.18.20': - optional: true + /@rolldown/pluginutils@1.0.0-beta.53: + resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + dev: false - '@esbuild/linux-s390x@0.19.12': - optional: true + /@rolldown/pluginutils@1.0.0-beta.60: + resolution: {integrity: sha512-Jz4aqXRPVtqkH1E3jRDzLO5cgN5JwW+WG0wXGE4NiJd25nougv/AHzxmKCzmVQUYnxLmTM0M4wrZp+LlC2FKLg==} + dev: false - '@esbuild/linux-s390x@0.21.5': - optional: true + /@rollup/plugin-alias@6.0.0(rollup@4.55.2): + resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==} + engines: {node: '>=20.19.0'} + peerDependencies: + rollup: '>=4.0.0' + peerDependenciesMeta: + rollup: + optional: true + dependencies: + rollup: 4.55.2 + dev: false - '@esbuild/linux-s390x@0.24.2': - optional: true + /@rollup/plugin-commonjs@29.0.0(rollup@4.55.2): + resolution: {integrity: sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.55.2) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.5.0(picomatch@4.0.3) + is-reference: 1.2.1 + magic-string: 0.30.21 + picomatch: 4.0.3 + rollup: 4.55.2 + dev: false - '@esbuild/linux-x64@0.18.20': - optional: true + /@rollup/plugin-inject@5.0.5(rollup@4.55.2): + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.55.2) + estree-walker: 2.0.2 + magic-string: 0.30.21 + rollup: 4.55.2 + dev: false - '@esbuild/linux-x64@0.19.12': - optional: true + /@rollup/plugin-json@6.1.0(rollup@4.55.2): + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.55.2) + rollup: 4.55.2 + dev: false - '@esbuild/linux-x64@0.21.5': - optional: true + /@rollup/plugin-node-resolve@16.0.3(rollup@4.55.2): + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.55.2) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.11 + rollup: 4.55.2 + dev: false - '@esbuild/linux-x64@0.24.2': - optional: true + /@rollup/plugin-replace@6.0.3(rollup@4.55.2): + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.55.2) + magic-string: 0.30.21 + rollup: 4.55.2 + dev: false - '@esbuild/netbsd-arm64@0.24.2': - optional: true + /@rollup/plugin-terser@0.4.4(rollup@4.55.2): + resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + rollup: 4.55.2 + serialize-javascript: 6.0.2 + smob: 1.5.0 + terser: 5.46.0 + dev: false - '@esbuild/netbsd-x64@0.18.20': - optional: true + /@rollup/pluginutils@5.3.0(rollup@4.55.2): + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + rollup: 4.55.2 + dev: false - '@esbuild/netbsd-x64@0.19.12': + /@rollup/rollup-android-arm-eabi@4.53.2: + resolution: {integrity: sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true optional: true - '@esbuild/netbsd-x64@0.21.5': + /@rollup/rollup-android-arm-eabi@4.55.2: + resolution: {integrity: sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false optional: true - '@esbuild/netbsd-x64@0.24.2': + /@rollup/rollup-android-arm-eabi@4.63.0: + resolution: {integrity: sha512-70TeIFezKKy65LgAVyQh+w94/gjWhvPWaLaGGeMEgVrPkQhuj/M5bAYYZzIFUj9Y69oHyTm5Um/R6gcLh4A8JA==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false optional: true - '@esbuild/openbsd-arm64@0.24.2': + /@rollup/rollup-android-arm64@4.53.2: + resolution: {integrity: sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true optional: true - '@esbuild/openbsd-x64@0.18.20': + /@rollup/rollup-android-arm64@4.55.2: + resolution: {integrity: sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false optional: true - '@esbuild/openbsd-x64@0.19.12': + /@rollup/rollup-android-arm64@4.63.0: + resolution: {integrity: sha512-YC86tYIHK6M1IV+wbzO+Bxk8RCBr6ZyWYgWxUCzaZD8mc8rrFoIJDNzDrkHBYRc/wKdrsIXmm6/F7NzrAO+OrA==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false optional: true - '@esbuild/openbsd-x64@0.21.5': + /@rollup/rollup-darwin-arm64@4.53.2: + resolution: {integrity: sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true optional: true - '@esbuild/openbsd-x64@0.24.2': + /@rollup/rollup-darwin-arm64@4.55.2: + resolution: {integrity: sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/sunos-x64@0.18.20': + /@rollup/rollup-darwin-arm64@4.63.0: + resolution: {integrity: sha512-oI+ECtUcli0y0fi4xpW82GdPIXdTkI8G8DSjG2LRuw09fPAGykaWYH/hXxiKuTxiAjiPSTIIuYUqof5Z2hShWw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/sunos-x64@0.19.12': + /@rollup/rollup-darwin-x64@4.53.2: + resolution: {integrity: sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true optional: true - '@esbuild/sunos-x64@0.21.5': + /@rollup/rollup-darwin-x64@4.55.2: + resolution: {integrity: sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/sunos-x64@0.24.2': + /@rollup/rollup-darwin-x64@4.63.0: + resolution: {integrity: sha512-NwV+1s7TiKrMe4owHyKB/dTLD7ZJD0YEBEhIz+hvav1Cu1GReJjF+rsdNwjzENQeIAbE/CoNiaAc5Vz2h5DPAA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@esbuild/win32-arm64@0.18.20': + /@rollup/rollup-freebsd-arm64@4.53.2: + resolution: {integrity: sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true optional: true - '@esbuild/win32-arm64@0.19.12': + /@rollup/rollup-freebsd-arm64@4.55.2: + resolution: {integrity: sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false optional: true - '@esbuild/win32-arm64@0.21.5': + /@rollup/rollup-freebsd-arm64@4.63.0: + resolution: {integrity: sha512-tWtHBTu5gOPK4u4Urtk4qAHW3zZ9rQAmbssO8gp7ELvGTGI3aCiq6NqyTQ0PCIg7KbHJF2UkGDDs77YZGxfjCA==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false optional: true - '@esbuild/win32-arm64@0.24.2': + /@rollup/rollup-freebsd-x64@4.53.2: + resolution: {integrity: sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true optional: true - '@esbuild/win32-ia32@0.18.20': + /@rollup/rollup-freebsd-x64@4.55.2: + resolution: {integrity: sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false optional: true - '@esbuild/win32-ia32@0.19.12': + /@rollup/rollup-freebsd-x64@4.63.0: + resolution: {integrity: sha512-2qPoJiwTvtHQ27NnYvTnsgk8laXWYuVmNESG8WFZBcEPKLfZ3I27qBJarjVRQtwGeYyRfq5ZowHXih9lm2BItw==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false optional: true - '@esbuild/win32-ia32@0.21.5': + /@rollup/rollup-linux-arm-gnueabihf@4.53.2: + resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true optional: true - '@esbuild/win32-ia32@0.24.2': + /@rollup/rollup-linux-arm-gnueabihf@4.55.2: + resolution: {integrity: sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/win32-x64@0.18.20': + /@rollup/rollup-linux-arm-gnueabihf@4.63.0: + resolution: {integrity: sha512-FQwsTRvLNuHoTdICABJQfbPUSEueISGmnpT06tXTMpfprf5NiKLSXKA0A+w45wJnCmZAnzgqBwbt6ARFuyOi5w==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/win32-x64@0.19.12': + /@rollup/rollup-linux-arm-musleabihf@4.53.2: + resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true optional: true - '@esbuild/win32-x64@0.21.5': + /@rollup/rollup-linux-arm-musleabihf@4.55.2: + resolution: {integrity: sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@esbuild/win32-x64@0.24.2': + /@rollup/rollup-linux-arm-musleabihf@4.63.0: + resolution: {integrity: sha512-BBVTXziw8mY1a4ZbWME9tZyfzqXCDPqaC7Z3heQ29p5dkvXzwL0NwelO8zLa8c3RBKvl3YTuSnBgsBhYBtwjIw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@ioredis/commands@1.2.0': {} - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@isaacs/fs-minipass@4.0.1': - dependencies: - minipass: 7.1.2 - - '@jridgewell/gen-mapping@0.3.8': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/set-array@1.2.1': {} - - '@jridgewell/source-map@0.3.6': - dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/sourcemap-codec@1.5.0': {} - - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 - - '@koa/router@12.0.2': - dependencies: - debug: 4.4.0(supports-color@9.4.0) - http-errors: 2.0.0 - koa-compose: 4.1.0 - methods: 1.1.2 - path-to-regexp: 6.3.0 - transitivePeerDependencies: - - supports-color - - '@kwsites/file-exists@1.1.1': - dependencies: - debug: 4.4.0(supports-color@9.4.0) - transitivePeerDependencies: - - supports-color - - '@kwsites/promise-deferred@1.1.1': {} - - '@mapbox/node-pre-gyp@2.0.0-rc.0': - dependencies: - consola: 3.4.0 - detect-libc: 2.0.3 - https-proxy-agent: 7.0.6(supports-color@9.4.0) - node-fetch: 2.7.0 - nopt: 8.0.0 - semver: 7.6.3 - tar: 7.4.3 - transitivePeerDependencies: - - encoding - - supports-color + /@rollup/rollup-linux-arm64-gnu@4.53.2: + resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true - '@netlify/functions@2.8.2': - dependencies: - '@netlify/serverless-functions-api': 1.26.1 + /@rollup/rollup-linux-arm64-gnu@4.55.2: + resolution: {integrity: sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@netlify/node-cookies@0.1.0': {} + /@rollup/rollup-linux-arm64-gnu@4.63.0: + resolution: {integrity: sha512-w2Iyy9+RqKwx3d9qWMKsJg0FfRBsY0/pXNv0mCQ3ueRvJI6+QAScfD4nrMlzFLs2HNVW6Ew+mtZfDl9b7Ew5/Q==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@netlify/serverless-functions-api@1.26.1': - dependencies: - '@netlify/node-cookies': 0.1.0 - urlpattern-polyfill: 8.0.2 + /@rollup/rollup-linux-arm64-musl@4.53.2: + resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 + /@rollup/rollup-linux-arm64-musl@4.55.2: + resolution: {integrity: sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nodelib/fs.stat@2.0.5': {} + /@rollup/rollup-linux-arm64-musl@4.63.0: + resolution: {integrity: sha512-YK++KtrFRHYE0P6/RtYEAy9t8F37znP+K03RrIuLPYOL6SVlObRumf/0OE4V/h63xL9DwkWbNssZfmA9hawuDA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.18.0 + /@rollup/rollup-linux-loong64-gnu@4.53.2: + resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true - '@nuxt/cli@3.20.0(magicast@0.3.5)': - dependencies: - c12: 2.0.1(magicast@0.3.5) - chokidar: 4.0.3 - citty: 0.1.6 - clipboardy: 4.0.0 - consola: 3.4.0 - defu: 6.1.4 - fuse.js: 7.0.0 - giget: 1.2.3 - h3: 1.13.1 - httpxy: 0.1.6 - jiti: 2.4.2 - listhen: 1.9.0 - nypm: 0.4.1 - ofetch: 1.4.1 - ohash: 1.1.4 - pathe: 2.0.2 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 - scule: 1.3.0 - semver: 7.6.3 - std-env: 3.8.0 - tinyexec: 0.3.2 - ufo: 1.5.4 - transitivePeerDependencies: - - magicast + /@rollup/rollup-linux-loong64-gnu@4.55.2: + resolution: {integrity: sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nuxt/devalue@2.0.2': {} + /@rollup/rollup-linux-loong64-gnu@4.63.0: + resolution: {integrity: sha512-aBfOG6fP7YkkPmTqPwufRJeFyz7WPpECv9XNbnsk9+vg7rxdih0lbtEel7jcRng4LZrrmU3FfitCFyEj4BWDWg==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))': - dependencies: - '@nuxt/kit': 3.15.2(magicast@0.3.5)(rollup@4.30.1) - '@nuxt/schema': 3.15.2 - execa: 7.2.0 - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - transitivePeerDependencies: - - magicast - - rollup - - supports-color + /@rollup/rollup-linux-loong64-musl@4.55.2: + resolution: {integrity: sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nuxt/devtools-wizard@1.7.0': - dependencies: - consola: 3.4.0 - diff: 7.0.0 - execa: 7.2.0 - global-directory: 4.0.1 - magicast: 0.3.5 - pathe: 1.1.2 - pkg-types: 1.3.1 - prompts: 2.4.2 - rc9: 2.1.2 - semver: 7.6.3 - - '@nuxt/devtools@1.7.0(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': - dependencies: - '@antfu/utils': 0.7.10 - '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) - '@nuxt/devtools-wizard': 1.7.0 - '@nuxt/kit': 3.15.2(magicast@0.3.5)(rollup@4.30.1) - '@vue/devtools-core': 7.6.8(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) - '@vue/devtools-kit': 7.6.8 - birpc: 0.2.19 - consola: 3.4.0 - cronstrue: 2.53.0 - destr: 2.0.3 - error-stack-parser-es: 0.1.5 - execa: 7.2.0 - fast-npm-meta: 0.2.2 - flatted: 3.3.2 - get-port-please: 3.1.2 - hookable: 5.5.3 - image-meta: 0.2.1 - is-installed-globally: 1.0.0 - launch-editor: 2.9.1 - local-pkg: 0.5.1 - magicast: 0.3.5 - nypm: 0.4.1 - ohash: 1.1.4 - pathe: 1.1.2 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 - rc9: 2.1.2 - scule: 1.3.0 - semver: 7.6.3 - simple-git: 3.27.0 - sirv: 3.0.0 - tinyglobby: 0.2.10 - unimport: 3.14.6(rollup@4.30.1) - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.2(magicast@0.3.5)(rollup@4.30.1))(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) - vite-plugin-vue-inspector: 5.3.1(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) - which: 3.0.1 - ws: 8.18.0 - transitivePeerDependencies: - - bufferutil - - rollup - - supports-color - - utf-8-validate - - vue + /@rollup/rollup-linux-loong64-musl@4.63.0: + resolution: {integrity: sha512-LGaHEOeHNAag9VuS1Crs5DFg4RrU9MPi2nVnNJk9DTePx/B6RRYKVmrIXt2h7YOJlwjaFJ6lwtFDliZxScTLrQ==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nuxt/kit@3.15.2(magicast@0.3.5)(rollup@4.30.1)': - dependencies: - '@nuxt/schema': 3.15.2 - c12: 2.0.1(magicast@0.3.5) - consola: 3.4.0 - defu: 6.1.4 - destr: 2.0.3 - globby: 14.0.2 - ignore: 7.0.3 - jiti: 2.4.2 - klona: 2.0.6 - knitwork: 1.2.0 - mlly: 1.7.4 - ohash: 1.1.4 - pathe: 2.0.2 - pkg-types: 1.3.1 - scule: 1.3.0 - semver: 7.6.3 - std-env: 3.8.0 - ufo: 1.5.4 - unctx: 2.4.1 - unimport: 3.14.6(rollup@4.30.1) - untyped: 1.5.2 - transitivePeerDependencies: - - magicast - - rollup - - supports-color + /@rollup/rollup-linux-ppc64-gnu@4.53.2: + resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true - '@nuxt/schema@3.15.2': - dependencies: - consola: 3.4.0 - defu: 6.1.4 - pathe: 2.0.2 - std-env: 3.8.0 + /@rollup/rollup-linux-ppc64-gnu@4.55.2: + resolution: {integrity: sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nuxt/telemetry@2.6.4(magicast@0.3.5)(rollup@4.30.1)': - dependencies: - '@nuxt/kit': 3.15.2(magicast@0.3.5)(rollup@4.30.1) - citty: 0.1.6 - consola: 3.4.0 - destr: 2.0.3 - dotenv: 16.4.7 - git-url-parse: 16.0.0 - is-docker: 3.0.0 - ofetch: 1.4.1 - package-manager-detector: 0.2.8 - parse-git-config: 3.0.0 - pathe: 2.0.2 - rc9: 2.1.2 - std-env: 3.8.0 - transitivePeerDependencies: - - magicast - - rollup - - supports-color + /@rollup/rollup-linux-ppc64-gnu@4.63.0: + resolution: {integrity: sha512-jClvk+J0FC3b7Udvegiw5/4hErbHtmsNsQgENnKXDWtNCJXsJYZH5WURvu7imDOO38xYml24eeh5x3A04ppwCw==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nuxt/vite-builder@3.15.2(@types/node@22.10.7)(magicast@0.3.5)(rollup@4.30.1)(terser@5.37.0)(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0)': - dependencies: - '@nuxt/kit': 3.15.2(magicast@0.3.5)(rollup@4.30.1) - '@rollup/plugin-replace': 6.0.2(rollup@4.30.1) - '@vitejs/plugin-vue': 5.2.1(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) - '@vitejs/plugin-vue-jsx': 4.1.1(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) - autoprefixer: 10.4.20(postcss@8.5.1) - consola: 3.4.0 - cssnano: 7.0.6(postcss@8.5.1) - defu: 6.1.4 - esbuild: 0.24.2 - escape-string-regexp: 5.0.0 - externality: 1.0.2 - get-port-please: 3.1.2 - h3: 1.13.1 - jiti: 2.4.2 - knitwork: 1.2.0 - magic-string: 0.30.17 - mlly: 1.7.4 - ohash: 1.1.4 - pathe: 2.0.2 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 - postcss: 8.5.1 - rollup-plugin-visualizer: 5.14.0(rollup@4.30.1) - std-env: 3.8.0 - ufo: 1.5.4 - unenv: 1.10.0 - unplugin: 2.1.2 - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - vite-node: 2.1.8(@types/node@22.10.7)(terser@5.37.0) - vite-plugin-checker: 0.8.0(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) - vue: 3.5.13(typescript@5.7.3) - vue-bundle-renderer: 2.1.1 - transitivePeerDependencies: - - '@biomejs/biome' - - '@types/node' - - eslint - - less - - lightningcss - - magicast - - meow - - optionator - - rolldown - - rollup - - sass - - sass-embedded - - stylelint - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - vls - - vti - - vue-tsc - - yaml + /@rollup/rollup-linux-ppc64-musl@4.55.2: + resolution: {integrity: sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@nuxtjs/tailwindcss@6.13.1(magicast@0.3.5)(rollup@4.30.1)': - dependencies: - '@nuxt/kit': 3.15.2(magicast@0.3.5)(rollup@4.30.1) - autoprefixer: 10.4.20(postcss@8.5.1) - c12: 2.0.1(magicast@0.3.5) - consola: 3.4.0 - defu: 6.1.4 - h3: 1.13.1 - klona: 2.0.6 - pathe: 2.0.2 - postcss: 8.5.1 - postcss-nesting: 13.0.1(postcss@8.5.1) - tailwind-config-viewer: 2.0.4(tailwindcss@3.4.17) - tailwindcss: 3.4.17 - ufo: 1.5.4 - unctx: 2.4.1 - transitivePeerDependencies: - - magicast - - rollup - - supports-color - - ts-node + /@rollup/rollup-linux-ppc64-musl@4.63.0: + resolution: {integrity: sha512-0OJlaGK+8+B777Ql5okIpD7ua5Ro9+VB9Ve0OKa28OQJZ1RbuUBVNHK/e3pr4BROqsyPl1JrPO1ZxJseCNffcA==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@parcel/watcher-android-arm64@2.5.0': + /@rollup/rollup-linux-riscv64-gnu@4.53.2: + resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true optional: true - '@parcel/watcher-darwin-arm64@2.5.0': + /@rollup/rollup-linux-riscv64-gnu@4.55.2: + resolution: {integrity: sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@parcel/watcher-darwin-x64@2.5.0': + /@rollup/rollup-linux-riscv64-gnu@4.63.0: + resolution: {integrity: sha512-Ygsx+HoNH7afwi1bTIXbnTvVnsO+zurPLSYxybV1hHFVU72OWOCl6v05ql/z0hkpAPx+DK7Kn9Bi7MayCcjLTA==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@parcel/watcher-freebsd-x64@2.5.0': + /@rollup/rollup-linux-riscv64-musl@4.53.2: + resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true optional: true - '@parcel/watcher-linux-arm-glibc@2.5.0': + /@rollup/rollup-linux-riscv64-musl@4.55.2: + resolution: {integrity: sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@parcel/watcher-linux-arm-musl@2.5.0': + /@rollup/rollup-linux-riscv64-musl@4.63.0: + resolution: {integrity: sha512-pDQxtMGb+OvG3fLwR2OkZlSd47hW+kWg4BYMG/++sR6RqorQccwPTDsxda5hPwiIeIErAnCF9ma3SAU06bdQtQ==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@parcel/watcher-linux-arm64-glibc@2.5.0': + /@rollup/rollup-linux-s390x-gnu@4.53.2: + resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true optional: true - '@parcel/watcher-linux-arm64-musl@2.5.0': + /@rollup/rollup-linux-s390x-gnu@4.55.2: + resolution: {integrity: sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false optional: true - '@parcel/watcher-linux-x64-glibc@2.5.0': + /@rollup/rollup-linux-s390x-gnu@4.63.0: + resolution: {integrity: sha512-0BnUG9mS8I4SSHr3XsxVhuCMEiu+rX61xxZF5vujso4LaiAGFZFxvDjg6Xn6tLPNTUAfuCvQYas4LMQMVsKRSQ==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false optional: true - '@parcel/watcher-linux-x64-musl@2.5.0': + /@rollup/rollup-linux-x64-gnu@4.53.2: + resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true optional: true - '@parcel/watcher-wasm@2.5.0': - dependencies: - is-glob: 4.0.3 - micromatch: 4.0.8 + /@rollup/rollup-linux-x64-gnu@4.55.2: + resolution: {integrity: sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@parcel/watcher-win32-arm64@2.5.0': + /@rollup/rollup-linux-x64-gnu@4.63.0: + resolution: {integrity: sha512-Adu/VttB1dpPNW+FEacrZ+xVm9tFty84+RrFzsqlFaPxoJB+9XXyDGtp5dCOoBwGBIEVH0To7lExFXEx0BIF4A==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@parcel/watcher-win32-ia32@2.5.0': + /@rollup/rollup-linux-x64-musl@4.53.2: + resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true optional: true - '@parcel/watcher-win32-x64@2.5.0': + /@rollup/rollup-linux-x64-musl@4.55.2: + resolution: {integrity: sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@parcel/watcher@2.5.0': - dependencies: - detect-libc: 1.0.3 - is-glob: 4.0.3 - micromatch: 4.0.8 - node-addon-api: 7.1.1 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.0 - '@parcel/watcher-darwin-arm64': 2.5.0 - '@parcel/watcher-darwin-x64': 2.5.0 - '@parcel/watcher-freebsd-x64': 2.5.0 - '@parcel/watcher-linux-arm-glibc': 2.5.0 - '@parcel/watcher-linux-arm-musl': 2.5.0 - '@parcel/watcher-linux-arm64-glibc': 2.5.0 - '@parcel/watcher-linux-arm64-musl': 2.5.0 - '@parcel/watcher-linux-x64-glibc': 2.5.0 - '@parcel/watcher-linux-x64-musl': 2.5.0 - '@parcel/watcher-win32-arm64': 2.5.0 - '@parcel/watcher-win32-ia32': 2.5.0 - '@parcel/watcher-win32-x64': 2.5.0 + /@rollup/rollup-linux-x64-musl@4.63.0: + resolution: {integrity: sha512-NQ3bDvjUbFKmP23671xUlXtKmqVsUBd6M4PQCvbmNtOy06hnQIdKHy8oG/6S3R/S6He1JgPk6A5VT+prAJMYEw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true - '@pkgjs/parseargs@0.11.0': + /@rollup/rollup-openbsd-x64@4.55.2: + resolution: {integrity: sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false optional: true - '@polka/url@1.0.0-next.28': {} + /@rollup/rollup-openbsd-x64@4.63.0: + resolution: {integrity: sha512-u2eDAl4+0aFvA13GxlGBtTI3SS3sdgwgtV0HyjZ0QaQVCgNE+jqNGey+GtxWiq+wxr/UycAx/OnfJzApCFamvA==} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true - '@popperjs/core@2.11.8': {} + /@rollup/rollup-openharmony-arm64@4.53.2: + resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: true + optional: true - '@redocly/ajv@8.11.2': - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js-replace: 1.0.1 + /@rollup/rollup-openharmony-arm64@4.55.2: + resolution: {integrity: sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: false + optional: true - '@redocly/config@0.20.1': {} + /@rollup/rollup-openharmony-arm64@4.63.0: + resolution: {integrity: sha512-XvRb5vfW3wAZQ+ZUG21AnHHDKtNcw99eigzEhjr//NZ3u7SoBaPP0seSc7FgP7p1epAEdAoZckMW9WY/+4w70w==} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: false + optional: true - '@redocly/openapi-core@1.27.2(supports-color@9.4.0)': - dependencies: - '@redocly/ajv': 8.11.2 - '@redocly/config': 0.20.1 - colorette: 1.4.0 - https-proxy-agent: 7.0.6(supports-color@9.4.0) - js-levenshtein: 1.1.6 - js-yaml: 4.1.0 - minimatch: 5.1.6 - node-fetch: 2.7.0 - pluralize: 8.0.0 - yaml-ast-parser: 0.0.43 - transitivePeerDependencies: - - encoding - - supports-color + /@rollup/rollup-win32-arm64-msvc@4.53.2: + resolution: {integrity: sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/plugin-alias@5.1.1(rollup@4.30.1)': - optionalDependencies: - rollup: 4.30.1 + /@rollup/rollup-win32-arm64-msvc@4.55.2: + resolution: {integrity: sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true - '@rollup/plugin-commonjs@28.0.2(rollup@4.30.1)': - dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - commondir: 1.0.1 - estree-walker: 2.0.2 - fdir: 6.4.3(picomatch@4.0.2) - is-reference: 1.2.1 - magic-string: 0.30.17 - picomatch: 4.0.2 - optionalDependencies: - rollup: 4.30.1 + /@rollup/rollup-win32-arm64-msvc@4.63.0: + resolution: {integrity: sha512-iZPmniy4kNBf5yo2RezbkYNNK5HPbXE9+g+twnbqSng7dtLEJy1SKoxiE/ni4FDacjyuZpEeb9U054N4EoKHYw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true - '@rollup/plugin-inject@5.0.5(rollup@4.30.1)': - dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - estree-walker: 2.0.2 - magic-string: 0.30.17 - optionalDependencies: - rollup: 4.30.1 + /@rollup/rollup-win32-ia32-msvc@4.53.2: + resolution: {integrity: sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/plugin-json@6.1.0(rollup@4.30.1)': - dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - optionalDependencies: - rollup: 4.30.1 + /@rollup/rollup-win32-ia32-msvc@4.55.2: + resolution: {integrity: sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true - '@rollup/plugin-node-resolve@15.3.1(rollup@4.30.1)': - dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - '@types/resolve': 1.20.2 - deepmerge: 4.3.1 - is-module: 1.0.0 - resolve: 1.22.10 - optionalDependencies: - rollup: 4.30.1 + /@rollup/rollup-win32-ia32-msvc@4.63.0: + resolution: {integrity: sha512-mFBBd+LF37fnE8JnYUOH+imj0aPFPK30vpar4ehJkgnLj9sZn8ZxiRENmLtgIwxK7TC8klF6N57fxdNBwQoqOA==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true - '@rollup/plugin-replace@6.0.2(rollup@4.30.1)': - dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - magic-string: 0.30.17 - optionalDependencies: - rollup: 4.30.1 + /@rollup/rollup-win32-x64-gnu@4.53.2: + resolution: {integrity: sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/plugin-terser@0.4.4(rollup@4.30.1)': - dependencies: - serialize-javascript: 6.0.2 - smob: 1.5.0 - terser: 5.37.0 - optionalDependencies: - rollup: 4.30.1 + /@rollup/rollup-win32-x64-gnu@4.55.2: + resolution: {integrity: sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true - '@rollup/pluginutils@5.1.4(rollup@4.30.1)': - dependencies: - '@types/estree': 1.0.6 - estree-walker: 2.0.2 - picomatch: 4.0.2 - optionalDependencies: - rollup: 4.30.1 + /@rollup/rollup-win32-x64-gnu@4.63.0: + resolution: {integrity: sha512-ujeqEY3B+zbGn3Z4Q03cUBG/LGWnBJncVT36WER31LcOsQk9+1dmINKKtvmmfChUvRbK1G0R8OhMWFgHgaZtAw==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true - '@rollup/rollup-android-arm-eabi@4.30.1': + /@rollup/rollup-win32-x64-msvc@4.53.2: + resolution: {integrity: sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true optional: true - '@rollup/rollup-android-arm64@4.30.1': + /@rollup/rollup-win32-x64-msvc@4.55.2: + resolution: {integrity: sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-darwin-arm64@4.30.1': + /@rollup/rollup-win32-x64-msvc@4.63.0: + resolution: {integrity: sha512-hncn90N4sOky0L2LKE5oESKLbxCPeVo4eLA2LSMoDzM+879ml4WSr+Rr4DWknNIVVvS1Hirkc9hx02W6YxS8rQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-darwin-x64@4.30.1': - optional: true + /@sindresorhus/is@7.2.0: + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + dev: false - '@rollup/rollup-freebsd-arm64@4.30.1': - optional: true + /@sindresorhus/merge-streams@4.0.0: + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + dev: false - '@rollup/rollup-freebsd-x64@4.30.1': - optional: true + /@speed-highlight/core@1.2.14: + resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==} + dev: false - '@rollup/rollup-linux-arm-gnueabihf@4.30.1': - optional: true + /@swc/helpers@0.5.15: + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + dependencies: + tslib: 2.8.1 + dev: false - '@rollup/rollup-linux-arm-musleabihf@4.30.1': - optional: true + /@tailwindcss/node@4.1.17: + resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.17 + dev: false - '@rollup/rollup-linux-arm64-gnu@4.30.1': + /@tailwindcss/oxide-android-arm64@4.1.17: + resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-linux-arm64-musl@4.30.1': + /@tailwindcss/oxide-darwin-arm64@4.1.17: + resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.30.1': + /@tailwindcss/oxide-darwin-x64@4.1.17: + resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.30.1': + /@tailwindcss/oxide-freebsd-x64@4.1.17: + resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-linux-riscv64-gnu@4.30.1': + /@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17: + resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-linux-s390x-gnu@4.30.1': + /@tailwindcss/oxide-linux-arm64-gnu@4.1.17: + resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-linux-x64-gnu@4.30.1': + /@tailwindcss/oxide-linux-arm64-musl@4.1.17: + resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-linux-x64-musl@4.30.1': + /@tailwindcss/oxide-linux-x64-gnu@4.1.17: + resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-win32-arm64-msvc@4.30.1': + /@tailwindcss/oxide-linux-x64-musl@4.1.17: + resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-win32-ia32-msvc@4.30.1': + /@tailwindcss/oxide-wasm32-wasi@4.1.17: + resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + requiresBuild: true + dev: false + optional: true + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + /@tailwindcss/oxide-win32-arm64-msvc@4.1.17: + resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@rollup/rollup-win32-x64-msvc@4.30.1': + /@tailwindcss/oxide-win32-x64-msvc@4.1.17: + resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@sindresorhus/merge-streams@2.3.0': {} + /@tailwindcss/oxide@4.1.17: + resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} + engines: {node: '>= 10'} + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-x64': 4.1.17 + '@tailwindcss/oxide-freebsd-x64': 4.1.17 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-x64-musl': 4.1.17 + '@tailwindcss/oxide-wasm32-wasi': 4.1.17 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 + dev: false + + /@tailwindcss/vite@4.1.17(vite@7.3.6): + resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + dependencies: + '@tailwindcss/node': 4.1.17 + '@tailwindcss/oxide': 4.1.17 + tailwindcss: 4.1.17 + vite: 7.3.6(tsx@4.21.0) + dev: false + + /@tanstack/table-core@8.21.3: + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + dev: false - '@trysound/sax@0.2.0': {} + /@tanstack/virtual-core@3.13.6: + resolution: {integrity: sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg==} + dev: false - '@types/better-sqlite3@7.6.12': + /@tanstack/vue-table@8.21.3(vue@3.5.27): + resolution: {integrity: sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw==} + engines: {node: '>=12'} + peerDependencies: + vue: '>=3.2' dependencies: - '@types/node': 22.10.7 + '@tanstack/table-core': 8.21.3 + vue: 3.5.27(typescript@5.9.3) + dev: false - '@types/estree@1.0.6': {} + /@tanstack/vue-virtual@3.13.6(vue@3.5.27): + resolution: {integrity: sha512-GYdZ3SJBQPzgxhuCE2fvpiH46qzHiVx5XzBSdtESgiqh4poj8UgckjGWYEhxaBbcVt1oLzh1m3Ql4TyH32TOzQ==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + dependencies: + '@tanstack/virtual-core': 3.13.6 + vue: 3.5.27(typescript@5.9.3) + dev: false - '@types/http-proxy@1.17.15': + /@tybys/wasm-util@0.10.3: + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + requiresBuild: true dependencies: - '@types/node': 22.10.7 + tslib: 2.8.1 + dev: false + optional: true - '@types/node@22.10.7': + /@types/better-sqlite3@7.6.13: + resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} dependencies: - undici-types: 6.20.0 + '@types/node': 22.14.0 - '@types/parse-path@7.0.3': {} + /@types/chai@5.2.2: + resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} + dependencies: + '@types/deep-eql': 4.0.2 + dev: true - '@types/resolve@1.20.2': {} + /@types/deep-eql@4.0.2: + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + dev: true - '@types/web-bluetooth@0.0.20': {} + /@types/estree@1.0.8: + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@unhead/dom@1.11.18': - dependencies: - '@unhead/schema': 1.11.18 - '@unhead/shared': 1.11.18 + /@types/estree@1.0.9: + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + dev: false - '@unhead/schema@1.11.18': + /@types/node@20.19.1: + resolution: {integrity: sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==} dependencies: - hookable: 5.5.3 - zhead: 2.2.4 + undici-types: 6.21.0 + dev: true - '@unhead/shared@1.11.18': + /@types/node@22.14.0: + resolution: {integrity: sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==} dependencies: - '@unhead/schema': 1.11.18 - packrup: 0.1.2 + undici-types: 6.21.0 - '@unhead/ssr@1.11.18': + /@types/parse-path@7.0.3: + resolution: {integrity: sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==} + dev: false + + /@types/pg@8.23.1: + resolution: {integrity: sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A==} dependencies: - '@unhead/schema': 1.11.18 - '@unhead/shared': 1.11.18 + '@types/node': 22.14.0 + pg-protocol: 1.13.0 + pg-types: 2.2.0 + + /@types/resolve@1.20.2: + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + dev: false - '@unhead/vue@1.11.18(vue@3.5.13(typescript@5.7.3))': + /@types/web-bluetooth@0.0.21: + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + dev: false + + /@types/whatwg-mimetype@3.0.2: + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + dev: true + + /@unhead/vue@2.0.19(vue@3.5.27): + resolution: {integrity: sha512-7BYjHfOaoZ9+ARJkT10Q2TjnTUqDXmMpfakIAsD/hXiuff1oqWg1xeXT5+MomhNcC15HbiABpbbBmITLSHxdKg==} + peerDependencies: + vue: '>=3.5.18' dependencies: - '@unhead/schema': 1.11.18 - '@unhead/shared': 1.11.18 hookable: 5.5.3 - unhead: 1.11.18 - vue: 3.5.13(typescript@5.7.3) + unhead: 2.0.19 + vue: 3.5.27(typescript@5.9.3) + dev: false - '@vercel/nft@0.27.10(rollup@4.30.1)': + /@vercel/nft@1.2.0(rollup@4.55.2): + resolution: {integrity: sha512-68326CAWJmd6P1cUgUmufor5d4ocPbpLxiy9TKG6U/a4aWEx9aC+NIzaDI6GmBZVpt3+MkO3OwnQ2YcgJg12Qw==} + engines: {node: '>=20'} + hasBin: true dependencies: - '@mapbox/node-pre-gyp': 2.0.0-rc.0 - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - acorn: 8.14.0 - acorn-import-attributes: 1.9.5(acorn@8.14.0) + '@mapbox/node-pre-gyp': 2.0.3 + '@rollup/pluginutils': 5.3.0(rollup@4.55.2) + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 - glob: 7.2.3 + glob: 13.0.0 graceful-fs: 4.2.11 node-gyp-build: 4.8.4 - picomatch: 4.0.2 + picomatch: 4.0.3 resolve-from: 5.0.0 transitivePeerDependencies: - encoding - rollup - supports-color + dev: false - '@vitejs/plugin-vue-jsx@4.1.1(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': + /@vitejs/plugin-vue-jsx@5.1.3(vite@7.3.1)(vue@3.5.27): + resolution: {integrity: sha512-I6Zr8cYVr5WHMW5gNOP09DNqW9rgO8RX73Wa6Czgq/0ndpTfJM4vfDChfOT1+3KtdrNqilNBtNlFwVeB02ZzGw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vue: ^3.0.0 dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-transform-typescript': 7.26.5(@babel/core@7.26.0) - '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.0) - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - vue: 3.5.13(typescript@5.7.3) + '@babel/core': 7.28.6 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.28.6) + '@rolldown/pluginutils': 1.0.0-beta.60 + '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.28.6) + vite: 7.3.1(jiti@2.6.1)(tsx@4.21.0) + vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - supports-color + dev: false - '@vitejs/plugin-vue@5.2.1(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': + /@vitejs/plugin-vue@6.0.3(vite@7.3.1)(vue@3.5.27): + resolution: {integrity: sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vue: ^3.2.25 dependencies: - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - vue: 3.5.13(typescript@5.7.3) + '@rolldown/pluginutils': 1.0.0-beta.53 + vite: 7.3.1(jiti@2.6.1)(tsx@4.21.0) + vue: 3.5.27(typescript@5.9.3) + dev: false - '@vue-macros/common@1.16.0(vue@3.5.13(typescript@5.7.3))': + /@vitest/expect@3.2.4: + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} dependencies: - '@vue/compiler-sfc': 3.5.13 - ast-kit: 1.4.0 - local-pkg: 1.0.0 - magic-string-ast: 0.7.0 - pathe: 2.0.2 - picomatch: 4.0.2 - optionalDependencies: - vue: 3.5.13(typescript@5.7.3) - - '@vue/babel-helper-vue-transform-on@1.2.5': {} - - '@vue/babel-plugin-jsx@1.2.5(@babel/core@7.26.0)': - dependencies: - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/template': 7.25.9 - '@babel/traverse': 7.26.5 - '@babel/types': 7.26.5 - '@vue/babel-helper-vue-transform-on': 1.2.5 - '@vue/babel-plugin-resolve-type': 1.2.5(@babel/core@7.26.0) - html-tags: 3.3.1 - svg-tags: 1.0.0 - optionalDependencies: - '@babel/core': 7.26.0 + '@types/chai': 5.2.2 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.2.0 + tinyrainbow: 2.0.0 + dev: true + + /@vitest/mocker@3.2.4(vite@7.2.6): + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + vite: 7.2.6(tsx@4.21.0) + dev: true + + /@vitest/pretty-format@3.2.4: + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + dependencies: + tinyrainbow: 2.0.0 + dev: true + + /@vitest/runner@3.2.4: + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.1.0 + dev: true + + /@vitest/snapshot@3.2.4: + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.21 + pathe: 2.0.3 + dev: true + + /@vitest/spy@3.2.4: + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + dependencies: + tinyspy: 4.0.3 + dev: true + + /@vitest/utils@3.2.4: + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.1.4 + tinyrainbow: 2.0.0 + dev: true + + /@volar/language-core@2.4.27: + resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==} + dependencies: + '@volar/source-map': 2.4.27 + dev: false + + /@volar/source-map@2.4.27: + resolution: {integrity: sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==} + dev: false + + /@vue-macros/common@3.1.2(vue@3.5.27): + resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==} + engines: {node: '>=20.19.0'} + peerDependencies: + vue: ^2.7.0 || ^3.2.25 + peerDependenciesMeta: + vue: + optional: true + dependencies: + '@vue/compiler-sfc': 3.5.27 + ast-kit: 2.2.0 + local-pkg: 1.1.2 + magic-string-ast: 1.0.3 + unplugin-utils: 0.3.1 + vue: 3.5.27(typescript@5.9.3) + dev: false + + /@vue/babel-helper-vue-transform-on@2.0.1: + resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==} + dev: false + + /@vue/babel-plugin-jsx@2.0.1(@babel/core@7.28.6): + resolution: {integrity: sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) + '@babel/template': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + '@vue/babel-helper-vue-transform-on': 2.0.1 + '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.28.6) + '@vue/shared': 3.5.25 transitivePeerDependencies: - supports-color + dev: false - '@vue/babel-plugin-resolve-type@1.2.5(@babel/core@7.26.0)': + /@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.28.6): + resolution: {integrity: sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/code-frame': 7.26.2 - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/parser': 7.26.5 - '@vue/compiler-sfc': 3.5.13 + '@babel/code-frame': 7.28.6 + '@babel/core': 7.28.6 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/parser': 7.28.6 + '@vue/compiler-sfc': 3.5.27 transitivePeerDependencies: - supports-color + dev: false - '@vue/compiler-core@3.5.13': + /@vue/compiler-core@3.5.27: + resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==} dependencies: - '@babel/parser': 7.26.5 - '@vue/shared': 3.5.13 - entities: 4.5.0 + '@babel/parser': 7.28.6 + '@vue/shared': 3.5.27 + entities: 7.0.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + /@vue/compiler-core@3.5.42: + resolution: {integrity: sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==} + dependencies: + '@babel/parser': 7.29.8 + '@vue/shared': 3.5.42 + entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 + dev: false - '@vue/compiler-dom@3.5.13': + /@vue/compiler-dom@3.5.27: + resolution: {integrity: sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==} dependencies: - '@vue/compiler-core': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/compiler-core': 3.5.27 + '@vue/shared': 3.5.27 - '@vue/compiler-sfc@3.5.13': + /@vue/compiler-dom@3.5.42: + resolution: {integrity: sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==} dependencies: - '@babel/parser': 7.26.5 - '@vue/compiler-core': 3.5.13 - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/compiler-core': 3.5.42 + '@vue/shared': 3.5.42 + dev: false + + /@vue/compiler-sfc@3.5.27: + resolution: {integrity: sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==} + dependencies: + '@babel/parser': 7.28.6 + '@vue/compiler-core': 3.5.27 + '@vue/compiler-dom': 3.5.27 + '@vue/compiler-ssr': 3.5.27 + '@vue/shared': 3.5.27 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.6 + source-map-js: 1.2.1 + + /@vue/compiler-sfc@3.5.42: + resolution: {integrity: sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==} + dependencies: + '@babel/parser': 7.29.8 + '@vue/compiler-core': 3.5.42 + '@vue/compiler-dom': 3.5.42 + '@vue/compiler-ssr': 3.5.42 + '@vue/shared': 3.5.42 estree-walker: 2.0.2 - magic-string: 0.30.17 - postcss: 8.5.1 + magic-string: 0.30.21 + postcss: 8.5.26 source-map-js: 1.2.1 + dev: false + + /@vue/compiler-ssr@3.5.27: + resolution: {integrity: sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==} + dependencies: + '@vue/compiler-dom': 3.5.27 + '@vue/shared': 3.5.27 - '@vue/compiler-ssr@3.5.13': + /@vue/compiler-ssr@3.5.42: + resolution: {integrity: sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==} dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/compiler-dom': 3.5.42 + '@vue/shared': 3.5.42 + dev: false - '@vue/devtools-api@6.6.4': {} + /@vue/devtools-api@6.6.4: + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + dev: false - '@vue/devtools-core@7.6.8(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': + /@vue/devtools-core@8.0.5(vite@7.3.6)(vue@3.5.27): + resolution: {integrity: sha512-dpCw8nl0GDBuiL9SaY0mtDxoGIEmU38w+TQiYEPOLhW03VDC0lfNMYXS/qhl4I0YlysGp04NLY4UNn6xgD0VIQ==} + peerDependencies: + vue: ^3.0.0 dependencies: - '@vue/devtools-kit': 7.6.8 - '@vue/devtools-shared': 7.7.0 + '@vue/devtools-kit': 8.0.5 + '@vue/devtools-shared': 8.0.5 mitt: 3.0.1 - nanoid: 5.0.9 - pathe: 1.1.2 - vite-hot-client: 0.2.4(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) - vue: 3.5.13(typescript@5.7.3) + nanoid: 5.1.5 + pathe: 2.0.3 + vite-hot-client: 2.1.0(vite@7.3.6) + vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - vite + dev: false - '@vue/devtools-kit@7.6.8': + /@vue/devtools-kit@8.0.5: + resolution: {integrity: sha512-q2VV6x1U3KJMTQPUlRMyWEKVbcHuxhqJdSr6Jtjz5uAThAIrfJ6WVZdGZm5cuO63ZnSUz0RCsVwiUUb0mDV0Yg==} dependencies: - '@vue/devtools-shared': 7.7.0 - birpc: 0.2.19 + '@vue/devtools-shared': 8.0.5 + birpc: 2.8.0 hookable: 5.5.3 mitt: 3.0.1 - perfect-debounce: 1.0.0 + perfect-debounce: 2.0.0 speakingurl: 14.0.1 superjson: 2.2.2 + dev: false - '@vue/devtools-shared@7.7.0': + /@vue/devtools-shared@8.0.5: + resolution: {integrity: sha512-bRLn6/spxpmgLk+iwOrR29KrYnJjG9DGpHGkDFG82UM21ZpJ39ztUT9OXX3g+usW7/b2z+h46I9ZiYyB07XMXg==} dependencies: rfdc: 1.4.1 + dev: false - '@vue/reactivity@3.5.13': + /@vue/language-core@3.2.2: + resolution: {integrity: sha512-5DAuhxsxBN9kbriklh3Q5AMaJhyOCNiQJvCskN9/30XOpdLiqZU9Q+WvjArP17ubdGEyZtBzlIeG5nIjEbNOrQ==} dependencies: - '@vue/shared': 3.5.13 + '@volar/language-core': 2.4.27 + '@vue/compiler-dom': 3.5.27 + '@vue/shared': 3.5.25 + alien-signals: 3.1.2 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.3 + dev: false - '@vue/runtime-core@3.5.13': + /@vue/reactivity@3.5.27: + resolution: {integrity: sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==} dependencies: - '@vue/reactivity': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/shared': 3.5.27 - '@vue/runtime-dom@3.5.13': + /@vue/runtime-core@3.5.27: + resolution: {integrity: sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==} dependencies: - '@vue/reactivity': 3.5.13 - '@vue/runtime-core': 3.5.13 - '@vue/shared': 3.5.13 - csstype: 3.1.3 + '@vue/reactivity': 3.5.27 + '@vue/shared': 3.5.27 - '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3))': + /@vue/runtime-dom@3.5.27: + resolution: {integrity: sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==} dependencies: - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - vue: 3.5.13(typescript@5.7.3) + '@vue/reactivity': 3.5.27 + '@vue/runtime-core': 3.5.27 + '@vue/shared': 3.5.27 + csstype: 3.2.3 + + /@vue/server-renderer@3.5.27(vue@3.5.27): + resolution: {integrity: sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==} + peerDependencies: + vue: 3.5.27 + dependencies: + '@vue/compiler-ssr': 3.5.27 + '@vue/shared': 3.5.27 + vue: 3.5.27(typescript@5.9.3) + + /@vue/shared@3.5.25: + resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} + dev: false - '@vue/shared@3.5.13': {} + /@vue/shared@3.5.27: + resolution: {integrity: sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==} - '@vueuse/core@12.4.0(typescript@5.7.3)': + /@vue/shared@3.5.42: + resolution: {integrity: sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==} + dev: false + + /@vue/test-utils@2.4.6: + resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} + dependencies: + js-beautify: 1.15.4 + vue-component-type-helpers: 2.2.10 + dev: true + + /@vueuse/core@12.8.2(typescript@5.9.3): + resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} dependencies: - '@types/web-bluetooth': 0.0.20 - '@vueuse/metadata': 12.4.0 - '@vueuse/shared': 12.4.0(typescript@5.7.3) - vue: 3.5.13(typescript@5.7.3) + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 12.8.2 + '@vueuse/shared': 12.8.2(typescript@5.9.3) + vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - typescript + dev: false + + /@vueuse/core@14.1.0(vue@3.5.27): + resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==} + peerDependencies: + vue: ^3.5.0 + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.1.0 + '@vueuse/shared': 14.1.0(vue@3.5.27) + vue: 3.5.27(typescript@5.9.3) + dev: false - '@vueuse/metadata@12.4.0': {} + /@vueuse/metadata@12.8.2: + resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} + dev: false - '@vueuse/shared@12.4.0(typescript@5.7.3)': + /@vueuse/metadata@14.1.0: + resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==} + dev: false + + /@vueuse/shared@12.8.2(typescript@5.9.3): + resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} dependencies: - vue: 3.5.13(typescript@5.7.3) + vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - typescript + dev: false - abbrev@2.0.0: {} - - abort-controller@3.0.0: + /@vueuse/shared@14.1.0(vue@3.5.27): + resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==} + peerDependencies: + vue: ^3.5.0 dependencies: - event-target-shim: 5.0.1 + vue: 3.5.27(typescript@5.9.3) + dev: false - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 + /abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} + dev: false - acorn-import-attributes@1.9.5(acorn@8.14.0): + /abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} dependencies: - acorn: 8.14.0 + event-target-shim: 5.0.1 + dev: false - acorn@8.14.0: {} + /acorn-import-attributes@1.9.5(acorn@8.15.0): + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + dependencies: + acorn: 8.15.0 + dev: false - agent-base@7.1.3: {} + /acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true - ansi-colors@4.1.3: {} + /agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + dev: false - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 + /alien-signals@3.1.2: + resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} + dev: false - ansi-regex@5.0.1: {} + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} - ansi-regex@6.1.0: {} + /ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} - ansi-styles@4.3.0: + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - ansi-styles@6.2.1: {} + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} - any-promise@1.3.0: {} + /ansis@4.1.0: + resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} + engines: {node: '>=14'} + dev: false - anymatch@3.1.3: + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 + dev: false - archiver-utils@5.0.2: + /archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} dependencies: - glob: 10.4.5 + glob: 10.5.0 graceful-fs: 4.2.11 is-stream: 2.0.1 lazystream: 1.0.1 lodash: 4.17.21 normalize-path: 3.0.0 readable-stream: 4.7.0 + dev: false - archiver@7.0.1: + /archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} dependencies: archiver-utils: 5.0.2 async: 3.2.6 @@ -5360,524 +4365,962 @@ snapshots: readdir-glob: 1.1.3 tar-stream: 3.1.7 zip-stream: 6.0.1 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + dev: false - arg@5.0.2: {} - - argparse@2.0.1: {} - - ast-kit@1.4.0: + /aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} dependencies: - '@babel/parser': 7.26.5 - pathe: 2.0.2 + tslib: 2.8.1 + dev: false - ast-walker-scope@0.6.2: - dependencies: - '@babel/parser': 7.26.5 - ast-kit: 1.4.0 + /assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + dev: true - async-sema@3.1.1: {} + /ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + dependencies: + '@babel/parser': 7.28.6 + pathe: 2.0.3 + dev: false - async@2.6.4: + /ast-walker-scope@0.8.3: + resolution: {integrity: sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==} + engines: {node: '>=20.19.0'} dependencies: - lodash: 4.17.21 + '@babel/parser': 7.28.6 + ast-kit: 2.2.0 + dev: false - async@3.2.6: {} + /async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + dev: false - at-least-node@1.0.0: {} + /async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + dev: false - autoprefixer@10.4.20(postcss@8.5.1): + /autoprefixer@10.4.23(postcss@8.5.6): + resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 dependencies: - browserslist: 4.24.4 - caniuse-lite: 1.0.30001695 - fraction.js: 4.3.7 - normalize-range: 0.1.2 + browserslist: 4.28.1 + caniuse-lite: 1.0.30001765 + fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false + + /b4a@1.7.3: + resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + dev: false - b4a@1.6.7: {} + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@1.0.2: {} + /bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + requiresBuild: true + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + dev: false - bare-events@2.5.4: - optional: true + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false - base64-js@1.5.1: {} + /baseline-browser-mapping@2.9.16: + resolution: {integrity: sha512-KeUZdBuxngy825i8xvzaK1Ncnkx0tBmb3k8DkEuqjKRkmtvNTjey2ZsNeh8Dw4lfKvbCOu9oeNx2TKm2vHqcRw==} + hasBin: true + dev: false - better-sqlite3@11.8.1: + /better-sqlite3@12.11.1: + resolution: {integrity: sha512-dq9AtApgg5PGFtBzPFSBl3HZQjHok5gaQCM6zh2Yk0aSmDCs1CbnVI8/HgASQkNKsWFpseIO9beg5xxpYhbIfA==} + engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x || 26.x} + requiresBuild: true dependencies: bindings: 1.5.0 - prebuild-install: 7.1.2 + prebuild-install: 7.1.3 + dev: false - binary-extensions@2.3.0: {} - - bindings@1.5.0: + /bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} dependencies: file-uri-to-path: 1.0.0 + dev: false - birpc@0.2.19: {} + /birpc@2.8.0: + resolution: {integrity: sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw==} + dev: false - bl@4.1.0: + /bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 + dev: false - boolbase@1.0.0: {} - - bootstrap@5.3.3(@popperjs/core@2.11.8): - dependencies: - '@popperjs/core': 2.11.8 + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false - brace-expansion@1.1.11: + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - concat-map: 0.0.1 - brace-expansion@2.0.1: + /brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} dependencies: balanced-match: 1.0.2 + dev: false - braces@3.0.3: + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} dependencies: fill-range: 7.1.1 + dev: false + + /brotli@1.3.3: + resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} + dependencies: + base64-js: 1.5.1 + dev: false - browserslist@4.24.4: + /browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true dependencies: - caniuse-lite: 1.0.30001695 - electron-to-chromium: 1.5.83 - node-releases: 2.0.19 - update-browserslist-db: 1.1.2(browserslist@4.24.4) + baseline-browser-mapping: 2.9.16 + caniuse-lite: 1.0.30001765 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + dev: false - buffer-crc32@1.0.0: {} + /buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + dev: false - buffer-from@1.1.2: {} + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer@5.7.1: + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: base64-js: 1.5.1 ieee754: 1.2.1 + dev: false - buffer@6.0.3: + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} dependencies: base64-js: 1.5.1 ieee754: 1.2.1 + dev: false - bundle-name@4.1.0: + /bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} dependencies: run-applescript: 7.0.0 + dev: false - c12@2.0.1(magicast@0.3.5): + /c12@3.3.2(magicast@0.5.1): + resolution: {integrity: sha512-QkikB2X5voO1okL3QsES0N690Sn/K9WokXqUsDQsWy5SnYb+psYQFGA10iy1bZHj3fjISKsI67Q90gruvWWM3A==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true dependencies: chokidar: 4.0.3 - confbox: 0.1.8 + confbox: 0.2.2 defu: 6.1.4 - dotenv: 16.4.7 - giget: 1.2.3 - jiti: 2.4.2 - mlly: 1.7.4 - ohash: 1.1.4 - pathe: 1.1.2 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 + dotenv: 17.2.3 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + magicast: 0.5.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 rc9: 2.1.2 - optionalDependencies: - magicast: 0.3.5 - - cac@6.7.14: {} + dev: false - cache-content-type@1.0.1: - dependencies: - mime-types: 2.1.35 - ylru: 1.4.0 - - call-bind-apply-helpers@1.0.1: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.3: + /c12@3.3.3(magicast@0.5.1): + resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true dependencies: - call-bind-apply-helpers: 1.0.1 - get-intrinsic: 1.2.7 + chokidar: 5.0.0 + confbox: 0.2.2 + defu: 6.1.4 + dotenv: 17.2.3 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + magicast: 0.5.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + rc9: 2.1.2 - camelcase-css@2.0.1: {} + /cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} - caniuse-api@3.0.0: + /caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: - browserslist: 4.24.4 - caniuse-lite: 1.0.30001695 + browserslist: 4.28.1 + caniuse-lite: 1.0.30001765 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 + dev: false - caniuse-lite@1.0.30001695: {} + /caniuse-lite@1.0.30001765: + resolution: {integrity: sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==} + dev: false - chalk@4.1.2: + /chai@5.2.0: + resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} + engines: {node: '>=12'} dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.4 + pathval: 2.0.1 + dev: true - change-case@5.4.4: {} + /check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + dev: true - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 + /chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + dependencies: + readdirp: 4.1.2 + dev: false - chokidar@4.0.3: + /chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} dependencies: - readdirp: 4.1.1 + readdirp: 5.0.0 + + /chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false - chownr@1.1.4: {} + /chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + dev: false - chownr@2.0.0: {} + /citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + dependencies: + consola: 3.4.2 - chownr@3.0.0: {} + /citty@0.2.0: + resolution: {integrity: sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA==} - citty@0.1.6: + /class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} dependencies: - consola: 3.4.0 + clsx: 2.1.1 + dev: false - clipboardy@4.0.0: + /clipboardy@4.0.0: + resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} + engines: {node: '>=18'} dependencies: execa: 8.0.1 is-wsl: 3.1.0 is64bit: 2.0.0 + dev: false - cliui@8.0.1: + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + dev: false + + /clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + dev: false - cluster-key-slot@1.1.2: {} + /clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + dev: false - co@4.6.0: {} + /cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + dev: false - color-convert@2.0.1: + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - color-name@1.1.4: {} - - colord@2.9.3: {} - - colorette@1.4.0: {} - - commander@2.20.3: {} + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - commander@4.1.1: {} + /colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + dev: false - commander@6.2.1: {} + /commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + dev: true - commander@7.2.0: {} + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: false - commander@8.3.0: {} + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: false - commondir@1.0.1: {} + /commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + dev: false - compatx@0.1.8: {} + /compatx@0.2.0: + resolution: {integrity: sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==} + dev: false - compress-commons@6.0.2: + /compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} dependencies: crc-32: 1.2.2 crc32-stream: 6.0.0 is-stream: 2.0.1 normalize-path: 3.0.0 readable-stream: 4.7.0 + dev: false - concat-map@0.0.1: {} - - confbox@0.1.8: {} + /confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - consola@3.4.0: {} + /confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} - content-disposition@0.5.4: + /config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} dependencies: - safe-buffer: 5.2.1 + ini: 1.3.8 + proto-list: 1.2.4 + dev: true - content-type@1.0.5: {} + /consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} - convert-source-map@2.0.0: {} + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: false - cookie-es@1.2.2: {} + /cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} - cookies@0.9.1: - dependencies: - depd: 2.0.0 - keygrip: 1.1.0 + /cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + dev: false - copy-anything@3.0.5: + /copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} dependencies: is-what: 4.1.16 + dev: false + + /copy-paste@2.2.0: + resolution: {integrity: sha512-jqSL4r9DSeiIvJZStLzY/sMLt9ToTM7RsK237lYOTG+KcbQJHGala3R1TUpa8h1p9adswVgIdV4qGbseVhL4lg==} + dependencies: + iconv-lite: 0.4.24 + dev: false - core-util-is@1.0.3: {} + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: false - crc-32@1.2.2: {} + /crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + dev: false - crc32-stream@6.0.0: + /crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} dependencies: crc-32: 1.2.2 readable-stream: 4.7.0 + dev: false - croner@9.0.0: {} - - cronstrue@2.53.0: {} + /croner@9.1.0: + resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==} + engines: {node: '>=18.0'} + dev: false - cross-spawn@7.0.6: + /cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - crossws@0.3.1: + /crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} dependencies: uncrypto: 0.1.3 - css-declaration-sorter@7.2.0(postcss@8.5.1): + /css-declaration-sorter@7.3.1(postcss@8.5.6): + resolution: {integrity: sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.0.9 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 + dev: false - css-select@5.1.0: + /css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} dependencies: boolbase: 1.0.0 - css-what: 6.1.0 + css-what: 6.2.2 domhandler: 5.0.3 domutils: 3.2.2 nth-check: 2.1.1 + dev: false - css-tree@2.2.1: + /css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} dependencies: mdn-data: 2.0.28 source-map-js: 1.2.1 + dev: false - css-tree@2.3.1: + /css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} dependencies: - mdn-data: 2.0.30 + mdn-data: 2.12.2 source-map-js: 1.2.1 + dev: false + + /css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + dev: false + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /cssnano-preset-default@7.0.10(postcss@8.5.6): + resolution: {integrity: sha512-6ZBjW0Lf1K1Z+0OKUAUpEN62tSXmYChXWi2NAA0afxEVsj9a+MbcB1l5qel6BHJHmULai2fCGRthCeKSFbScpA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + dependencies: + browserslist: 4.28.1 + css-declaration-sorter: 7.3.1(postcss@8.5.6) + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-calc: 10.1.1(postcss@8.5.6) + postcss-colormin: 7.0.5(postcss@8.5.6) + postcss-convert-values: 7.0.8(postcss@8.5.6) + postcss-discard-comments: 7.0.5(postcss@8.5.6) + postcss-discard-duplicates: 7.0.2(postcss@8.5.6) + postcss-discard-empty: 7.0.1(postcss@8.5.6) + postcss-discard-overridden: 7.0.1(postcss@8.5.6) + postcss-merge-longhand: 7.0.5(postcss@8.5.6) + postcss-merge-rules: 7.0.7(postcss@8.5.6) + postcss-minify-font-values: 7.0.1(postcss@8.5.6) + postcss-minify-gradients: 7.0.1(postcss@8.5.6) + postcss-minify-params: 7.0.5(postcss@8.5.6) + postcss-minify-selectors: 7.0.5(postcss@8.5.6) + postcss-normalize-charset: 7.0.1(postcss@8.5.6) + postcss-normalize-display-values: 7.0.1(postcss@8.5.6) + postcss-normalize-positions: 7.0.1(postcss@8.5.6) + postcss-normalize-repeat-style: 7.0.1(postcss@8.5.6) + postcss-normalize-string: 7.0.1(postcss@8.5.6) + postcss-normalize-timing-functions: 7.0.1(postcss@8.5.6) + postcss-normalize-unicode: 7.0.5(postcss@8.5.6) + postcss-normalize-url: 7.0.1(postcss@8.5.6) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.6) + postcss-ordered-values: 7.0.2(postcss@8.5.6) + postcss-reduce-initial: 7.0.5(postcss@8.5.6) + postcss-reduce-transforms: 7.0.1(postcss@8.5.6) + postcss-svgo: 7.1.0(postcss@8.5.6) + postcss-unique-selectors: 7.0.4(postcss@8.5.6) + dev: false + + /cssnano-utils@5.0.1(postcss@8.5.6): + resolution: {integrity: sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + dependencies: + postcss: 8.5.6 + dev: false - css-what@6.1.0: {} - - cssesc@3.0.0: {} - - cssnano-preset-default@7.0.6(postcss@8.5.1): - dependencies: - browserslist: 4.24.4 - css-declaration-sorter: 7.2.0(postcss@8.5.1) - cssnano-utils: 5.0.0(postcss@8.5.1) - postcss: 8.5.1 - postcss-calc: 10.1.0(postcss@8.5.1) - postcss-colormin: 7.0.2(postcss@8.5.1) - postcss-convert-values: 7.0.4(postcss@8.5.1) - postcss-discard-comments: 7.0.3(postcss@8.5.1) - postcss-discard-duplicates: 7.0.1(postcss@8.5.1) - postcss-discard-empty: 7.0.0(postcss@8.5.1) - postcss-discard-overridden: 7.0.0(postcss@8.5.1) - postcss-merge-longhand: 7.0.4(postcss@8.5.1) - postcss-merge-rules: 7.0.4(postcss@8.5.1) - postcss-minify-font-values: 7.0.0(postcss@8.5.1) - postcss-minify-gradients: 7.0.0(postcss@8.5.1) - postcss-minify-params: 7.0.2(postcss@8.5.1) - postcss-minify-selectors: 7.0.4(postcss@8.5.1) - postcss-normalize-charset: 7.0.0(postcss@8.5.1) - postcss-normalize-display-values: 7.0.0(postcss@8.5.1) - postcss-normalize-positions: 7.0.0(postcss@8.5.1) - postcss-normalize-repeat-style: 7.0.0(postcss@8.5.1) - postcss-normalize-string: 7.0.0(postcss@8.5.1) - postcss-normalize-timing-functions: 7.0.0(postcss@8.5.1) - postcss-normalize-unicode: 7.0.2(postcss@8.5.1) - postcss-normalize-url: 7.0.0(postcss@8.5.1) - postcss-normalize-whitespace: 7.0.0(postcss@8.5.1) - postcss-ordered-values: 7.0.1(postcss@8.5.1) - postcss-reduce-initial: 7.0.2(postcss@8.5.1) - postcss-reduce-transforms: 7.0.0(postcss@8.5.1) - postcss-svgo: 7.0.1(postcss@8.5.1) - postcss-unique-selectors: 7.0.3(postcss@8.5.1) - - cssnano-utils@5.0.0(postcss@8.5.1): - dependencies: - postcss: 8.5.1 - - cssnano@7.0.6(postcss@8.5.1): - dependencies: - cssnano-preset-default: 7.0.6(postcss@8.5.1) + /cssnano@7.1.2(postcss@8.5.6): + resolution: {integrity: sha512-HYOPBsNvoiFeR1eghKD5C3ASm64v9YVyJB4Ivnl2gqKoQYvjjN/G0rztvKQq8OxocUtC6sjqY8jwYngIB4AByA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + dependencies: + cssnano-preset-default: 7.0.10(postcss@8.5.6) lilconfig: 3.1.3 - postcss: 8.5.1 + postcss: 8.5.6 + dev: false - csso@5.0.5: + /csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} dependencies: css-tree: 2.2.1 + dev: false - csstype@3.1.3: {} - - dayjs@1.11.13: {} + /csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - db0@0.2.1(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1)): - optionalDependencies: - better-sqlite3: 11.8.1 - drizzle-orm: 0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1) + /dayjs@1.11.23: + resolution: {integrity: sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==} + dev: false - debug@2.6.9: + /db0@0.3.4(better-sqlite3@12.11.1)(drizzle-orm@0.45.1): + resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==} + peerDependencies: + '@electric-sql/pglite': '*' + '@libsql/client': '*' + better-sqlite3: '*' + drizzle-orm: '*' + mysql2: '*' + sqlite3: '*' + peerDependenciesMeta: + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + better-sqlite3: + optional: true + drizzle-orm: + optional: true + mysql2: + optional: true + sqlite3: + optional: true dependencies: - ms: 2.0.0 + better-sqlite3: 12.11.1 + drizzle-orm: 0.45.1(@types/better-sqlite3@7.6.13)(@types/pg@8.23.1)(better-sqlite3@12.11.1)(pg@8.23.0) + dev: false - debug@3.2.7: + /debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.1.3 + dev: true - debug@4.4.0(supports-color@9.4.0): + /debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.1.3 - optionalDependencies: - supports-color: 9.4.0 + dev: false - decompress-response@6.0.0: + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} dependencies: mimic-response: 3.1.0 + dev: false - deep-equal@1.0.1: {} + /deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + dev: true - deep-extend@0.6.0: {} + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false - deepmerge@4.3.1: {} + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: false - default-browser-id@5.0.0: {} + /default-browser-id@5.0.0: + resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + engines: {node: '>=18'} + dev: false - default-browser@5.2.1: + /default-browser@5.2.1: + resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + engines: {node: '>=18'} dependencies: bundle-name: 4.1.0 default-browser-id: 5.0.0 + dev: false - define-lazy-prop@2.0.0: {} - - define-lazy-prop@3.0.0: {} - - defu@6.1.4: {} - - delegates@1.0.0: {} - - denque@2.1.0: {} + /define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + dev: false - depd@1.1.2: {} + /define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + dev: false - depd@2.0.0: {} + /defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - destr@2.0.3: {} + /denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + dev: false - destroy@1.2.0: {} + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false - detect-libc@1.0.3: {} + /destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - detect-libc@2.0.3: {} + /detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + engines: {node: '>=8'} + dev: false - devalue@5.1.1: {} + /detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + dev: false - didyoumean@1.2.2: {} + /devalue@5.6.2: + resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} + dev: false - diff@7.0.0: {} + /dfa@1.2.0: + resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==} + dev: false - dlv@1.1.3: {} + /diff@8.0.2: + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + engines: {node: '>=0.3.1'} + dev: false - dom-serializer@2.0.0: + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 entities: 4.5.0 + dev: false - domelementtype@2.3.0: {} + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false - domhandler@5.0.3: + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} dependencies: domelementtype: 2.3.0 + dev: false - domutils@3.2.2: + /domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 + dev: false - dot-prop@9.0.0: + /dot-prop@10.1.0: + resolution: {integrity: sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==} + engines: {node: '>=20'} dependencies: - type-fest: 4.32.0 + type-fest: 5.4.1 + dev: false - dotenv@16.4.7: {} + /dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dev: false + + /dotenv@17.2.3: + resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + engines: {node: '>=12'} - drizzle-kit@0.30.2: + /drizzle-kit@0.31.8: + resolution: {integrity: sha512-O9EC/miwdnRDY10qRxM8P3Pg8hXe3LyU4ZipReKOgTwn4OqANmftj8XJz1UPUAS6NMHf0E2htjsbQujUTkncCg==} + hasBin: true dependencies: '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.6.5 - esbuild: 0.19.12 - esbuild-register: 3.6.0(esbuild@0.19.12) + esbuild: 0.25.12 + esbuild-register: 3.6.0(esbuild@0.25.12) transitivePeerDependencies: - supports-color + dev: true - drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1): - optionalDependencies: - '@types/better-sqlite3': 7.6.12 - better-sqlite3: 11.8.1 - - dunder-proto@1.0.1: + /drizzle-orm@0.45.1(@types/better-sqlite3@7.6.13)(@types/pg@8.23.1)(better-sqlite3@12.11.1)(pg@8.23.0): + resolution: {integrity: sha512-Te0FOdKIistGNPMq2jscdqngBRfBpC8uMFVwqjf6gtTVJHIQ/dosgV/CLBU2N4ZJBsXL5savCba9b0YJskKdcA==} + peerDependencies: + '@aws-sdk/client-rds-data': '>=3' + '@cloudflare/workers-types': '>=4' + '@electric-sql/pglite': '>=0.2.0' + '@libsql/client': '>=0.10.0' + '@libsql/client-wasm': '>=0.10.0' + '@neondatabase/serverless': '>=0.10.0' + '@op-engineering/op-sqlite': '>=2' + '@opentelemetry/api': ^1.4.1 + '@planetscale/database': '>=1.13' + '@prisma/client': '*' + '@tidbcloud/serverless': '*' + '@types/better-sqlite3': '*' + '@types/pg': '*' + '@types/sql.js': '*' + '@upstash/redis': '>=1.34.7' + '@vercel/postgres': '>=0.8.0' + '@xata.io/client': '*' + better-sqlite3: '>=7' + bun-types: '*' + expo-sqlite: '>=14.0.0' + gel: '>=2' + knex: '*' + kysely: '*' + mysql2: '>=2' + pg: '>=8' + postgres: '>=3' + prisma: '*' + sql.js: '>=1' + sqlite3: '>=5' + peerDependenciesMeta: + '@aws-sdk/client-rds-data': + optional: true + '@cloudflare/workers-types': + optional: true + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + '@libsql/client-wasm': + optional: true + '@neondatabase/serverless': + optional: true + '@op-engineering/op-sqlite': + optional: true + '@opentelemetry/api': + optional: true + '@planetscale/database': + optional: true + '@prisma/client': + optional: true + '@tidbcloud/serverless': + optional: true + '@types/better-sqlite3': + optional: true + '@types/pg': + optional: true + '@types/sql.js': + optional: true + '@upstash/redis': + optional: true + '@vercel/postgres': + optional: true + '@xata.io/client': + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + gel: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + prisma: + optional: true + sql.js: + optional: true + sqlite3: + optional: true dependencies: - call-bind-apply-helpers: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 + '@types/better-sqlite3': 7.6.13 + '@types/pg': 8.23.1 + better-sqlite3: 12.11.1 + pg: 8.23.0 + dev: false - duplexer@0.1.2: {} + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: false - eastasianwidth@0.2.0: {} + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ee-first@1.1.1: {} + /editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.7.3 + dev: true - electron-to-chromium@1.5.83: {} + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: false - emoji-regex@8.0.0: {} + /electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + dev: false - emoji-regex@9.2.2: {} + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - encodeurl@1.0.2: {} + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encodeurl@2.0.0: {} + /encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + dev: false - end-of-stream@1.4.4: + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: once: 1.4.0 + dev: false - enhanced-resolve@5.18.0: + /enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 - tapable: 2.2.1 + tapable: 2.3.0 + dev: false - entities@4.5.0: {} + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: false - error-stack-parser-es@0.1.5: {} + /entities@7.0.0: + resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} + engines: {node: '>=0.12'} - errx@0.1.0: {} + /entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + dev: false - es-define-property@1.0.1: {} + /error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + dev: false - es-errors@1.3.0: {} + /errx@0.1.0: + resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==} - es-module-lexer@1.6.0: {} + /es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + dev: true - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 + /es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + dev: false - esbuild-register@3.6.0(esbuild@0.19.12): + /esbuild-register@3.6.0(esbuild@0.25.12): + resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} + peerDependencies: + esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@9.4.0) - esbuild: 0.19.12 + debug: 4.4.1 + esbuild: 0.25.12 transitivePeerDependencies: - supports-color + dev: true - esbuild@0.18.20: + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true optionalDependencies: '@esbuild/android-arm': 0.18.20 '@esbuild/android-arm64': 0.18.20 @@ -5901,118 +5344,190 @@ snapshots: '@esbuild/win32-arm64': 0.18.20 '@esbuild/win32-ia32': 0.18.20 '@esbuild/win32-x64': 0.18.20 + dev: true - esbuild@0.19.12: + /esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + /esbuild@0.27.0: + resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - - esbuild@0.21.5: + '@esbuild/aix-ppc64': 0.27.0 + '@esbuild/android-arm': 0.27.0 + '@esbuild/android-arm64': 0.27.0 + '@esbuild/android-x64': 0.27.0 + '@esbuild/darwin-arm64': 0.27.0 + '@esbuild/darwin-x64': 0.27.0 + '@esbuild/freebsd-arm64': 0.27.0 + '@esbuild/freebsd-x64': 0.27.0 + '@esbuild/linux-arm': 0.27.0 + '@esbuild/linux-arm64': 0.27.0 + '@esbuild/linux-ia32': 0.27.0 + '@esbuild/linux-loong64': 0.27.0 + '@esbuild/linux-mips64el': 0.27.0 + '@esbuild/linux-ppc64': 0.27.0 + '@esbuild/linux-riscv64': 0.27.0 + '@esbuild/linux-s390x': 0.27.0 + '@esbuild/linux-x64': 0.27.0 + '@esbuild/netbsd-arm64': 0.27.0 + '@esbuild/netbsd-x64': 0.27.0 + '@esbuild/openbsd-arm64': 0.27.0 + '@esbuild/openbsd-x64': 0.27.0 + '@esbuild/openharmony-arm64': 0.27.0 + '@esbuild/sunos-x64': 0.27.0 + '@esbuild/win32-arm64': 0.27.0 + '@esbuild/win32-ia32': 0.27.0 + '@esbuild/win32-x64': 0.27.0 + + /esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 - - esbuild@0.24.2: + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 + dev: false + + /esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true optionalDependencies: - '@esbuild/aix-ppc64': 0.24.2 - '@esbuild/android-arm': 0.24.2 - '@esbuild/android-arm64': 0.24.2 - '@esbuild/android-x64': 0.24.2 - '@esbuild/darwin-arm64': 0.24.2 - '@esbuild/darwin-x64': 0.24.2 - '@esbuild/freebsd-arm64': 0.24.2 - '@esbuild/freebsd-x64': 0.24.2 - '@esbuild/linux-arm': 0.24.2 - '@esbuild/linux-arm64': 0.24.2 - '@esbuild/linux-ia32': 0.24.2 - '@esbuild/linux-loong64': 0.24.2 - '@esbuild/linux-mips64el': 0.24.2 - '@esbuild/linux-ppc64': 0.24.2 - '@esbuild/linux-riscv64': 0.24.2 - '@esbuild/linux-s390x': 0.24.2 - '@esbuild/linux-x64': 0.24.2 - '@esbuild/netbsd-arm64': 0.24.2 - '@esbuild/netbsd-x64': 0.24.2 - '@esbuild/openbsd-arm64': 0.24.2 - '@esbuild/openbsd-x64': 0.24.2 - '@esbuild/sunos-x64': 0.24.2 - '@esbuild/win32-arm64': 0.24.2 - '@esbuild/win32-ia32': 0.24.2 - '@esbuild/win32-x64': 0.24.2 - - escalade@3.2.0: {} + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + dev: false + + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + dev: false - escape-html@1.0.3: {} + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: false - escape-string-regexp@5.0.0: {} + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: false - estree-walker@2.0.2: {} + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - estree-walker@3.0.3: + /estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 - etag@1.8.1: {} - - event-target-shim@5.0.1: {} + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + dev: false - events@3.3.0: {} + /event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: false - execa@7.2.0: + /events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 4.3.1 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 3.0.7 - strip-final-newline: 3.0.0 + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + dev: false - execa@8.0.1: + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: false + + /execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} dependencies: cross-spawn: 7.0.6 get-stream: 8.0.1 @@ -6023,298 +5538,452 @@ snapshots: onetime: 6.0.0 signal-exit: 4.1.0 strip-final-newline: 3.0.0 + dev: false - expand-template@2.0.3: {} + /expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + dev: false - externality@1.0.2: - dependencies: - enhanced-resolve: 5.18.0 - mlly: 1.7.4 - pathe: 1.1.2 - ufo: 1.5.4 + /expect-type@1.2.1: + resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + engines: {node: '>=12.0.0'} + dev: true + + /exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + /fake-indexeddb@6.2.5: + resolution: {integrity: sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w==} + engines: {node: '>=18'} + dev: true - fast-deep-equal@3.1.3: {} + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: false - fast-fifo@1.3.2: {} + /fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + dev: false - fast-glob@3.3.3: + /fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.8 + dev: false - fast-npm-meta@0.2.2: {} + /fast-npm-meta@0.4.7: + resolution: {integrity: sha512-aZU3i3eRcSb2NCq8i6N6IlyiTyF6vqAqzBGl2NBF6ngNx/GIqfYbkLDIKZ4z4P0o/RmtsFnVqHwdrSm13o4tnQ==} + dev: false - fastq@1.18.0: + /fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} dependencies: - reusify: 1.0.4 - - fdir@6.4.3(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - - file-uri-to-path@1.0.0: {} + reusify: 1.1.0 + dev: false - fill-range@7.1.1: + /fdir@6.5.0(picomatch@4.0.3): + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true dependencies: - to-regex-range: 5.0.1 - - flatted@3.3.2: {} + picomatch: 4.0.3 - foreground-child@3.3.0: + /fdir@6.5.0(picomatch@4.0.7): + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 + picomatch: 4.0.7 + dev: false - fraction.js@4.3.7: {} - - fresh@0.5.2: {} - - fs-constants@1.0.0: {} + /file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + dev: false - fs-extra@11.3.0: + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 + to-regex-range: 5.0.1 + dev: false - fs-extra@9.1.0: + /fontaine@0.7.0: + resolution: {integrity: sha512-vlaWLyoJrOnCBqycmFo/CA8ZmPzuyJHYmgu261KYKByZ4YLz9sTyHZ4qoHgWSYiDsZXhiLo2XndVMz0WOAyZ8Q==} + engines: {node: '>=18.12.0'} dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-minipass@2.1.0: + '@capsizecss/unpack': 3.0.1 + css-tree: 3.1.0 + magic-regexp: 0.10.0 + magic-string: 0.30.21 + pathe: 2.0.3 + ufo: 1.6.1 + unplugin: 2.3.10 + dev: false + + /fontkit@2.0.4: + resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} + dependencies: + '@swc/helpers': 0.5.15 + brotli: 1.3.3 + clone: 2.1.2 + dfa: 1.2.0 + fast-deep-equal: 3.1.3 + restructure: 3.0.2 + tiny-inflate: 1.0.3 + unicode-properties: 1.4.1 + unicode-trie: 2.0.0 + dev: false + + /fontless@0.1.0(vite@7.3.6): + resolution: {integrity: sha512-KyvRd732HuVd/XP9iEFTb1w8Q01TPSA5GaCJV9HYmPiEs/ZZg/on2YdrQmlKfi9gDGpmN5Bn27Ze/CHqk0vE+w==} + engines: {node: '>=18.12.0'} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true dependencies: - minipass: 3.3.6 + consola: 3.4.2 + css-tree: 3.1.0 + defu: 6.1.4 + esbuild: 0.25.12 + fontaine: 0.7.0 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + ohash: 2.0.11 + pathe: 2.0.3 + ufo: 1.6.1 + unifont: 0.6.0 + unstorage: 1.17.2 + vite: 7.3.6(tsx@4.21.0) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - uploadthing + dev: false - fs.realpath@1.0.0: {} + /foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 - fsevents@2.3.3: - optional: true + /fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + dev: false - function-bind@1.1.2: {} + /fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + dev: false - fuse.js@7.0.0: {} + /fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: false - gensync@1.0.0-beta.2: {} + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + optional: true - get-caller-file@2.0.5: {} + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: false - get-intrinsic@1.2.7: - dependencies: - call-bind-apply-helpers: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 + /fuse.js@7.1.0: + resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} + engines: {node: '>=10'} + dev: false - get-port-please@3.1.2: {} + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: false - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: false - get-stream@6.0.1: {} + /get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} - get-stream@8.0.1: {} + /get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + dev: false - get-tsconfig@4.8.1: + /get-tsconfig@4.10.0: + resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} dependencies: resolve-pkg-maps: 1.0.0 - giget@1.2.3: + /giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 defu: 6.1.4 - node-fetch-native: 1.6.4 - nypm: 0.3.12 - ohash: 1.1.4 - pathe: 1.1.2 - tar: 6.2.1 - - git-config-path@2.0.0: {} + node-fetch-native: 1.6.7 + nypm: 0.6.4 + pathe: 2.0.3 - git-up@8.0.0: + /git-up@8.1.0: + resolution: {integrity: sha512-cT2f5ERrhFDMPS5wLHURcjRiacC8HonX0zIAWBTwHv1fS6HheP902l6pefOX/H9lNmvCHDwomw0VeN7nhg5bxg==} dependencies: - is-ssh: 1.4.0 + is-ssh: 1.4.1 parse-url: 9.2.0 + dev: false - git-url-parse@16.0.0: + /git-url-parse@16.0.1: + resolution: {integrity: sha512-mcD36GrhAzX5JVOsIO52qNpgRyFzYWRbU1VSRFCvJt1IJvqfvH427wWw/CFqkWvjVPtdG5VTx4MKUeC5GeFPDQ==} dependencies: - git-up: 8.0.0 + git-up: 8.1.0 + dev: false - github-from-package@0.0.0: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 + /github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + dev: false - glob-parent@6.0.2: + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 + dev: false - glob@10.4.5: + /glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + hasBin: true dependencies: - foreground-child: 3.3.0 + foreground-child: 3.3.1 jackspeak: 3.4.3 minimatch: 9.0.5 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@7.2.3: + /glob@13.0.0: + resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} + engines: {node: 20 || >=22} dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + minimatch: 10.1.1 + minipass: 7.1.2 + path-scurry: 2.0.1 + dev: false - global-directory@4.0.1: + /global-directory@4.0.1: + resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} + engines: {node: '>=18'} dependencies: ini: 4.1.1 + dev: false - globals@11.12.0: {} - - globby@14.0.2: + /globby@16.1.0: + resolution: {integrity: sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==} + engines: {node: '>=20'} dependencies: - '@sindresorhus/merge-streams': 2.3.0 + '@sindresorhus/merge-streams': 4.0.0 fast-glob: 3.3.3 - ignore: 5.3.2 - path-type: 5.0.0 + ignore: 7.0.5 + is-path-inside: 4.0.0 slash: 5.1.0 - unicorn-magic: 0.1.0 + unicorn-magic: 0.4.0 + dev: false - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: false - gzip-size@7.0.0: + /gzip-size@7.0.0: + resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: duplexer: 0.1.2 + dev: false - h3@1.13.1: + /h3@1.15.4: + resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} dependencies: cookie-es: 1.2.2 - crossws: 0.3.1 + crossws: 0.3.5 defu: 6.1.4 - destr: 2.0.3 + destr: 2.0.5 iron-webcrypto: 1.2.1 - ohash: 1.1.4 + node-mock-http: 1.0.4 radix3: 1.1.2 - ufo: 1.5.4 + ufo: 1.6.1 uncrypto: 0.1.3 - unenv: 1.10.0 - has-flag@4.0.0: {} - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: + /h3@1.15.5: + resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==} dependencies: - has-symbols: 1.1.0 + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.3 + uncrypto: 0.1.3 + dev: false - hasown@2.0.2: + /h3@2.0.1-rc.29: + resolution: {integrity: sha512-woEUYLvpUa9SzbBGOYn3GfsK/EU7JhoUeNc49B2an6mcO1aqg7P8VvWVUfa5Vkb8FxBh9ZAkU+/rJ5m5pTULUA==} + engines: {node: '>=20.11.1'} + hasBin: true + peerDependencies: + crossws: ^0.4.12 + ocache: '>=0.3.0' + peerDependenciesMeta: + crossws: + optional: true + ocache: + optional: true dependencies: - function-bind: 1.1.2 - - hookable@5.5.3: {} + rou3: 0.9.2 + srvx: 0.12.7 + dev: true - html-tags@3.3.1: {} - - http-assert@1.5.0: + /happy-dom@18.0.1: + resolution: {integrity: sha512-qn+rKOW7KWpVTtgIUi6RVmTBZJSe2k0Db0vh1f7CWrWclkkc7/Q+FrOfkZIb2eiErLyqu5AXEzE7XthO9JVxRA==} + engines: {node: '>=20.0.0'} dependencies: - deep-equal: 1.0.1 - http-errors: 1.8.1 + '@types/node': 20.19.1 + '@types/whatwg-mimetype': 3.0.2 + whatwg-mimetype: 3.0.0 + dev: true - http-errors@1.6.3: + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} dependencies: - depd: 1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.0 - statuses: 1.5.0 + function-bind: 1.1.2 + dev: false - http-errors@1.8.1: - dependencies: - depd: 1.1.2 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 1.5.0 - toidentifier: 1.0.1 + /hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + dev: false - http-errors@2.0.0: + /http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} dependencies: depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 - statuses: 2.0.1 + statuses: 2.0.2 toidentifier: 1.0.1 + dev: false - http-shutdown@1.2.2: {} + /http-shutdown@1.2.2: + resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: false - https-proxy-agent@7.0.6(supports-color@9.4.0): + /https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} dependencies: - agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.4.0) + agent-base: 7.1.4 + debug: 4.4.3 transitivePeerDependencies: - supports-color + dev: false - httpxy@0.1.6: {} + /httpxy@0.1.7: + resolution: {integrity: sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ==} + dev: false - human-signals@4.3.1: {} - - human-signals@5.0.0: {} - - ieee754@1.2.1: {} - - ignore@5.3.2: {} + /human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + dev: false - ignore@7.0.3: {} + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false - image-meta@0.2.1: {} + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false - impound@0.2.0(rollup@4.30.1): - dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - mlly: 1.7.4 - pathe: 1.1.2 - unenv: 1.10.0 - unplugin: 1.16.1 - transitivePeerDependencies: - - rollup + /ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} - index-to-position@0.1.2: {} + /image-meta@0.2.2: + resolution: {integrity: sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA==} + dev: false - inflight@1.0.6: + /impound@1.0.0: + resolution: {integrity: sha512-8lAJ+1Arw2sMaZ9HE2ZmL5zOcMnt18s6+7Xqgq2aUVy4P1nlzAyPtzCDxsk51KVFwHEEdc6OWvUyqwHwhRYaug==} dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.3: {} + exsolve: 1.0.8 + mocked-exports: 0.1.1 + pathe: 2.0.3 + unplugin: 2.3.11 + unplugin-utils: 0.2.4 + dev: false - inherits@2.0.4: {} + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false - ini@1.3.8: {} + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@4.1.1: {} + /ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: false - ioredis@5.4.2: + /ioredis@5.9.2: + resolution: {integrity: sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==} + engines: {node: '>=12.22.0'} dependencies: - '@ioredis/commands': 1.2.0 + '@ioredis/commands': 1.5.0 cluster-key-slot: 1.1.2 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.3 denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -6323,434 +5992,682 @@ snapshots: standard-as-callback: 2.1.0 transitivePeerDependencies: - supports-color + dev: false - iron-webcrypto@1.2.1: {} - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 + /iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} - is-core-module@2.16.1: + /is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} dependencies: hasown: 2.0.2 + dev: false - is-docker@2.2.1: {} - - is-docker@3.0.0: {} + /is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: false - is-extglob@2.1.1: {} + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: false - is-fullwidth-code-point@3.0.0: {} + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: false - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.3 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} - is-glob@4.0.3: + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 + dev: false - is-inside-container@1.0.0: + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true dependencies: is-docker: 3.0.0 + dev: false - is-installed-globally@1.0.0: + /is-installed-globally@1.0.0: + resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} + engines: {node: '>=18'} dependencies: global-directory: 4.0.1 is-path-inside: 4.0.0 + dev: false - is-module@1.0.0: {} - - is-number@7.0.0: {} + /is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + dev: false - is-path-inside@4.0.0: {} + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: false - is-reference@1.2.1: - dependencies: - '@types/estree': 1.0.6 + /is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + dev: false - is-regex@1.2.1: + /is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} dependencies: - call-bound: 1.0.3 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 + '@types/estree': 1.0.8 + dev: false - is-ssh@1.4.0: + /is-ssh@1.4.1: + resolution: {integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==} dependencies: - protocols: 2.0.1 + protocols: 2.0.2 + dev: false - is-stream@2.0.1: {} + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: false - is-stream@3.0.0: {} + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false - is-what@4.1.16: {} + /is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + dev: false - is-wsl@2.2.0: + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} dependencies: is-docker: 2.2.1 + dev: false - is-wsl@3.1.0: + /is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} dependencies: is-inside-container: 1.0.0 + dev: false - is64bit@2.0.0: + /is64bit@2.0.0: + resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==} + engines: {node: '>=18'} dependencies: system-architecture: 0.1.0 + dev: false + + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: false + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + /isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + dev: false - isarray@1.0.0: {} + /jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 - isexe@2.0.0: {} + /jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true - jackspeak@3.4.3: + /js-beautify@1.15.4: + resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} + engines: {node: '>=14'} + hasBin: true dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 10.5.0 + js-cookie: 3.0.5 + nopt: 7.2.1 + dev: true - jiti@1.21.7: {} + /js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + dev: true - jiti@2.4.2: {} + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: false - js-levenshtein@1.1.6: {} + /js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - js-tokens@4.0.0: {} + /jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + dev: false - js-tokens@9.0.1: {} + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: false - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: false - jsesc@3.1.0: {} + /kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + dev: false - json-schema-traverse@1.0.0: {} + /klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} - json5@2.2.3: {} + /knitwork@1.3.0: + resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} - jsonfile@6.1.0: + /launch-editor@2.12.0: + resolution: {integrity: sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==} dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 + picocolors: 1.1.1 + shell-quote: 1.8.3 + dev: false - keygrip@1.1.0: + /lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} dependencies: - tsscmp: 1.0.6 - - kleur@3.0.3: {} + readable-stream: 2.3.8 + dev: false - klona@2.0.6: {} + /lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true - knitwork@1.2.0: {} + /lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true - koa-compose@4.1.0: {} + /lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true - koa-convert@2.0.0: - dependencies: - co: 4.6.0 - koa-compose: 4.1.0 + /lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true - koa-send@5.0.1: - dependencies: - debug: 4.4.0(supports-color@9.4.0) - http-errors: 1.8.1 - resolve-path: 1.4.0 - transitivePeerDependencies: - - supports-color + /lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true - koa-static@5.0.0: - dependencies: - debug: 3.2.7 - koa-send: 5.0.1 - transitivePeerDependencies: - - supports-color + /lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true - koa@2.15.3: - dependencies: - accepts: 1.3.8 - cache-content-type: 1.0.1 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookies: 0.9.1 - debug: 4.4.0(supports-color@9.4.0) - delegates: 1.0.0 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - fresh: 0.5.2 - http-assert: 1.5.0 - http-errors: 1.8.1 - is-generator-function: 1.1.0 - koa-compose: 4.1.0 - koa-convert: 2.0.0 - on-finished: 2.4.1 - only: 0.0.2 - parseurl: 1.3.3 - statuses: 1.5.0 - type-is: 1.6.18 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color + /lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true - kolorist@1.8.0: {} + /lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true - launch-editor@2.9.1: - dependencies: - picocolors: 1.1.1 - shell-quote: 1.8.2 + /lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true - lazystream@1.0.1: - dependencies: - readable-stream: 2.3.8 + /lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true - lilconfig@3.1.3: {} + /lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true - lines-and-columns@1.2.4: {} + /lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 2.0.3 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + dev: false + + /lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + dev: false - listhen@1.9.0: + /listhen@1.9.0: + resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==} + hasBin: true dependencies: - '@parcel/watcher': 2.5.0 - '@parcel/watcher-wasm': 2.5.0 + '@parcel/watcher': 2.5.4 + '@parcel/watcher-wasm': 2.5.4 citty: 0.1.6 clipboardy: 4.0.0 - consola: 3.4.0 - crossws: 0.3.1 + consola: 3.4.2 + crossws: 0.3.5 defu: 6.1.4 - get-port-please: 3.1.2 - h3: 1.13.1 + get-port-please: 3.2.0 + h3: 1.15.4 http-shutdown: 1.2.2 - jiti: 2.4.2 - mlly: 1.7.4 - node-forge: 1.3.1 + jiti: 2.6.1 + mlly: 1.8.0 + node-forge: 1.3.3 pathe: 1.1.2 - std-env: 3.8.0 - ufo: 1.5.4 + std-env: 3.10.0 + ufo: 1.6.1 untun: 0.1.3 uqr: 0.1.2 + dev: false - local-pkg@0.5.1: + /local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} dependencies: - mlly: 1.7.4 - pkg-types: 1.3.1 + mlly: 1.8.0 + pkg-types: 2.3.0 + quansync: 0.2.11 - local-pkg@1.0.0: - dependencies: - mlly: 1.7.4 - pkg-types: 1.3.1 + /lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: false - lodash.defaults@4.2.0: {} + /lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + dev: false + + /lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: false - lodash.isarguments@3.1.0: {} + /lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + dev: false - lodash.memoize@4.1.2: {} + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false - lodash.uniq@4.5.0: {} + /loupe@3.1.4: + resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==} + dev: true - lodash@4.17.21: {} + /lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@10.4.3: {} + /lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + engines: {node: 20 || >=22} + dev: false - lru-cache@5.1.1: + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: yallist: 3.1.1 + dev: false - magic-string-ast@0.7.0: + /lucide-vue-next@0.524.0(vue@3.5.27): + resolution: {integrity: sha512-Ea+g23VY0pS6hTscAKxflu2yHpoSloN8ouIguLfXggUCnYjo0ymPEfxcWmXzSJyUE5+otZF5R7yALX8F46jSEA==} + peerDependencies: + vue: '>=3.0.1' dependencies: - magic-string: 0.30.17 + vue: 3.5.27(typescript@5.9.3) + dev: false - magic-string@0.30.17: + /magic-regexp@0.10.0: + resolution: {integrity: sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==} dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 + estree-walker: 3.0.3 + magic-string: 0.30.21 + mlly: 1.8.0 + regexp-tree: 0.1.27 + type-level-regexp: 0.1.17 + ufo: 1.6.1 + unplugin: 2.3.10 + dev: false - magicast@0.3.5: + /magic-string-ast@1.0.3: + resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==} + engines: {node: '>=20.19.0'} dependencies: - '@babel/parser': 7.26.5 - '@babel/types': 7.26.5 - source-map-js: 1.2.1 + magic-string: 0.30.21 + dev: false - math-intrinsics@1.1.0: {} - - mdn-data@2.0.28: {} + /magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 - mdn-data@2.0.30: {} + /magicast@0.5.1: + resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + source-map-js: 1.2.1 - media-typer@0.3.0: {} + /mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + dev: false - merge-stream@2.0.0: {} + /mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + dev: false - merge2@1.4.1: {} + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: false - methods@1.1.2: {} + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: false - micromatch@4.0.8: + /micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} dependencies: braces: 3.0.3 picomatch: 2.3.1 + dev: false - mime-db@1.52.0: {} + /mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + dev: false - mime-types@2.1.35: + /mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} dependencies: - mime-db: 1.52.0 - - mime@1.6.0: {} - - mime@3.0.0: {} + mime-db: 1.54.0 + dev: false - mime@4.0.6: {} + /mime@4.1.0: + resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} + engines: {node: '>=16'} + hasBin: true + dev: false - mimic-fn@4.0.0: {} + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: false - mimic-response@3.1.0: {} + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false - minimatch@3.1.2: + /minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} dependencies: - brace-expansion: 1.1.11 + '@isaacs/brace-expansion': 5.0.0 + dev: false - minimatch@5.1.6: + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 + dev: false - minimatch@9.0.5: + /minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 + dev: true - minimist@1.2.8: {} - - minipass@3.3.6: + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} + brace-expansion: 2.0.1 - minipass@7.1.2: {} + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: false - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} - minizlib@3.0.1: + /minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} dependencies: minipass: 7.1.2 - rimraf: 5.0.10 - - mitt@3.0.1: {} - - mkdirp-classic@0.5.3: {} - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 + dev: false - mkdirp@1.0.4: {} + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + dev: false - mkdirp@3.0.1: {} + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false - mlly@1.7.4: + /mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} dependencies: - acorn: 8.14.0 - pathe: 2.0.2 + acorn: 8.15.0 + pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.5.4 + ufo: 1.6.1 + + /mocked-exports@0.1.1: + resolution: {integrity: sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==} + dev: false - mrmime@2.0.0: {} + /mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + dev: false - ms@2.0.0: {} + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - ms@2.1.3: {} + /muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + dev: false - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 + /nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true - nanoid@3.3.8: {} + /nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: false - nanoid@5.0.9: {} + /nanoid@5.1.5: + resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} + engines: {node: ^18 || >=20} + hasBin: true + dev: false - nanotar@0.1.1: {} + /nanotar@0.2.0: + resolution: {integrity: sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==} + dev: false - napi-build-utils@1.0.2: {} + /napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + dev: false - negotiator@0.6.3: {} + /napi-wasm@1.1.3: + resolution: {integrity: sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg==} + dev: false - nitropack@2.10.4(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1))(typescript@5.7.3): + /nitropack@2.13.1(better-sqlite3@12.11.1)(drizzle-orm@0.45.1): + resolution: {integrity: sha512-2dDj89C4wC2uzG7guF3CnyG+zwkZosPEp7FFBGHB3AJo11AywOolWhyQJFHDzve8COvGxJaqscye9wW2IrUsNw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + xml2js: ^0.6.2 + peerDependenciesMeta: + xml2js: + optional: true dependencies: - '@cloudflare/kv-asset-handler': 0.3.4 - '@netlify/functions': 2.8.2 - '@rollup/plugin-alias': 5.1.1(rollup@4.30.1) - '@rollup/plugin-commonjs': 28.0.2(rollup@4.30.1) - '@rollup/plugin-inject': 5.0.5(rollup@4.30.1) - '@rollup/plugin-json': 6.1.0(rollup@4.30.1) - '@rollup/plugin-node-resolve': 15.3.1(rollup@4.30.1) - '@rollup/plugin-replace': 6.0.2(rollup@4.30.1) - '@rollup/plugin-terser': 0.4.4(rollup@4.30.1) - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - '@types/http-proxy': 1.17.15 - '@vercel/nft': 0.27.10(rollup@4.30.1) + '@cloudflare/kv-asset-handler': 0.4.2 + '@rollup/plugin-alias': 6.0.0(rollup@4.55.2) + '@rollup/plugin-commonjs': 29.0.0(rollup@4.55.2) + '@rollup/plugin-inject': 5.0.5(rollup@4.55.2) + '@rollup/plugin-json': 6.1.0(rollup@4.55.2) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.55.2) + '@rollup/plugin-replace': 6.0.3(rollup@4.55.2) + '@rollup/plugin-terser': 0.4.4(rollup@4.55.2) + '@vercel/nft': 1.2.0(rollup@4.55.2) archiver: 7.0.1 - c12: 2.0.1(magicast@0.3.5) - chokidar: 3.6.0 + c12: 3.3.3(magicast@0.5.1) + chokidar: 5.0.0 citty: 0.1.6 - compatx: 0.1.8 - confbox: 0.1.8 - consola: 3.4.0 - cookie-es: 1.2.2 - croner: 9.0.0 - crossws: 0.3.1 - db0: 0.2.1(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1)) + compatx: 0.2.0 + confbox: 0.2.2 + consola: 3.4.2 + cookie-es: 2.0.0 + croner: 9.1.0 + crossws: 0.3.5 + db0: 0.3.4(better-sqlite3@12.11.1)(drizzle-orm@0.45.1) defu: 6.1.4 - destr: 2.0.3 - dot-prop: 9.0.0 - esbuild: 0.24.2 + destr: 2.0.5 + dot-prop: 10.1.0 + esbuild: 0.27.2 escape-string-regexp: 5.0.0 etag: 1.8.1 - fs-extra: 11.3.0 - globby: 14.0.2 + exsolve: 1.0.8 + globby: 16.1.0 gzip-size: 7.0.0 - h3: 1.13.1 + h3: 1.15.5 hookable: 5.5.3 - httpxy: 0.1.6 - ioredis: 5.4.2 - jiti: 2.4.2 + httpxy: 0.1.7 + ioredis: 5.9.2 + jiti: 2.6.1 klona: 2.0.6 - knitwork: 1.2.0 + knitwork: 1.3.0 listhen: 1.9.0 - magic-string: 0.30.17 - magicast: 0.3.5 - mime: 4.0.6 - mlly: 1.7.4 - node-fetch-native: 1.6.4 - ofetch: 1.4.1 - ohash: 1.1.4 - openapi-typescript: 7.5.2(typescript@5.7.3) - pathe: 1.1.2 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 - pretty-bytes: 6.1.1 + magic-string: 0.30.21 + magicast: 0.5.1 + mime: 4.1.0 + mlly: 1.8.0 + node-fetch-native: 1.6.7 + node-mock-http: 1.0.4 + ofetch: 1.5.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + pretty-bytes: 7.1.0 radix3: 1.1.2 - rollup: 4.30.1 - rollup-plugin-visualizer: 5.14.0(rollup@4.30.1) + rollup: 4.55.2 + rollup-plugin-visualizer: 6.0.5(rollup@4.55.2) scule: 1.3.0 - semver: 7.6.3 + semver: 7.7.3 serve-placeholder: 2.0.2 - serve-static: 1.16.2 - std-env: 3.8.0 - ufo: 1.5.4 + serve-static: 2.2.1 + source-map: 0.7.6 + std-env: 3.10.0 + ufo: 1.6.3 + ultrahtml: 1.6.0 uncrypto: 0.1.3 - unctx: 2.4.1 - unenv: 1.10.0 - unimport: 3.14.6(rollup@4.30.1) - unstorage: 1.14.4(db0@0.2.1(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1)))(ioredis@5.4.2) - untyped: 1.5.2 - unwasm: 0.3.9 + unctx: 2.5.0 + unenv: 2.0.0-rc.24 + unimport: 5.6.0 + unplugin-utils: 0.3.1 + unstorage: 1.17.4(db0@0.3.4)(ioredis@5.9.2) + untyped: 2.0.0 + unwasm: 0.5.3 + youch: 4.1.0-beta.13 + youch-core: 0.3.3 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -6766,125 +6683,177 @@ snapshots: - '@planetscale/database' - '@upstash/redis' - '@vercel/blob' + - '@vercel/functions' - '@vercel/kv' - aws4fetch + - bare-abort-controller - better-sqlite3 - drizzle-orm - encoding - idb-keyval - mysql2 + - react-native-b4a - rolldown + - sqlite3 - supports-color - - typescript - uploadthing + dev: false - node-abi@3.73.0: + /node-abi@3.74.0: + resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==} + engines: {node: '>=10'} dependencies: - semver: 7.6.3 + semver: 7.7.3 + dev: false - node-addon-api@7.1.1: {} + /node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + dev: false - node-fetch-native@1.6.4: {} + /node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - node-fetch@2.7.0: + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true dependencies: whatwg-url: 5.0.0 + dev: false + + /node-forge@1.3.3: + resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} + engines: {node: '>= 6.13.0'} + dev: false - node-forge@1.3.1: {} + /node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + dev: false - node-gyp-build@4.8.4: {} + /node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} - node-releases@2.0.19: {} + /node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + dev: false - nopt@8.0.0: + /nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true dependencies: abbrev: 2.0.0 + dev: true - normalize-path@3.0.0: {} + /nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + dependencies: + abbrev: 3.0.1 + dev: false - normalize-range@0.1.2: {} + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: false - npm-run-path@4.0.1: + /npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: - path-key: 3.1.1 + path-key: 4.0.0 + dev: false - npm-run-path@5.3.0: + /npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} dependencies: path-key: 4.0.0 + unicorn-magic: 0.3.0 + dev: false - nth-check@2.1.1: + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: boolbase: 1.0.0 + dev: false - nuxt@3.15.2(@parcel/watcher@2.5.0)(@types/node@22.10.7)(better-sqlite3@11.8.1)(db0@0.2.1(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1)))(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1))(ioredis@5.4.2)(magicast@0.3.5)(rollup@4.30.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(yaml@2.7.0): + /nuxt@4.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@vue/compiler-sfc@3.5.42)(better-sqlite3@12.11.1)(drizzle-orm@0.45.1)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.6): + resolution: {integrity: sha512-n6oYFikgLEb70J4+K19jAzfx4exZcRSRX7yZn09P5qlf2Z59VNOBqNmaZO5ObzvyGUZ308SZfL629/Q2v2FVjw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@parcel/watcher': ^2.1.0 + '@types/node': '>=18.12.0' + peerDependenciesMeta: + '@parcel/watcher': + optional: true + '@types/node': + optional: true dependencies: - '@nuxt/cli': 3.20.0(magicast@0.3.5) - '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 1.7.0(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) - '@nuxt/kit': 3.15.2(magicast@0.3.5)(rollup@4.30.1) - '@nuxt/schema': 3.15.2 - '@nuxt/telemetry': 2.6.4(magicast@0.3.5)(rollup@4.30.1) - '@nuxt/vite-builder': 3.15.2(@types/node@22.10.7)(magicast@0.3.5)(rollup@4.30.1)(terser@5.37.0)(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0) - '@unhead/dom': 1.11.18 - '@unhead/shared': 1.11.18 - '@unhead/ssr': 1.11.18 - '@unhead/vue': 1.11.18(vue@3.5.13(typescript@5.7.3)) - '@vue/shared': 3.5.13 - acorn: 8.14.0 - c12: 2.0.1(magicast@0.3.5) - chokidar: 4.0.3 - compatx: 0.1.8 - consola: 3.4.0 - cookie-es: 1.2.2 + '@dxup/nuxt': 0.2.2 + '@nuxt/cli': 3.32.0 + '@nuxt/devtools': 3.1.1(vite@7.3.6)(vue@3.5.27) + '@nuxt/kit': 4.2.2(magicast@0.5.1) + '@nuxt/nitro-server': 4.2.2(better-sqlite3@12.11.1)(drizzle-orm@0.45.1)(nuxt@4.2.2)(typescript@5.9.3) + '@nuxt/schema': 4.2.2 + '@nuxt/telemetry': 2.6.6 + '@nuxt/vite-builder': 4.2.2(nuxt@4.2.2)(tsx@4.21.0)(typescript@5.9.3)(vue@3.5.27) + '@unhead/vue': 2.0.19(vue@3.5.27) + '@vue/shared': 3.5.25 + c12: 3.3.2(magicast@0.5.1) + chokidar: 5.0.0 + compatx: 0.2.0 + consola: 3.4.2 + cookie-es: 2.0.0 defu: 6.1.4 - destr: 2.0.3 - devalue: 5.1.1 + destr: 2.0.5 + devalue: 5.6.2 errx: 0.1.0 - esbuild: 0.24.2 escape-string-regexp: 5.0.0 - estree-walker: 3.0.3 - globby: 14.0.2 - h3: 1.13.1 + exsolve: 1.0.8 + h3: 1.15.4 hookable: 5.5.3 - ignore: 7.0.3 - impound: 0.2.0(rollup@4.30.1) - jiti: 2.4.2 + ignore: 7.0.5 + impound: 1.0.0 + jiti: 2.6.1 klona: 2.0.6 - knitwork: 1.2.0 - magic-string: 0.30.17 - mlly: 1.7.4 - nanotar: 0.1.1 - nitropack: 2.10.4(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1))(typescript@5.7.3) - nypm: 0.4.1 - ofetch: 1.4.1 - ohash: 1.1.4 - pathe: 2.0.2 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.0 + nanotar: 0.2.0 + nypm: 0.6.2 + ofetch: 1.5.1 + ohash: 2.0.11 + on-change: 6.0.1 + oxc-minify: 0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + oxc-parser: 0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + oxc-transform: 0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + oxc-walker: 0.6.0(oxc-parser@0.102.0) + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 radix3: 1.1.2 scule: 1.3.0 - semver: 7.6.3 - std-env: 3.8.0 - strip-literal: 3.0.0 - tinyglobby: 0.2.10 - ufo: 1.5.4 - ultrahtml: 1.5.3 + semver: 7.7.3 + std-env: 3.10.0 + tinyglobby: 0.2.15 + ufo: 1.6.1 + ultrahtml: 1.6.0 uncrypto: 0.1.3 unctx: 2.4.1 - unenv: 1.10.0 - unhead: 1.11.18 - unimport: 3.14.6(rollup@4.30.1) - unplugin: 2.1.2 - unplugin-vue-router: 0.10.9(rollup@4.30.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) - unstorage: 1.14.4(db0@0.2.1(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1)))(ioredis@5.4.2) - untyped: 1.5.2 - vue: 3.5.13(typescript@5.7.3) - vue-bundle-renderer: 2.1.1 - vue-devtools-stub: 0.1.0 - vue-router: 4.5.0(vue@3.5.13(typescript@5.7.3)) - optionalDependencies: - '@parcel/watcher': 2.5.0 - '@types/node': 22.10.7 + unimport: 5.5.0 + unplugin: 2.3.11 + unplugin-vue-router: 0.19.2(@vue/compiler-sfc@3.5.42)(vue-router@4.6.4)(vue@3.5.27) + untyped: 2.0.0 + vue: 3.5.27(typescript@5.9.3) + vue-router: 4.6.4(vue@3.5.27) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -6896,15 +6865,23 @@ snapshots: - '@capacitor/preferences' - '@deno/kv' - '@electric-sql/pglite' + - '@emnapi/core' + - '@emnapi/runtime' - '@libsql/client' - '@netlify/blobs' - '@planetscale/database' - '@upstash/redis' - '@vercel/blob' + - '@vercel/functions' - '@vercel/kv' + - '@vitejs/devtools' + - '@vue/compiler-sfc' - aws4fetch + - bare-abort-controller - better-sqlite3 - bufferutil + - cac + - commander - db0 - drizzle-orm - encoding @@ -6917,10 +6894,13 @@ snapshots: - meow - mysql2 - optionator + - oxlint + - react-native-b4a - rolldown - rollup - sass - sass-embedded + - sqlite3 - stylelint - stylus - sugarss @@ -6936,418 +6916,779 @@ snapshots: - vue-tsc - xml2js - yaml + dev: false - nypm@0.3.12: + /nypm@0.6.2: + resolution: {integrity: sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true dependencies: citty: 0.1.6 - consola: 3.4.0 - execa: 8.0.1 - pathe: 1.1.2 - pkg-types: 1.3.1 - ufo: 1.5.4 - - nypm@0.4.1: + consola: 3.4.2 + pathe: 2.0.3 + pkg-types: 2.3.0 + tinyexec: 1.0.2 + dev: false + + /nypm@0.6.4: + resolution: {integrity: sha512-1TvCKjZyyklN+JJj2TS3P4uSQEInrM/HkkuSXsEzm1ApPgBffOn8gFguNnZf07r/1X6vlryfIqMUkJKQMzlZiw==} + engines: {node: '>=18'} + hasBin: true dependencies: - citty: 0.1.6 - consola: 3.4.0 - pathe: 1.1.2 - pkg-types: 1.3.1 - tinyexec: 0.3.2 - ufo: 1.5.4 + citty: 0.2.0 + pathe: 2.0.3 + tinyexec: 1.0.2 - object-assign@4.1.1: {} + /obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + dev: false - object-hash@3.0.0: {} - - ofetch@1.4.1: + /ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} dependencies: - destr: 2.0.3 - node-fetch-native: 1.6.4 - ufo: 1.5.4 + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.1 + + /ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - ohash@1.1.4: {} + /on-change@6.0.1: + resolution: {integrity: sha512-P7o0hkMahOhjb1niG28vLNAXsJrRcfpJvYWcTmPt/Tf4xedcF2PA1E9++N1tufY8/vIsaiJgHhjQp53hJCe+zw==} + engines: {node: '>=20'} + dev: false - on-finished@2.4.1: + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} dependencies: ee-first: 1.1.1 + dev: false - once@1.4.0: + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 + dev: false - onetime@6.0.0: + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} dependencies: mimic-fn: 4.0.0 + dev: false - only@0.0.2: {} - - open@10.1.0: + /open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} dependencies: default-browser: 5.2.1 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 - is-wsl: 3.1.0 + wsl-utils: 0.1.0 + dev: false - open@7.4.2: - dependencies: - is-docker: 2.2.1 - is-wsl: 2.2.0 - - open@8.4.2: + /open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} dependencies: define-lazy-prop: 2.0.0 is-docker: 2.2.1 is-wsl: 2.2.0 + dev: false + + /oxc-minify@0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3): + resolution: {integrity: sha512-FphAHDyTCNepQbiQTSyWFMbNc9zdUmj1WBsoLwvZhWm7rEe/IeIKYKRhy75lWOjwFsi5/i4Qucq43hgs3n2Exw==} + engines: {node: ^20.19.0 || >=22.12.0} + optionalDependencies: + '@oxc-minify/binding-android-arm64': 0.102.0 + '@oxc-minify/binding-darwin-arm64': 0.102.0 + '@oxc-minify/binding-darwin-x64': 0.102.0 + '@oxc-minify/binding-freebsd-x64': 0.102.0 + '@oxc-minify/binding-linux-arm-gnueabihf': 0.102.0 + '@oxc-minify/binding-linux-arm64-gnu': 0.102.0 + '@oxc-minify/binding-linux-arm64-musl': 0.102.0 + '@oxc-minify/binding-linux-riscv64-gnu': 0.102.0 + '@oxc-minify/binding-linux-s390x-gnu': 0.102.0 + '@oxc-minify/binding-linux-x64-gnu': 0.102.0 + '@oxc-minify/binding-linux-x64-musl': 0.102.0 + '@oxc-minify/binding-openharmony-arm64': 0.102.0 + '@oxc-minify/binding-wasm32-wasi': 0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + '@oxc-minify/binding-win32-arm64-msvc': 0.102.0 + '@oxc-minify/binding-win32-x64-msvc': 0.102.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + dev: false - openapi-typescript@7.5.2(typescript@5.7.3): + /oxc-parser@0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3): + resolution: {integrity: sha512-xMiyHgr2FZsphQ12ZCsXRvSYzmKXCm1ejmyG4GDZIiKOmhyt5iKtWq0klOfFsEQ6jcgbwrUdwcCVYzr1F+h5og==} + engines: {node: ^20.19.0 || >=22.12.0} dependencies: - '@redocly/openapi-core': 1.27.2(supports-color@9.4.0) - ansi-colors: 4.1.3 - change-case: 5.4.4 - parse-json: 8.1.0 - supports-color: 9.4.0 - typescript: 5.7.3 - yargs-parser: 21.1.1 + '@oxc-project/types': 0.102.0 + optionalDependencies: + '@oxc-parser/binding-android-arm64': 0.102.0 + '@oxc-parser/binding-darwin-arm64': 0.102.0 + '@oxc-parser/binding-darwin-x64': 0.102.0 + '@oxc-parser/binding-freebsd-x64': 0.102.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.102.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.102.0 + '@oxc-parser/binding-linux-arm64-musl': 0.102.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.102.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.102.0 + '@oxc-parser/binding-linux-x64-gnu': 0.102.0 + '@oxc-parser/binding-linux-x64-musl': 0.102.0 + '@oxc-parser/binding-openharmony-arm64': 0.102.0 + '@oxc-parser/binding-wasm32-wasi': 0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + '@oxc-parser/binding-win32-arm64-msvc': 0.102.0 + '@oxc-parser/binding-win32-x64-msvc': 0.102.0 transitivePeerDependencies: - - encoding + - '@emnapi/core' + - '@emnapi/runtime' + dev: false + + /oxc-transform@0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3): + resolution: {integrity: sha512-MR5ohiBS6/kvxRpmUZ3LIDTTJBEC4xLAEZXfYr7vrA0eP7WHewQaNQPFDgT4Bee89TdmVQ5ZKrifGwxLjSyHHw==} + engines: {node: ^20.19.0 || >=22.12.0} + optionalDependencies: + '@oxc-transform/binding-android-arm64': 0.102.0 + '@oxc-transform/binding-darwin-arm64': 0.102.0 + '@oxc-transform/binding-darwin-x64': 0.102.0 + '@oxc-transform/binding-freebsd-x64': 0.102.0 + '@oxc-transform/binding-linux-arm-gnueabihf': 0.102.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.102.0 + '@oxc-transform/binding-linux-arm64-musl': 0.102.0 + '@oxc-transform/binding-linux-riscv64-gnu': 0.102.0 + '@oxc-transform/binding-linux-s390x-gnu': 0.102.0 + '@oxc-transform/binding-linux-x64-gnu': 0.102.0 + '@oxc-transform/binding-linux-x64-musl': 0.102.0 + '@oxc-transform/binding-openharmony-arm64': 0.102.0 + '@oxc-transform/binding-wasm32-wasi': 0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + '@oxc-transform/binding-win32-arm64-msvc': 0.102.0 + '@oxc-transform/binding-win32-x64-msvc': 0.102.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + dev: false + + /oxc-walker@0.6.0(oxc-parser@0.102.0): + resolution: {integrity: sha512-BA3hlxq5+Sgzp7TCQF52XDXCK5mwoIZuIuxv/+JuuTzOs2RXkLqWZgZ69d8pJDDjnL7wiREZTWHBzFp/UWH88Q==} + peerDependencies: + oxc-parser: '>=0.98.0' + dependencies: + magic-regexp: 0.10.0 + oxc-parser: 0.102.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + dev: false + + /package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + /package-manager-detector@1.1.0: + resolution: {integrity: sha512-Y8f9qUlBzW8qauJjd/eu6jlpJZsuPJm2ZAV0cDVd420o4EdpH5RPdoCv+60/TdJflGatr4sDfpAL6ArWZbM5tA==} + dev: false + + /pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + dev: false + + /parse-path@7.0.1: + resolution: {integrity: sha512-6ReLMptznuuOEzLoGEa+I1oWRSj2Zna5jLWC+l6zlfAI4dbbSaIES29ThzuPkbhNahT65dWzfoZEO6cfJw2Ksg==} + dependencies: + protocols: 2.0.2 + dev: false + + /parse-url@9.2.0: + resolution: {integrity: sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==} + engines: {node: '>=14.13.0'} + dependencies: + '@types/parse-path': 7.0.3 + parse-path: 7.0.1 + dev: false + + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: false - package-json-from-dist@1.0.1: {} + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: false - package-manager-detector@0.2.8: {} + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} - packrup@0.1.2: {} + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: false - parse-git-config@3.0.0: - dependencies: - git-config-path: 2.0.0 - ini: 1.3.8 + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: false - parse-json@8.1.0: + /path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} dependencies: - '@babel/code-frame': 7.26.2 - index-to-position: 0.1.2 - type-fest: 4.32.0 + lru-cache: 10.4.3 + minipass: 7.1.2 - parse-path@7.0.0: + /path-scurry@2.0.1: + resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} + engines: {node: 20 || >=22} dependencies: - protocols: 2.0.1 + lru-cache: 11.2.4 + minipass: 7.1.2 + dev: false - parse-url@9.2.0: - dependencies: - '@types/parse-path': 7.0.3 - parse-path: 7.0.0 + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: false + + /pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - parseurl@1.3.3: {} + /pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + dev: true - path-is-absolute@1.0.1: {} + /perfect-debounce@2.0.0: + resolution: {integrity: sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==} - path-key@3.1.1: {} + /pg-cloudflare@1.4.0: + resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} + requiresBuild: true + dev: false + optional: true - path-key@4.0.0: {} + /pg-connection-string@2.14.0: + resolution: {integrity: sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==} + dev: false - path-parse@1.0.7: {} + /pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} - path-scurry@1.11.1: + /pg-pool@3.14.0(pg@8.23.0): + resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} + peerDependencies: + pg: '>=8.0' dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - - path-to-regexp@6.3.0: {} + pg: 8.23.0 + dev: false - path-type@5.0.0: {} + /pg-protocol@1.13.0: + resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} - pathe@1.1.2: {} + /pg-protocol@1.16.0: + resolution: {integrity: sha512-sILXutLVjCLjcDuOmvhX5e2Z4cS5qG/6Bu3VkpFwdf/633ElGLpEh9bgmuI5I4sqKqkifQiGyiCcx1HdtrK7tg==} + dev: false - pathe@2.0.2: {} + /pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.1 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 - perfect-debounce@1.0.0: {} + /pg@8.23.0: + resolution: {integrity: sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + pg-connection-string: 2.14.0 + pg-pool: 3.14.0(pg@8.23.0) + pg-protocol: 1.16.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.4.0 + dev: false - picocolors@1.1.1: {} + /pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.2.0 + dev: false - picomatch@2.3.1: {} + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@4.0.2: {} + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: false - pify@2.3.0: {} + /picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} - pirates@4.0.6: {} + /picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + dev: false - pkg-types@1.3.1: + /pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} dependencies: confbox: 0.1.8 - mlly: 1.7.4 - pathe: 2.0.2 + mlly: 1.8.0 + pathe: 2.0.3 - pluralize@8.0.0: {} - - portfinder@1.0.32: + /pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} dependencies: - async: 2.6.4 - debug: 3.2.7 - mkdirp: 0.5.6 - transitivePeerDependencies: - - supports-color + confbox: 0.2.2 + exsolve: 1.0.8 + pathe: 2.0.3 + + /playwright-core@1.57.0: + resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} + engines: {node: '>=18'} + hasBin: true + dev: true - postcss-calc@10.1.0(postcss@8.5.1): + /postcss-calc@10.1.1(postcss@8.5.6): + resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==} + engines: {node: ^18.12 || ^20.9 || >=22.0} + peerDependencies: + postcss: ^8.4.38 dependencies: - postcss: 8.5.1 - postcss-selector-parser: 7.0.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 + dev: false - postcss-colormin@7.0.2(postcss@8.5.1): + /postcss-colormin@7.0.5(postcss@8.5.6): + resolution: {integrity: sha512-ekIBP/nwzRWhEMmIxHHbXHcMdzd1HIUzBECaj5KEdLz9DVP2HzT065sEhvOx1dkLjYW7jyD0CngThx6bpFi2fA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - browserslist: 4.24.4 + browserslist: 4.28.1 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-convert-values@7.0.4(postcss@8.5.1): + /postcss-convert-values@7.0.8(postcss@8.5.6): + resolution: {integrity: sha512-+XNKuPfkHTCEo499VzLMYn94TiL3r9YqRE3Ty+jP7UX4qjewUONey1t7CG21lrlTLN07GtGM8MqFVp86D4uKJg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - browserslist: 4.24.4 - postcss: 8.5.1 + browserslist: 4.28.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-discard-comments@7.0.3(postcss@8.5.1): - dependencies: - postcss: 8.5.1 - postcss-selector-parser: 6.1.2 - - postcss-discard-duplicates@7.0.1(postcss@8.5.1): - dependencies: - postcss: 8.5.1 - - postcss-discard-empty@7.0.0(postcss@8.5.1): - dependencies: - postcss: 8.5.1 - - postcss-discard-overridden@7.0.0(postcss@8.5.1): + /postcss-discard-comments@7.0.5(postcss@8.5.6): + resolution: {integrity: sha512-IR2Eja8WfYgN5n32vEGSctVQ1+JARfu4UH8M7bgGh1bC+xI/obsPJXaBpQF7MAByvgwZinhpHpdrmXtvVVlKcQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + dev: false - postcss-import@15.1.0(postcss@8.5.1): + /postcss-discard-duplicates@7.0.2(postcss@8.5.6): + resolution: {integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.10 + postcss: 8.5.6 + dev: false - postcss-js@4.0.1(postcss@8.5.1): + /postcss-discard-empty@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - camelcase-css: 2.0.1 - postcss: 8.5.1 + postcss: 8.5.6 + dev: false - postcss-load-config@4.0.2(postcss@8.5.1): + /postcss-discard-overridden@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - lilconfig: 3.1.3 - yaml: 2.7.0 - optionalDependencies: - postcss: 8.5.1 + postcss: 8.5.6 + dev: false - postcss-merge-longhand@7.0.4(postcss@8.5.1): + /postcss-merge-longhand@7.0.5(postcss@8.5.6): + resolution: {integrity: sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - stylehacks: 7.0.4(postcss@8.5.1) + stylehacks: 7.0.7(postcss@8.5.6) + dev: false - postcss-merge-rules@7.0.4(postcss@8.5.1): + /postcss-merge-rules@7.0.7(postcss@8.5.6): + resolution: {integrity: sha512-njWJrd/Ms6XViwowaaCc+/vqhPG3SmXn725AGrnl+BgTuRPEacjiLEaGq16J6XirMJbtKkTwnt67SS+e2WGoew==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - browserslist: 4.24.4 + browserslist: 4.28.1 caniuse-api: 3.0.0 - cssnano-utils: 5.0.0(postcss@8.5.1) - postcss: 8.5.1 - postcss-selector-parser: 6.1.2 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + dev: false - postcss-minify-font-values@7.0.0(postcss@8.5.1): + /postcss-minify-font-values@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-minify-gradients@7.0.0(postcss@8.5.1): + /postcss-minify-gradients@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: colord: 2.9.3 - cssnano-utils: 5.0.0(postcss@8.5.1) - postcss: 8.5.1 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-minify-params@7.0.2(postcss@8.5.1): + /postcss-minify-params@7.0.5(postcss@8.5.6): + resolution: {integrity: sha512-FGK9ky02h6Ighn3UihsyeAH5XmLEE2MSGH5Tc4tXMFtEDx7B+zTG6hD/+/cT+fbF7PbYojsmmWjyTwFwW1JKQQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - browserslist: 4.24.4 - cssnano-utils: 5.0.0(postcss@8.5.1) - postcss: 8.5.1 + browserslist: 4.28.1 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-minify-selectors@7.0.4(postcss@8.5.1): + /postcss-minify-selectors@7.0.5(postcss@8.5.6): + resolution: {integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: cssesc: 3.0.0 - postcss: 8.5.1 - postcss-selector-parser: 6.1.2 - - postcss-nested@6.2.0(postcss@8.5.1): - dependencies: - postcss: 8.5.1 - postcss-selector-parser: 6.1.2 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + dev: false - postcss-nesting@13.0.1(postcss@8.5.1): - dependencies: - '@csstools/selector-resolve-nested': 3.0.0(postcss-selector-parser@7.0.0) - '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.0.0) - postcss: 8.5.1 - postcss-selector-parser: 7.0.0 - - postcss-normalize-charset@7.0.0(postcss@8.5.1): + /postcss-normalize-charset@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 + dev: false - postcss-normalize-display-values@7.0.0(postcss@8.5.1): + /postcss-normalize-display-values@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-normalize-positions@7.0.0(postcss@8.5.1): + /postcss-normalize-positions@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-normalize-repeat-style@7.0.0(postcss@8.5.1): + /postcss-normalize-repeat-style@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-normalize-string@7.0.0(postcss@8.5.1): + /postcss-normalize-string@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-normalize-timing-functions@7.0.0(postcss@8.5.1): + /postcss-normalize-timing-functions@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-normalize-unicode@7.0.2(postcss@8.5.1): + /postcss-normalize-unicode@7.0.5(postcss@8.5.6): + resolution: {integrity: sha512-X6BBwiRxVaFHrb2WyBMddIeB5HBjJcAaUHyhLrM2FsxSq5TFqcHSsK7Zu1otag+o0ZphQGJewGH1tAyrD0zX1Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - browserslist: 4.24.4 - postcss: 8.5.1 + browserslist: 4.28.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-normalize-url@7.0.0(postcss@8.5.1): + /postcss-normalize-url@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-normalize-whitespace@7.0.0(postcss@8.5.1): + /postcss-normalize-whitespace@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-ordered-values@7.0.1(postcss@8.5.1): + /postcss-ordered-values@7.0.2(postcss@8.5.6): + resolution: {integrity: sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - cssnano-utils: 5.0.0(postcss@8.5.1) - postcss: 8.5.1 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-reduce-initial@7.0.2(postcss@8.5.1): + /postcss-reduce-initial@7.0.5(postcss@8.5.6): + resolution: {integrity: sha512-RHagHLidG8hTZcnr4FpyMB2jtgd/OcyAazjMhoy5qmWJOx1uxKh4ntk0Pb46ajKM0rkf32lRH4C8c9qQiPR6IA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - browserslist: 4.24.4 + browserslist: 4.28.1 caniuse-api: 3.0.0 - postcss: 8.5.1 + postcss: 8.5.6 + dev: false - postcss-reduce-transforms@7.0.0(postcss@8.5.1): + /postcss-reduce-transforms@7.0.1(postcss@8.5.6): + resolution: {integrity: sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 + dev: false - postcss-selector-parser@6.1.2: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss-selector-parser@7.0.0: + /postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 + dev: false - postcss-svgo@7.0.1(postcss@8.5.1): + /postcss-svgo@7.1.0(postcss@8.5.6): + resolution: {integrity: sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==} + engines: {node: ^18.12.0 || ^20.9.0 || >= 18} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - svgo: 3.3.2 + svgo: 4.0.0 + dev: false - postcss-unique-selectors@7.0.3(postcss@8.5.1): + /postcss-unique-selectors@7.0.4(postcss@8.5.6): + resolution: {integrity: sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - postcss: 8.5.1 - postcss-selector-parser: 6.1.2 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + dev: false + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: false - postcss-value-parser@4.2.0: {} + /postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: false - postcss@8.5.1: + /postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.8 + nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - prebuild-install@7.1.2: + /postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + /postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + /postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + /postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + dependencies: + xtend: 4.0.2 + + /prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true dependencies: detect-libc: 2.0.3 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 mkdirp-classic: 0.5.3 - napi-build-utils: 1.0.2 - node-abi: 3.73.0 + napi-build-utils: 2.0.0 + node-abi: 3.74.0 pump: 3.0.2 rc: 1.2.8 simple-get: 4.0.1 tar-fs: 2.1.2 tunnel-agent: 0.6.0 + dev: false + + /prettier@3.7.3: + resolution: {integrity: sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==} + engines: {node: '>=14'} + hasBin: true + dev: true - pretty-bytes@6.1.1: {} + /pretty-bytes@7.1.0: + resolution: {integrity: sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==} + engines: {node: '>=20'} + dev: false - process-nextick-args@2.0.1: {} + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: false - process@0.11.10: {} + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false - prompts@2.4.2: + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} dependencies: kleur: 3.0.3 sisteransi: 1.0.5 + dev: false + + /proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: true - protocols@2.0.1: {} + /protocols@2.0.2: + resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} + dev: false - pump@3.0.2: + /pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} dependencies: end-of-stream: 1.4.4 once: 1.4.0 + dev: false - queue-microtask@1.2.3: {} + /quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} - queue-tick@1.0.1: {} + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: false - radix3@1.1.2: {} + /radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} - randombytes@2.1.0: + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 + dev: false - range-parser@1.2.1: {} + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: false - rc9@2.1.2: + /rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} dependencies: defu: 6.1.4 - destr: 2.0.3 + destr: 2.0.5 - rc@1.2.8: + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true dependencies: deep-extend: 0.6.0 ini: 1.3.8 minimist: 1.2.8 strip-json-comments: 2.0.1 + dev: false - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - - readable-stream@2.3.8: + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} dependencies: core-util-is: 1.0.3 inherits: 2.0.4 @@ -7356,616 +7697,1179 @@ snapshots: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 + dev: false - readable-stream@3.6.2: + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 + dev: false - readable-stream@4.7.0: + /readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: abort-controller: 3.0.0 buffer: 6.0.3 events: 3.3.0 process: 0.11.10 string_decoder: 1.3.0 + dev: false - readdir-glob@1.1.3: + /readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} dependencies: minimatch: 5.1.6 + dev: false - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 + /readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + dev: false - readdirp@4.1.1: {} + /readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} - redis-errors@1.2.0: {} + /redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + dev: false - redis-parser@3.0.0: + /redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} dependencies: redis-errors: 1.2.0 + dev: false - replace-in-file@6.3.5: - dependencies: - chalk: 4.1.2 - glob: 7.2.3 - yargs: 17.7.2 - - require-directory@2.1.1: {} + /regexp-tree@0.1.27: + resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} + hasBin: true + dev: false - require-from-string@2.0.2: {} + /reka-ui@2.6.1(typescript@5.9.3)(vue@3.5.27): + resolution: {integrity: sha512-XK7cJDQoNuGXfCNzBBo/81Yg/OgjPwvbabnlzXG2VsdSgNsT6iIkuPBPr+C0Shs+3bb0x0lbPvgQAhMSCKm5Ww==} + peerDependencies: + vue: '>= 3.2.0' + dependencies: + '@floating-ui/dom': 1.6.13 + '@floating-ui/vue': 1.1.6(vue@3.5.27) + '@internationalized/date': 3.10.1 + '@internationalized/number': 3.6.0 + '@tanstack/vue-virtual': 3.13.6(vue@3.5.27) + '@vueuse/core': 12.8.2(typescript@5.9.3) + '@vueuse/shared': 12.8.2(typescript@5.9.3) + aria-hidden: 1.2.4 + defu: 6.1.4 + ohash: 2.0.11 + vue: 3.5.27(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + - typescript + dev: false - resolve-from@5.0.0: {} + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: false - resolve-path@1.4.0: - dependencies: - http-errors: 1.6.3 - path-is-absolute: 1.0.1 + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: false - resolve-pkg-maps@1.0.0: {} + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.10: + /resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + dev: false - reusify@1.0.4: {} + /restructure@3.0.2: + resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} + dev: false - rfdc@1.4.1: {} + /reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: false - rimraf@5.0.10: - dependencies: - glob: 10.4.5 + /rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + dev: false - rollup-plugin-visualizer@5.14.0(rollup@4.30.1): + /rollup-plugin-visualizer@6.0.5(rollup@4.55.2): + resolution: {integrity: sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x || ^1.0.0-beta + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true dependencies: open: 8.4.2 - picomatch: 4.0.2 - source-map: 0.7.4 + picomatch: 4.0.3 + rollup: 4.55.2 + source-map: 0.7.6 yargs: 17.7.2 + dev: false + + /rollup@4.53.2: + resolution: {integrity: sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.2 + '@rollup/rollup-android-arm64': 4.53.2 + '@rollup/rollup-darwin-arm64': 4.53.2 + '@rollup/rollup-darwin-x64': 4.53.2 + '@rollup/rollup-freebsd-arm64': 4.53.2 + '@rollup/rollup-freebsd-x64': 4.53.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.2 + '@rollup/rollup-linux-arm-musleabihf': 4.53.2 + '@rollup/rollup-linux-arm64-gnu': 4.53.2 + '@rollup/rollup-linux-arm64-musl': 4.53.2 + '@rollup/rollup-linux-loong64-gnu': 4.53.2 + '@rollup/rollup-linux-ppc64-gnu': 4.53.2 + '@rollup/rollup-linux-riscv64-gnu': 4.53.2 + '@rollup/rollup-linux-riscv64-musl': 4.53.2 + '@rollup/rollup-linux-s390x-gnu': 4.53.2 + '@rollup/rollup-linux-x64-gnu': 4.53.2 + '@rollup/rollup-linux-x64-musl': 4.53.2 + '@rollup/rollup-openharmony-arm64': 4.53.2 + '@rollup/rollup-win32-arm64-msvc': 4.53.2 + '@rollup/rollup-win32-ia32-msvc': 4.53.2 + '@rollup/rollup-win32-x64-gnu': 4.53.2 + '@rollup/rollup-win32-x64-msvc': 4.53.2 + fsevents: 2.3.3 + dev: true + + /rollup@4.55.2: + resolution: {integrity: sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.8 optionalDependencies: - rollup: 4.30.1 + '@rollup/rollup-android-arm-eabi': 4.55.2 + '@rollup/rollup-android-arm64': 4.55.2 + '@rollup/rollup-darwin-arm64': 4.55.2 + '@rollup/rollup-darwin-x64': 4.55.2 + '@rollup/rollup-freebsd-arm64': 4.55.2 + '@rollup/rollup-freebsd-x64': 4.55.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.2 + '@rollup/rollup-linux-arm-musleabihf': 4.55.2 + '@rollup/rollup-linux-arm64-gnu': 4.55.2 + '@rollup/rollup-linux-arm64-musl': 4.55.2 + '@rollup/rollup-linux-loong64-gnu': 4.55.2 + '@rollup/rollup-linux-loong64-musl': 4.55.2 + '@rollup/rollup-linux-ppc64-gnu': 4.55.2 + '@rollup/rollup-linux-ppc64-musl': 4.55.2 + '@rollup/rollup-linux-riscv64-gnu': 4.55.2 + '@rollup/rollup-linux-riscv64-musl': 4.55.2 + '@rollup/rollup-linux-s390x-gnu': 4.55.2 + '@rollup/rollup-linux-x64-gnu': 4.55.2 + '@rollup/rollup-linux-x64-musl': 4.55.2 + '@rollup/rollup-openbsd-x64': 4.55.2 + '@rollup/rollup-openharmony-arm64': 4.55.2 + '@rollup/rollup-win32-arm64-msvc': 4.55.2 + '@rollup/rollup-win32-ia32-msvc': 4.55.2 + '@rollup/rollup-win32-x64-gnu': 4.55.2 + '@rollup/rollup-win32-x64-msvc': 4.55.2 + fsevents: 2.3.3 + dev: false - rollup@4.30.1: + /rollup@4.63.0: + resolution: {integrity: sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.30.1 - '@rollup/rollup-android-arm64': 4.30.1 - '@rollup/rollup-darwin-arm64': 4.30.1 - '@rollup/rollup-darwin-x64': 4.30.1 - '@rollup/rollup-freebsd-arm64': 4.30.1 - '@rollup/rollup-freebsd-x64': 4.30.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.30.1 - '@rollup/rollup-linux-arm-musleabihf': 4.30.1 - '@rollup/rollup-linux-arm64-gnu': 4.30.1 - '@rollup/rollup-linux-arm64-musl': 4.30.1 - '@rollup/rollup-linux-loongarch64-gnu': 4.30.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.30.1 - '@rollup/rollup-linux-riscv64-gnu': 4.30.1 - '@rollup/rollup-linux-s390x-gnu': 4.30.1 - '@rollup/rollup-linux-x64-gnu': 4.30.1 - '@rollup/rollup-linux-x64-musl': 4.30.1 - '@rollup/rollup-win32-arm64-msvc': 4.30.1 - '@rollup/rollup-win32-ia32-msvc': 4.30.1 - '@rollup/rollup-win32-x64-msvc': 4.30.1 + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.63.0 + '@rollup/rollup-android-arm64': 4.63.0 + '@rollup/rollup-darwin-arm64': 4.63.0 + '@rollup/rollup-darwin-x64': 4.63.0 + '@rollup/rollup-freebsd-arm64': 4.63.0 + '@rollup/rollup-freebsd-x64': 4.63.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.0 + '@rollup/rollup-linux-arm-musleabihf': 4.63.0 + '@rollup/rollup-linux-arm64-gnu': 4.63.0 + '@rollup/rollup-linux-arm64-musl': 4.63.0 + '@rollup/rollup-linux-loong64-gnu': 4.63.0 + '@rollup/rollup-linux-loong64-musl': 4.63.0 + '@rollup/rollup-linux-ppc64-gnu': 4.63.0 + '@rollup/rollup-linux-ppc64-musl': 4.63.0 + '@rollup/rollup-linux-riscv64-gnu': 4.63.0 + '@rollup/rollup-linux-riscv64-musl': 4.63.0 + '@rollup/rollup-linux-s390x-gnu': 4.63.0 + '@rollup/rollup-linux-x64-gnu': 4.63.0 + '@rollup/rollup-linux-x64-musl': 4.63.0 + '@rollup/rollup-openbsd-x64': 4.63.0 + '@rollup/rollup-openharmony-arm64': 4.63.0 + '@rollup/rollup-win32-arm64-msvc': 4.63.0 + '@rollup/rollup-win32-ia32-msvc': 4.63.0 + '@rollup/rollup-win32-x64-gnu': 4.63.0 + '@rollup/rollup-win32-x64-msvc': 4.63.0 fsevents: 2.3.3 + dev: false + + /rou3@0.9.2: + resolution: {integrity: sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==} + dev: true - run-applescript@7.0.0: {} + /run-applescript@7.0.0: + resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} + engines: {node: '>=18'} + dev: false - run-parallel@1.2.0: + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 + dev: false + + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: false - safe-buffer@5.1.2: {} + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false - safe-buffer@5.2.1: {} + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.3 - es-errors: 1.3.0 - is-regex: 1.2.1 + /sax@1.4.4: + resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + engines: {node: '>=11.0.0'} + dev: false - scule@1.3.0: {} + /scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} - semver@6.3.1: {} + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: false - semver@7.6.3: {} + /semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true - send@0.19.0: + /send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 + debug: 4.4.3 + encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 - statuses: 2.0.1 + statuses: 2.0.2 transitivePeerDependencies: - supports-color + dev: false - serialize-javascript@6.0.2: + /serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} dependencies: randombytes: 2.1.0 + dev: false - serve-placeholder@2.0.2: + /seroval@1.4.2: + resolution: {integrity: sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==} + engines: {node: '>=10'} + dev: false + + /serve-placeholder@2.0.2: + resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==} dependencies: defu: 6.1.4 + dev: false - serve-static@1.16.2: + /serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.19.0 + send: 1.2.1 transitivePeerDependencies: - supports-color + dev: false - setprototypeof@1.1.0: {} - - setprototypeof@1.2.0: {} + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false - shebang-command@2.0.0: + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - shebang-regex@3.0.0: {} + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} - shell-quote@1.8.2: {} + /shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + dev: false - signal-exit@3.0.7: {} + /siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true - signal-exit@4.1.0: {} + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} - simple-concat@1.0.1: {} + /simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + dev: false - simple-get@4.0.1: + /simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} dependencies: decompress-response: 6.0.0 once: 1.4.0 simple-concat: 1.0.1 + dev: false - simple-git@3.27.0: + /simple-git@3.30.0: + resolution: {integrity: sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==} dependencies: '@kwsites/file-exists': 1.1.1 '@kwsites/promise-deferred': 1.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.3 transitivePeerDependencies: - supports-color + dev: false - sirv@3.0.0: + /sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} dependencies: '@polka/url': 1.0.0-next.28 - mrmime: 2.0.0 + mrmime: 2.0.1 totalist: 3.0.1 + dev: false - sisteransi@1.0.5: {} + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - slash@5.1.0: {} + /slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + dev: false - smob@1.5.0: {} + /smob@1.5.0: + resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + dev: false - source-map-js@1.2.1: {} + /source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} - source-map-support@0.5.21: + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - source-map@0.6.1: {} + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + /source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + dev: false + + /speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + dev: false - source-map@0.7.4: {} + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + + /srvx@0.10.1: + resolution: {integrity: sha512-A//xtfak4eESMWWydSRFUVvCTQbSwivnGCEf8YGPe2eHU0+Z6znfUTCPF0a7oV3sObSOcrXHlL6Bs9vVctfXdg==} + engines: {node: '>=20.16.0'} + hasBin: true + dev: false - speakingurl@14.0.1: {} + /srvx@0.12.7: + resolution: {integrity: sha512-PIaq1pDGg3EU2OGSN3pzRfYVu9MJDzLdojlGN6E3lvhAdxqn/lNMJFMA1xGA38jYkBb0V9xw02QEVVMDb0PExA==} + engines: {node: '>=20.16.0'} + hasBin: true + dev: true - standard-as-callback@2.1.0: {} + /stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true - statuses@1.5.0: {} + /standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + dev: false - statuses@2.0.1: {} + /statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + dev: false - std-env@3.8.0: {} + /std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - streamx@2.21.1: + /streamx@2.23.0: + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} dependencies: + events-universal: 1.0.1 fast-fifo: 1.3.2 - queue-tick: 1.0.1 text-decoder: 1.2.3 - optionalDependencies: - bare-events: 2.5.4 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + dev: false - string-width@4.2.3: + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@5.1.2: + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 - string_decoder@1.1.1: + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: safe-buffer: 5.1.2 + dev: false - string_decoder@1.3.0: + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 + dev: false - strip-ansi@6.0.1: + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.0: + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} dependencies: ansi-regex: 6.1.0 - strip-final-newline@3.0.0: {} - - strip-json-comments@2.0.1: {} + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: false - strip-literal@2.1.1: - dependencies: - js-tokens: 9.0.1 + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: false - strip-literal@3.0.0: + /strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} dependencies: js-tokens: 9.0.1 - stylehacks@7.0.4(postcss@8.5.1): - dependencies: - browserslist: 4.24.4 - postcss: 8.5.1 - postcss-selector-parser: 6.1.2 + /structured-clone-es@1.0.0: + resolution: {integrity: sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==} + dev: false - sucrase@3.35.0: + /stylehacks@7.0.7(postcss@8.5.6): + resolution: {integrity: sha512-bJkD0JkEtbRrMFtwgpJyBbFIwfDDONQ1Ov3sDLZQP8HuJ73kBOyx66H4bOcAbVWmnfLdvQ0AJwXxOMkpujcO6g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 dependencies: - '@jridgewell/gen-mapping': 0.3.8 - commander: 4.1.1 - glob: 10.4.5 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.6 - ts-interface-checker: 0.1.13 + browserslist: 4.28.1 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + dev: false - superjson@2.2.2: + /superjson@2.2.2: + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + engines: {node: '>=16'} dependencies: copy-anything: 3.0.5 + dev: false - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@9.4.0: {} - - supports-preserve-symlinks-flag@1.0.0: {} + /supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + dev: false - svg-tags@1.0.0: {} + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: false - svgo@3.3.2: + /svgo@4.0.0: + resolution: {integrity: sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==} + engines: {node: '>=16'} + hasBin: true dependencies: - '@trysound/sax': 0.2.0 - commander: 7.2.0 - css-select: 5.1.0 - css-tree: 2.3.1 - css-what: 6.1.0 + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.1.0 + css-what: 6.2.2 csso: 5.0.5 picocolors: 1.1.1 + sax: 1.4.4 + dev: false - system-architecture@0.1.0: {} + /system-architecture@0.1.0: + resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} + engines: {node: '>=18'} + dev: false - tailwind-config-viewer@2.0.4(tailwindcss@3.4.17): - dependencies: - '@koa/router': 12.0.2 - commander: 6.2.1 - fs-extra: 9.1.0 - koa: 2.15.3 - koa-static: 5.0.0 - open: 7.4.2 - portfinder: 1.0.32 - replace-in-file: 6.3.5 - tailwindcss: 3.4.17 - transitivePeerDependencies: - - supports-color + /tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + dev: false - tailwindcss@3.4.17: - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.6.0 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.3 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.7 - lilconfig: 3.1.3 - micromatch: 4.0.8 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.1 - postcss-import: 15.1.0(postcss@8.5.1) - postcss-js: 4.0.1(postcss@8.5.1) - postcss-load-config: 4.0.2(postcss@8.5.1) - postcss-nested: 6.2.0(postcss@8.5.1) - postcss-selector-parser: 6.1.2 - resolve: 1.22.10 - sucrase: 3.35.0 - transitivePeerDependencies: - - ts-node + /tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + dev: false - tapable@2.2.1: {} + /tailwindcss@4.1.17: + resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + dev: false - tar-fs@2.1.2: + /tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + dev: false + + /tar-fs@2.1.2: + resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 pump: 3.0.2 tar-stream: 2.2.0 + dev: false - tar-stream@2.2.0: + /tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} dependencies: bl: 4.1.0 end-of-stream: 1.4.4 fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 + dev: false - tar-stream@3.1.7: + /tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} dependencies: - b4a: 1.6.7 + b4a: 1.7.3 fast-fifo: 1.3.2 - streamx: 2.21.1 - - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + dev: false - tar@7.4.3: + /tar@7.5.4: + resolution: {integrity: sha512-AN04xbWGrSTDmVwlI4/GTlIIwMFk/XEv7uL8aa57zuvRy6s4hdBed+lVq2fAZ89XDa7Us3ANXcE3Tvqvja1kTA==} + engines: {node: '>=18'} dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 minipass: 7.1.2 - minizlib: 3.0.1 - mkdirp: 3.0.1 + minizlib: 3.1.0 yallist: 5.0.0 + dev: false - terser@5.37.0: + /terser@5.46.0: + resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} + engines: {node: '>=10'} + hasBin: true dependencies: - '@jridgewell/source-map': 0.3.6 - acorn: 8.14.0 + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 + dev: false - text-decoder@1.2.3: + /text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} dependencies: - b4a: 1.6.7 + b4a: 1.7.3 + transitivePeerDependencies: + - react-native-b4a + dev: false + + /tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + dev: false + + /tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + dev: false + + /tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + dev: true + + /tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + dev: true - thenify-all@1.6.0: + /tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + /tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} dependencies: - thenify: 3.3.1 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 - thenify@3.3.1: + /tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} dependencies: - any-promise: 1.3.0 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + dev: false - tiny-invariant@1.3.3: {} + /tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + dev: true - tinyexec@0.3.2: {} + /tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + dev: true - tinyglobby@0.2.10: - dependencies: - fdir: 6.4.3(picomatch@4.0.2) - picomatch: 4.0.2 + /tinyspy@4.0.3: + resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + engines: {node: '>=14.0.0'} + dev: true - to-regex-range@5.0.1: + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 + dev: false - toidentifier@1.0.1: {} + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false - totalist@3.0.1: {} + /totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + dev: false - tr46@0.0.3: {} + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false - ts-interface-checker@0.1.13: {} + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + requiresBuild: true + dev: false - tsscmp@1.0.6: {} + /tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + esbuild: 0.27.0 + get-tsconfig: 4.10.0 + optionalDependencies: + fsevents: 2.3.3 - tunnel-agent@0.6.0: + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} dependencies: safe-buffer: 5.2.1 + dev: false - type-fest@0.21.3: {} - - type-fest@4.32.0: {} + /tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + dev: false - type-is@1.6.18: + /type-fest@5.4.1: + resolution: {integrity: sha512-xygQcmneDyzsEuKZrFbRMne5HDqMs++aFzefrJTgEIKjQ3rekM+RPfFCVq2Gp1VIDqddoYeppCj4Pcb+RZW0GQ==} + engines: {node: '>=20'} dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 + tagged-tag: 1.0.0 + dev: false + + /type-level-regexp@0.1.17: + resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==} + dev: false + + /typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true - typescript@5.7.3: {} + /ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - ufo@1.5.4: {} + /ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + dev: false - ultrahtml@1.5.3: {} + /ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + dev: false + + /uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - uncrypto@0.1.3: {} + /unctx@2.4.1: + resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==} + dependencies: + acorn: 8.15.0 + estree-walker: 3.0.3 + magic-string: 0.30.21 + unplugin: 2.3.11 + dev: false - unctx@2.4.1: + /unctx@2.5.0: + resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==} dependencies: - acorn: 8.14.0 + acorn: 8.15.0 estree-walker: 3.0.3 - magic-string: 0.30.17 - unplugin: 2.1.2 + magic-string: 0.30.21 + unplugin: 2.3.11 - undici-types@6.20.0: {} + /undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - unenv@1.10.0: + /unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} dependencies: - consola: 3.4.0 - defu: 6.1.4 - mime: 3.0.0 - node-fetch-native: 1.6.4 - pathe: 1.1.2 + pathe: 2.0.3 + dev: false - unhead@1.11.18: + /unhead@2.0.19: + resolution: {integrity: sha512-gEEjkV11Aj+rBnY6wnRfsFtF2RxKOLaPN4i+Gx3UhBxnszvV6ApSNZbGk7WKyy/lErQ6ekPN63qdFL7sa1leow==} dependencies: - '@unhead/dom': 1.11.18 - '@unhead/schema': 1.11.18 - '@unhead/shared': 1.11.18 hookable: 5.5.3 + dev: false + + /unicode-properties@1.4.1: + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + dev: false - unicorn-magic@0.1.0: {} + /unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + dev: false + + /unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + dev: false + + /unicorn-magic@0.4.0: + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} + engines: {node: '>=20'} + dev: false - unimport@3.14.6(rollup@4.30.1): + /unifont@0.6.0: + resolution: {integrity: sha512-5Fx50fFQMQL5aeHyWnZX9122sSLckcDvcfFiBf3QYeHa7a1MKJooUy52b67moi2MJYkrfo/TWY+CoLdr/w0tTA==} dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - acorn: 8.14.0 + css-tree: 3.1.0 + ofetch: 1.5.1 + ohash: 2.0.11 + dev: false + + /unimport@5.5.0: + resolution: {integrity: sha512-/JpWMG9s1nBSlXJAQ8EREFTFy3oy6USFd8T6AoBaw1q2GGcF4R9yp3ofg32UODZlYEO5VD0EWE1RpI9XDWyPYg==} + engines: {node: '>=18.12.0'} + dependencies: + acorn: 8.15.0 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 - fast-glob: 3.3.3 - local-pkg: 1.0.0 - magic-string: 0.30.17 - mlly: 1.7.4 - pathe: 2.0.2 - picomatch: 4.0.2 - pkg-types: 1.3.1 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.0 + pathe: 2.0.3 + picomatch: 4.0.3 + pkg-types: 2.3.0 scule: 1.3.0 - strip-literal: 2.1.1 - unplugin: 1.16.1 - transitivePeerDependencies: - - rollup + strip-literal: 3.1.0 + tinyglobby: 0.2.15 + unplugin: 2.3.11 + unplugin-utils: 0.3.1 + dev: false + + /unimport@5.6.0: + resolution: {integrity: sha512-8rqAmtJV8o60x46kBAJKtHpJDJWkA2xcBqWKPI14MgUb05o1pnpnCnXSxedUXyeq7p8fR5g3pTo2BaswZ9lD9A==} + engines: {node: '>=18.12.0'} + dependencies: + acorn: 8.15.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.0 + pathe: 2.0.3 + picomatch: 4.0.3 + pkg-types: 2.3.0 + scule: 1.3.0 + strip-literal: 3.1.0 + tinyglobby: 0.2.15 + unplugin: 2.3.11 + unplugin-utils: 0.3.1 + dev: false + + /unplugin-utils@0.2.4: + resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==} + engines: {node: '>=18.12.0'} + dependencies: + pathe: 2.0.3 + picomatch: 4.0.3 + dev: false - universalify@2.0.1: {} + /unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} + dependencies: + pathe: 2.0.3 + picomatch: 4.0.3 + dev: false - unplugin-vue-router@0.10.9(rollup@4.30.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)): + /unplugin-vue-router@0.19.2(@vue/compiler-sfc@3.5.42)(vue-router@4.6.4)(vue@3.5.27): + resolution: {integrity: sha512-u5dgLBarxE5cyDK/hzJGfpCTLIAyiTXGlo85COuD4Nssj6G7NxS+i9mhCWz/1p/ud1eMwdcUbTXehQe41jYZUA==} + peerDependencies: + '@vue/compiler-sfc': ^3.5.17 + vue-router: ^4.6.0 + peerDependenciesMeta: + vue-router: + optional: true dependencies: - '@babel/types': 7.26.5 - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - '@vue-macros/common': 1.16.0(vue@3.5.13(typescript@5.7.3)) - ast-walker-scope: 0.6.2 - chokidar: 3.6.0 - fast-glob: 3.3.3 + '@babel/generator': 7.28.6 + '@vue-macros/common': 3.1.2(vue@3.5.27) + '@vue/compiler-sfc': 3.5.42 + '@vue/language-core': 3.2.2 + ast-walker-scope: 0.8.3 + chokidar: 5.0.0 json5: 2.2.3 - local-pkg: 0.5.1 - magic-string: 0.30.17 - mlly: 1.7.4 - pathe: 1.1.2 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.0 + muggle-string: 0.4.1 + pathe: 2.0.3 + picomatch: 4.0.3 scule: 1.3.0 - unplugin: 2.0.0-beta.1 - yaml: 2.7.0 - optionalDependencies: - vue-router: 4.5.0(vue@3.5.13(typescript@5.7.3)) + tinyglobby: 0.2.15 + unplugin: 2.3.11 + unplugin-utils: 0.3.1 + vue-router: 4.6.4(vue@3.5.27) + yaml: 2.8.2 transitivePeerDependencies: - - rollup - vue + dev: false - unplugin@1.16.1: - dependencies: - acorn: 8.14.0 - webpack-virtual-modules: 0.6.2 - - unplugin@2.0.0-beta.1: + /unplugin@2.3.10: + resolution: {integrity: sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==} + engines: {node: '>=18.12.0'} dependencies: - acorn: 8.14.0 + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 + dev: false - unplugin@2.1.2: + /unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} dependencies: - acorn: 8.14.0 + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 - unstorage@1.14.4(db0@0.2.1(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1)))(ioredis@5.4.2): + /unstorage@1.17.2: + resolution: {integrity: sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6.0.3 || ^7.0.0 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1.0.1 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true dependencies: anymatch: 3.1.3 - chokidar: 3.6.0 - destr: 2.0.3 - h3: 1.13.1 + chokidar: 4.0.3 + destr: 2.0.5 + h3: 1.15.4 lru-cache: 10.4.3 - node-fetch-native: 1.6.4 - ofetch: 1.4.1 - ufo: 1.5.4 - optionalDependencies: - db0: 0.2.1(better-sqlite3@11.8.1)(drizzle-orm@0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1)) - ioredis: 5.4.2 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.1 + dev: false - untun@0.1.3: + /unstorage@1.17.4(db0@0.3.4)(ioredis@5.9.2): + resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + db0: 0.3.4(better-sqlite3@12.11.1)(drizzle-orm@0.45.1) + destr: 2.0.5 + h3: 1.15.5 + ioredis: 5.9.2 + lru-cache: 11.2.4 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.3 + dev: false + + /untun@0.1.3: + resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} + hasBin: true dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 pathe: 1.1.2 + dev: false - untyped@1.5.2: + /untyped@2.0.0: + resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} + hasBin: true dependencies: - '@babel/core': 7.26.0 - '@babel/standalone': 7.26.6 - '@babel/types': 7.26.5 citty: 0.1.6 defu: 6.1.4 - jiti: 2.4.2 - knitwork: 1.2.0 + jiti: 2.6.1 + knitwork: 1.3.0 scule: 1.3.0 - transitivePeerDependencies: - - supports-color - unwasm@0.3.9: + /unwasm@0.5.3: + resolution: {integrity: sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==} dependencies: - knitwork: 1.2.0 - magic-string: 0.30.17 - mlly: 1.7.4 - pathe: 1.1.2 - pkg-types: 1.3.1 - unplugin: 1.16.1 + exsolve: 1.0.8 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.0 + pathe: 2.0.3 + pkg-types: 2.3.0 + dev: false - update-browserslist-db@1.1.2(browserslist@4.24.4): + /update-browserslist-db@1.2.3(browserslist@4.28.1): + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' dependencies: - browserslist: 4.24.4 + browserslist: 4.28.1 escalade: 3.2.0 picocolors: 1.1.1 + dev: false - uqr@0.1.2: {} - - uri-js-replace@1.0.1: {} - - urlpattern-polyfill@8.0.2: {} + /uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + dev: false - util-deprecate@1.0.2: {} + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false - vary@1.1.2: {} + /vite-dev-rpc@1.1.0(vite@7.3.6): + resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 + dependencies: + birpc: 2.8.0 + vite: 7.3.6(tsx@4.21.0) + vite-hot-client: 2.1.0(vite@7.3.6) + dev: false - vite-hot-client@0.2.4(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): + /vite-hot-client@2.1.0(vite@7.3.6): + resolution: {integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==} + peerDependencies: + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 dependencies: - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite: 7.3.6(tsx@4.21.0) + dev: false - vite-node@2.1.8(@types/node@22.10.7)(terser@5.37.0): + /vite-node@3.2.4(tsx@4.21.0): + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@9.4.0) - es-module-lexer: 1.6.0 - pathe: 1.1.2 - vite: 5.4.11(@types/node@22.10.7)(terser@5.37.0) + debug: 4.4.1 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.2.6(tsx@4.21.0) transitivePeerDependencies: - '@types/node' + - jiti - less - lightningcss - sass @@ -7974,174 +8878,554 @@ snapshots: - sugarss - supports-color - terser + - tsx + - yaml + dev: true - vite-plugin-checker@0.8.0(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): + /vite-node@5.3.0(jiti@2.6.1)(tsx@4.21.0): + resolution: {integrity: sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true dependencies: - '@babel/code-frame': 7.26.2 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - chokidar: 3.6.0 - commander: 8.3.0 - fast-glob: 3.3.3 - fs-extra: 11.3.0 - npm-run-path: 4.0.1 - strip-ansi: 6.0.1 - tiny-invariant: 1.3.3 - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - vscode-languageclient: 7.0.0 - vscode-languageserver: 7.0.0 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.0.8 - optionalDependencies: - typescript: 5.7.3 + cac: 6.7.14 + es-module-lexer: 2.0.0 + obug: 2.1.1 + pathe: 2.0.3 + vite: 7.3.1(jiti@2.6.1)(tsx@4.21.0) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + dev: false - vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.2(magicast@0.3.5)(rollup@4.30.1))(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): + /vite-plugin-checker@0.12.0(typescript@5.9.3)(vite@7.3.1): + resolution: {integrity: sha512-CmdZdDOGss7kdQwv73UyVgLPv0FVYe5czAgnmRX2oKljgEvSrODGuClaV3PDR2+3ou7N/OKGauDDBjy2MB07Rg==} + engines: {node: '>=16.11'} + peerDependencies: + '@biomejs/biome': '>=1.7' + eslint: '>=9.39.1' + meow: ^13.2.0 + optionator: ^0.9.4 + oxlint: '>=1' + stylelint: '>=16' + typescript: '*' + vite: '>=5.4.21' + vls: '*' + vti: '*' + vue-tsc: ~2.2.10 || ^3.0.0 + peerDependenciesMeta: + '@biomejs/biome': + optional: true + eslint: + optional: true + meow: + optional: true + optionator: + optional: true + oxlint: + optional: true + stylelint: + optional: true + typescript: + optional: true + vls: + optional: true + vti: + optional: true + vue-tsc: + optional: true dependencies: - '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - debug: 4.4.0(supports-color@9.4.0) - error-stack-parser-es: 0.1.5 - fs-extra: 11.3.0 - open: 10.1.0 - perfect-debounce: 1.0.0 + '@babel/code-frame': 7.28.6 + chokidar: 4.0.3 + npm-run-path: 6.0.0 picocolors: 1.1.1 - sirv: 3.0.0 - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - optionalDependencies: - '@nuxt/kit': 3.15.2(magicast@0.3.5)(rollup@4.30.1) + picomatch: 4.0.3 + tiny-invariant: 1.3.3 + tinyglobby: 0.2.15 + typescript: 5.9.3 + vite: 7.3.1(jiti@2.6.1)(tsx@4.21.0) + vscode-uri: 3.1.0 + dev: false + + /vite-plugin-inspect@11.3.3(@nuxt/kit@4.2.2)(vite@7.3.6): + resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} + engines: {node: '>=14'} + peerDependencies: + '@nuxt/kit': '*' + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + dependencies: + '@nuxt/kit': 4.2.2(magicast@0.5.1) + ansis: 4.1.0 + debug: 4.4.3 + error-stack-parser-es: 1.0.5 + ohash: 2.0.11 + open: 10.2.0 + perfect-debounce: 2.0.0 + sirv: 3.0.2 + unplugin-utils: 0.3.1 + vite: 7.3.6(tsx@4.21.0) + vite-dev-rpc: 1.1.0(vite@7.3.6) transitivePeerDependencies: - - rollup - supports-color + dev: false - vite-plugin-vue-inspector@5.3.1(vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.26.5(@babel/core@7.26.0) - '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.0) - '@vue/compiler-dom': 3.5.13 - kolorist: 1.8.0 - magic-string: 0.30.17 - vite: 6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - transitivePeerDependencies: - - supports-color + /vite-plugin-vue-tracer@1.1.3(vite@7.3.6)(vue@3.5.27): + resolution: {integrity: sha512-fM7hfHELZvbPnSn8EKZwHfzxm5EfYFQIclz8rwcNXfodNbRkwNvh0AGMtaBfMxQ9HC5KVa3KitwHnmE4ezDemw==} + peerDependencies: + vite: ^6.0.0 || ^7.0.0 + vue: ^3.5.0 + dependencies: + estree-walker: 3.0.3 + exsolve: 1.0.8 + magic-string: 0.30.21 + pathe: 2.0.3 + source-map-js: 1.2.1 + vite: 7.3.6(tsx@4.21.0) + vue: 3.5.27(typescript@5.9.3) + dev: false - vite@5.4.11(@types/node@22.10.7)(terser@5.37.0): + /vite@7.2.6(tsx@4.21.0): + resolution: {integrity: sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true dependencies: - esbuild: 0.21.5 - postcss: 8.5.1 - rollup: 4.30.1 + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.2 + tinyglobby: 0.2.15 + tsx: 4.21.0 optionalDependencies: - '@types/node': 22.10.7 fsevents: 2.3.3 - terser: 5.37.0 + dev: true - vite@6.0.7(@types/node@22.10.7)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0): + /vite@7.3.1(jiti@2.6.1)(tsx@4.21.0): + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true dependencies: - esbuild: 0.24.2 - postcss: 8.5.1 - rollup: 4.30.1 + esbuild: 0.27.2 + fdir: 6.5.0(picomatch@4.0.3) + jiti: 2.6.1 + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.55.2 + tinyglobby: 0.2.15 + tsx: 4.21.0 optionalDependencies: - '@types/node': 22.10.7 fsevents: 2.3.3 - jiti: 2.4.2 - terser: 5.37.0 - yaml: 2.7.0 + dev: false - vscode-jsonrpc@6.0.0: {} - - vscode-languageclient@7.0.0: + /vite@7.3.6(tsx@4.21.0): + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true dependencies: - minimatch: 3.1.2 - semver: 7.6.3 - vscode-languageserver-protocol: 3.16.0 + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.26 + rollup: 4.63.0 + tinyglobby: 0.2.17 + tsx: 4.21.0 + optionalDependencies: + fsevents: 2.3.3 + dev: false - vscode-languageserver-protocol@3.16.0: + /vitest-environment-nuxt@1.0.1(@vue/test-utils@2.4.6)(happy-dom@18.0.1)(playwright-core@1.57.0)(typescript@5.9.3)(vitest@3.2.4): + resolution: {integrity: sha512-eBCwtIQriXW5/M49FjqNKfnlJYlG2LWMSNFsRVKomc8CaMqmhQPBS5LZ9DlgYL9T8xIVsiA6RZn2lk7vxov3Ow==} dependencies: - vscode-jsonrpc: 6.0.0 - vscode-languageserver-types: 3.16.0 + '@nuxt/test-utils': 3.23.0(@vue/test-utils@2.4.6)(happy-dom@18.0.1)(playwright-core@1.57.0)(typescript@5.9.3)(vitest@3.2.4) + transitivePeerDependencies: + - '@cucumber/cucumber' + - '@jest/globals' + - '@playwright/test' + - '@testing-library/vue' + - '@vitest/ui' + - '@vue/test-utils' + - crossws + - happy-dom + - jsdom + - magicast + - ocache + - playwright-core + - typescript + - vitest + dev: true - vscode-languageserver-textdocument@1.0.12: {} + /vitest@3.2.4(happy-dom@18.0.1)(tsx@4.21.0): + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/chai': 5.2.2 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.2.6) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.2.0 + debug: 4.4.1 + expect-type: 1.2.1 + happy-dom: 18.0.1 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.2.6(tsx@4.21.0) + vite-node: 3.2.4(tsx@4.21.0) + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + dev: true - vscode-languageserver-types@3.16.0: {} + /vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + dev: false - vscode-languageserver@7.0.0: + /vue-bundle-renderer@2.2.0: + resolution: {integrity: sha512-sz/0WEdYH1KfaOm0XaBmRZOWgYTEvUDt6yPYaUzl4E52qzgWLlknaPPTTZmp6benaPTlQAI/hN1x3tAzZygycg==} dependencies: - vscode-languageserver-protocol: 3.16.0 + ufo: 1.6.1 + dev: false - vscode-uri@3.0.8: {} + /vue-component-type-helpers@2.2.10: + resolution: {integrity: sha512-iDUO7uQK+Sab2tYuiP9D1oLujCWlhHELHMgV/cB13cuGbG4qwkLHvtfWb6FzvxrIOPDnU0oHsz2MlQjhYDeaHA==} + dev: true - vue-bundle-renderer@2.1.1: + /vue-demi@0.14.10(vue@3.5.27): + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true dependencies: - ufo: 1.5.4 + vue: 3.5.27(typescript@5.9.3) + dev: false - vue-devtools-stub@0.1.0: {} + /vue-devtools-stub@0.1.0: + resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} + dev: false - vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)): + /vue-router@4.6.4(vue@3.5.27): + resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} + peerDependencies: + vue: ^3.5.0 dependencies: '@vue/devtools-api': 6.6.4 - vue: 3.5.13(typescript@5.7.3) + vue: 3.5.27(typescript@5.9.3) + dev: false - vue@3.5.13(typescript@5.7.3): + /vue-sonner@2.0.9(nuxt@4.2.2): + resolution: {integrity: sha512-i6BokNlNDL93fpzNxN/LZSn6D6MzlO+i3qXt6iVZne3x1k7R46d5HlFB4P8tYydhgqOrRbIZEsnRd3kG7qGXyw==} + peerDependencies: + '@nuxt/kit': ^4.0.3 + '@nuxt/schema': ^4.0.3 + nuxt: ^4.0.3 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + '@nuxt/schema': + optional: true + nuxt: + optional: true dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-sfc': 3.5.13 - '@vue/runtime-dom': 3.5.13 - '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.3)) - '@vue/shared': 3.5.13 - optionalDependencies: - typescript: 5.7.3 + nuxt: 4.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@vue/compiler-sfc@3.5.42)(better-sqlite3@12.11.1)(drizzle-orm@0.45.1)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.6) + dev: false + + /vue@3.5.27(typescript@5.9.3): + resolution: {integrity: sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@vue/compiler-dom': 3.5.27 + '@vue/compiler-sfc': 3.5.27 + '@vue/runtime-dom': 3.5.27 + '@vue/server-renderer': 3.5.27(vue@3.5.27) + '@vue/shared': 3.5.27 + typescript: 5.9.3 + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false - webidl-conversions@3.0.1: {} + /webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack-virtual-modules@0.6.2: {} + /whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + dev: true - whatwg-url@5.0.0: + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 + dev: false - which@2.0.2: + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true dependencies: isexe: 2.0.0 - which@3.0.1: + /which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true dependencies: - isexe: 2.0.0 + isexe: 3.1.1 + dev: false + + /why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + dev: true - wrap-ansi@7.0.0: + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - wrap-ansi@8.1.0: + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} dependencies: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 - wrappy@1.0.2: {} + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: false - ws@8.18.0: {} + /ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + 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 + dev: false - y18n@5.0.8: {} + /wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + dependencies: + is-wsl: 3.1.0 + dev: false - yallist@3.1.1: {} + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} - yallist@4.0.0: {} + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: false - yallist@5.0.0: {} + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: false - yaml-ast-parser@0.0.43: {} + /yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + dev: false - yaml@2.7.0: {} + /yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + dev: false - yargs-parser@21.1.1: {} + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: false - yargs@17.7.2: + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} dependencies: cliui: 8.0.1 escalade: 3.2.0 @@ -8150,15 +9434,34 @@ snapshots: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 + dev: false - ylru@1.4.0: {} + /youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + dev: false - zhead@2.2.4: {} + /youch@4.1.0-beta.13: + resolution: {integrity: sha512-3+AG1Xvt+R7M7PSDudhbfbwiyveW6B8PLBIwTyEC598biEYIjHhC89i6DBEvR0EZUjGY3uGSnC429HpIa2Z09g==} + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.14 + cookie-es: 2.0.0 + youch-core: 0.3.3 + dev: false - zip-stream@6.0.1: + /zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} dependencies: archiver-utils: 5.0.2 compress-commons: 6.0.2 readable-stream: 4.7.0 + dev: false - zod@3.24.1: {} + /zod@4.3.5: + resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} + dev: false diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..941d854 Binary files /dev/null and b/public/favicon.ico differ diff --git a/src/public/robots.txt b/public/robots.txt similarity index 100% rename from src/public/robots.txt rename to public/robots.txt diff --git a/server/api/settings/index.get.ts b/server/api/settings/index.get.ts new file mode 100644 index 0000000..151e24f --- /dev/null +++ b/server/api/settings/index.get.ts @@ -0,0 +1,6 @@ +import { defineEventHandler } from '#imports' +import { settingsRepository } from '~~/server/repositories/settings' + +export default defineEventHandler(async () => { + return await settingsRepository.getAll() +}) diff --git a/server/api/settings/index.put.ts b/server/api/settings/index.put.ts new file mode 100644 index 0000000..94766b4 --- /dev/null +++ b/server/api/settings/index.put.ts @@ -0,0 +1,10 @@ +import { settingsSchema } from '~~/shared/schemas/settings' +import { defineEventHandler, readValidatedBody } from '#imports' +import { settingsRepository } from '~~/server/repositories/settings' + +export default defineEventHandler(async (event) => { + const body = await readValidatedBody(event, settingsSchema.parse) + await settingsRepository.setValues(body) + + return settingsRepository.getAll() +}) diff --git a/src/server/api/tasks/[id]/executed.post.ts b/server/api/tasks/[id]/executed.post.ts similarity index 52% rename from src/server/api/tasks/[id]/executed.post.ts rename to server/api/tasks/[id]/executed.post.ts index 4f238c7..502cae4 100644 --- a/src/server/api/tasks/[id]/executed.post.ts +++ b/server/api/tasks/[id]/executed.post.ts @@ -1,17 +1,24 @@ import { taskExecutedRequestSchema, - taskRouteParamsSchema, -} from "../../../schemas/tasks" -import { tasksRepository } from "../../../repositories/tasks" -import { envVariables } from "~/server/env" + taskRouteParamsSchema +} from '../../../../shared/schemas/tasks' +import { tasksRepository } from '../../../repositories/tasks' +import { envVariables } from '../../../../shared/env' +import { + createError, + defineEventHandler, + getRequestHeader, + getValidatedRouterParams, + readValidatedBody +} from '#imports' export default defineEventHandler(async (event) => { - const accessToken = getRequestHeader(event, "access-token") + const accessToken = getRequestHeader(event, 'access-token') if (!accessToken || accessToken !== envVariables.taskiqAdminApiToken) { throw createError({ status: 401, - statusMessage: "Unauthorized", - message: "Invalid access token", + statusMessage: 'Unauthorized', + message: 'Invalid access token' }) } const params = await getValidatedRouterParams( @@ -20,14 +27,14 @@ export default defineEventHandler(async (event) => { ) const body = await readValidatedBody(event, taskExecutedRequestSchema.parse) - const state = body.error ? "failure" : "success" + const state = body.error ? 'failure' : 'success' await tasksRepository.update(params.id, { state: state, error: body.error, finishedAt: body.finishedAt, returnValue: body.returnValue, - executionTime: body.executionTime, + executionTime: body.executionTime }) return { success: true } diff --git a/src/server/api/tasks/[id]/index.get.ts b/server/api/tasks/[id]/index.get.ts similarity index 50% rename from src/server/api/tasks/[id]/index.get.ts rename to server/api/tasks/[id]/index.get.ts index f170ef0..963c85a 100644 --- a/src/server/api/tasks/[id]/index.get.ts +++ b/server/api/tasks/[id]/index.get.ts @@ -1,6 +1,6 @@ -import { defineEventHandler, getValidatedRouterParams } from "h3" -import { taskRouteParamsSchema } from "../../../schemas/tasks" -import { tasksRepository } from "../../../repositories/tasks" +import { defineEventHandler, getValidatedRouterParams } from 'h3' +import { taskRouteParamsSchema } from '../../../../shared/schemas/tasks' +import { tasksRepository } from '../../../repositories/tasks' export default defineEventHandler(async (event) => { const params = await getValidatedRouterParams( diff --git a/server/api/tasks/[id]/queued.post.ts b/server/api/tasks/[id]/queued.post.ts new file mode 100644 index 0000000..85d1c8c --- /dev/null +++ b/server/api/tasks/[id]/queued.post.ts @@ -0,0 +1,48 @@ +import { + taskQueuedRequestSchema, + taskRouteParamsSchema +} from '../../../../shared/schemas/tasks' +import { tasksRepository } from '../../../repositories/tasks' +import { envVariables } from '../../../../shared/env' +import { + createError, + defineEventHandler, + getRequestHeader, + getValidatedRouterParams, + readValidatedBody +} from '#imports' + +export default defineEventHandler(async (event) => { + const accessToken = getRequestHeader(event, 'access-token') + if (!accessToken || accessToken !== envVariables.taskiqAdminApiToken) { + throw createError({ + status: 401, + statusMessage: 'Unauthorized', + message: 'Invalid access token' + }) + } + const params = await getValidatedRouterParams( + event, + taskRouteParamsSchema.parse + ) + const body = await readValidatedBody(event, taskQueuedRequestSchema.parse) + + await tasksRepository.upsert( + { + id: params.id, + returnValue: null, + executionTime: null, + state: 'queued', + args: body.args, + worker: body.worker, + kwargs: body.kwargs, + name: body.taskName, + startedAt: null, + queuedAt: body.queuedAt, + finishedAt: null + }, + ['queuedAt'] + ) + + return { success: true } +}) diff --git a/server/api/tasks/[id]/started.post.ts b/server/api/tasks/[id]/started.post.ts new file mode 100644 index 0000000..2231a2a --- /dev/null +++ b/server/api/tasks/[id]/started.post.ts @@ -0,0 +1,50 @@ +import { + taskRouteParamsSchema, + taskStartedRequestSchema +} from '../../../../shared/schemas/tasks' +import { envVariables } from '../../../../shared/env' +import { tasksRepository } from '../../../repositories/tasks' +import { + createError, + defineEventHandler, + getRequestHeader, + getValidatedRouterParams, + readValidatedBody +} from '#imports' + +export default defineEventHandler(async (event) => { + const accessToken = getRequestHeader(event, 'access-token') + if (!accessToken || accessToken !== envVariables.taskiqAdminApiToken) { + throw createError({ + status: 401, + statusMessage: 'Unauthorized', + message: 'Invalid access token' + }) + } + const params = await getValidatedRouterParams( + event, + taskRouteParamsSchema.parse + ) + const body = await readValidatedBody(event, taskStartedRequestSchema.parse) + + // Upserts the task if QUEUED event has not been received yet + await tasksRepository.upsert( + { + id: params.id, + returnValue: null, + executionTime: null, + state: 'running', + args: body.args, + worker: body.worker, + kwargs: body.kwargs, + name: body.taskName, + queuedAt: body.startedAt, + startedAt: body.startedAt, + finishedAt: null + }, + ['startedAt'] + ) + await tasksRepository.promoteToRunning(params.id, body.startedAt) + + return { success: true } +}) diff --git a/server/api/tasks/backup.get.ts b/server/api/tasks/backup.get.ts new file mode 100644 index 0000000..0dbf5b4 --- /dev/null +++ b/server/api/tasks/backup.get.ts @@ -0,0 +1,37 @@ +import fs from 'fs' +import { backupDatabase } from '../../../shared/db' +import { utcNow } from '../../../shared/utils' +import { envVariables } from '../../../shared/env' +import { + createError, + defineEventHandler, + sendStream, + setHeader +} from '#imports' + +export default defineEventHandler(async (event) => { + try { + await backupDatabase(envVariables.backupFilePath) + } catch (error) { + throw createError({ + status: 400, + statusMessage: + error instanceof Error + ? error.message + : 'Could not create database backup' + }) + } + + const stream = fs.createReadStream(envVariables.backupFilePath) + + const now = utcNow() + const formatted = now.format('YYYY-MM-DD HH-mm-ss') + setHeader(event, 'Content-Type', 'application/octet-stream') + setHeader( + event, + 'Content-Disposition', + `attachment; filename="${formatted}-backup.db"` + ) + + return sendStream(event, stream) +}) diff --git a/server/api/tasks/index.get.ts b/server/api/tasks/index.get.ts new file mode 100644 index 0000000..7e428cf --- /dev/null +++ b/server/api/tasks/index.get.ts @@ -0,0 +1,21 @@ +import { defineEventHandler, getValidatedQuery } from 'h3' +import { tasksRepository } from '../../repositories/tasks' +import { getTasksQueryParamsSchema } from '../../../shared/schemas/tasks' + +export default defineEventHandler(async (event) => { + const query = await getValidatedQuery(event, getTasksQueryParamsSchema.parse) + + const { tasks, count } = await tasksRepository.getAll({ + name: query.search ? query.search : null, + limit: query.limit, + offset: query.offset, + state: query.state, + sortByRuntime: query.sortByRuntime, + sortByStartedAt: query.sortByStartedAt, + sortByQueuedAt: query.sortByQueuedAt, + startDate: query.startDate ? new Date(query.startDate) : undefined, + endDate: query.endDate ? new Date(query.endDate) : undefined + }) + + return { tasks, count } +}) diff --git a/server/middleware/log.ts b/server/middleware/log.ts new file mode 100644 index 0000000..2ac8aa0 --- /dev/null +++ b/server/middleware/log.ts @@ -0,0 +1,6 @@ +import { defineEventHandler } from '#imports' + +export default defineEventHandler((event) => { + const { method, url } = event.node.req + console.log(`[API] ${method} ${url}`) +}) diff --git a/server/plugins/shutdown.ts b/server/plugins/shutdown.ts new file mode 100644 index 0000000..78de80d --- /dev/null +++ b/server/plugins/shutdown.ts @@ -0,0 +1,8 @@ +import { defineNitroPlugin } from '#imports' +import { tasksRepository } from '../repositories/tasks' + +export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook('close', async () => { + await tasksRepository.setAbandoned() + }) +}) diff --git a/server/plugins/startup.ts b/server/plugins/startup.ts new file mode 100644 index 0000000..b3806ec --- /dev/null +++ b/server/plugins/startup.ts @@ -0,0 +1,22 @@ +import { db, initializeDatabase } from '../../shared/db' +import { defineNitroPlugin } from '#imports' +import { taskiqAdminSettingsTable } from '~~/shared/db/schema' +import { SETTINGS } from '~~/shared/constants/settings' + +export default defineNitroPlugin(async () => { + console.log('Running DB initialization...') + await initializeDatabase() + + // seeding default settings + await db + .insert(taskiqAdminSettingsTable) + .values( + Object.entries(SETTINGS).map(([_, value]) => ({ + key: value.key, + value: value.defaultValue + })) + ) + .onConflictDoNothing() + + console.log('DB initialization completed.') +}) diff --git a/server/repositories/settings.ts b/server/repositories/settings.ts new file mode 100644 index 0000000..14e96f0 --- /dev/null +++ b/server/repositories/settings.ts @@ -0,0 +1,49 @@ +import { eq } from 'drizzle-orm' +import { db } from '../../shared/db' +import { SettingKey } from '~~/shared/constants/settings' +import { taskiqAdminSettingsTable } from '../../shared/db/schema' +import { settingsSchema } from '~~/shared/schemas/settings' + +class SettingsRepository { + async getValue(key: SettingKey) { + const rows = await db + .select({ value: taskiqAdminSettingsTable.value }) + .from(taskiqAdminSettingsTable) + .where(eq(taskiqAdminSettingsTable.key, key)) + + if (rows.length === 0) { + return undefined + } + + return rows[0].value + } + + async setValue(key: SettingKey, value: string | null) { + return db + .update(taskiqAdminSettingsTable) + .set({ + value + }) + .where(eq(taskiqAdminSettingsTable.key, key)) + } + + async setValues(values: Record) { + for (const [key, value] of Object.entries(values)) { + await db + .update(taskiqAdminSettingsTable) + .set({ + value + }) + .where(eq(taskiqAdminSettingsTable.key, key as SettingKey)) + } + } + + async getAll() { + const settings = await db.select().from(taskiqAdminSettingsTable) + const object = Object.fromEntries(settings.map((s) => [s.key, s.value])) + + return settingsSchema.parse(object) + } +} + +export const settingsRepository = new SettingsRepository() diff --git a/server/repositories/tasks.ts b/server/repositories/tasks.ts new file mode 100644 index 0000000..5a2b80c --- /dev/null +++ b/server/repositories/tasks.ts @@ -0,0 +1,177 @@ +import { db } from '../../shared/db' +import { tasksTable } from '../../shared/db/schema' +import { DB_TABLE_NAMES } from '../../shared/db/constants' +import { envVariables } from '../../shared/env' +import { takeUniqueOrThrow, utcNow } from '../../shared/utils' +import { TaskCreate, TaskState } from '../../shared/types' +import { count, eq, desc, and, asc, gte, lte, sql, like } from 'drizzle-orm' + +const escapeLikePattern = (value: string) => + value.replace(/[\\%_]/g, (character) => `\\${character}`) + +const buildNameCondition = (name: string) => { + if (envVariables.dbDriver === 'postgres') { + const pattern = `%${escapeLikePattern(name.toLowerCase())}%` + return like(tasksTable.name, pattern) + } + // wrap user input as an FTS5 phrase query (escape embedded double quotes by doubling) + const ftsQuery = `"${name.replace(/"/g, '""')}"` + return sql`rowid IN (SELECT rowid FROM ${sql.identifier( + DB_TABLE_NAMES.tasksFts + )} WHERE name MATCH ${ftsQuery})` +} + +class TasksRepository { + async getAll({ + name, + state, + limit, + offset, + sortByRuntime, + sortByStartedAt, + sortByQueuedAt, + startDate, + endDate + }: { + limit: number + offset: number + name: string | null + state?: TaskState + sortByRuntime?: 'asc' | 'desc' + sortByStartedAt?: 'asc' | 'desc' + sortByQueuedAt?: 'asc' | 'desc' + startDate?: Date + endDate?: Date + }) { + const whereConditions = [] + if (name) { + whereConditions.push(buildNameCondition(name)) + } + if (state) { + whereConditions.push(eq(tasksTable.state, state)) + } + if (startDate) { + whereConditions.push(gte(tasksTable.startedAt, startDate)) + } + if (endDate) { + whereConditions.push(lte(tasksTable.startedAt, endDate)) + } + + const orderMap = { asc, desc } + const sortConditions = [] + if (sortByRuntime) { + sortConditions.push(orderMap[sortByRuntime](tasksTable.executionTime)) + } + if (sortByStartedAt) { + sortConditions.push(orderMap[sortByStartedAt](tasksTable.startedAt)) + } + if (sortByQueuedAt) { + sortConditions.push(orderMap[sortByQueuedAt](tasksTable.queuedAt)) + } + if (sortConditions.length === 0) { + sortConditions.push(desc(tasksTable.queuedAt)) + } + + const whereClause = whereConditions.length + ? and(...whereConditions) + : undefined + + const countQuery = db + .select({ + count: count() + }) + .from(tasksTable) + + const tasksQuery = db.select().from(tasksTable) + + const countResult = await ( + whereClause ? countQuery.where(whereClause) : countQuery + ).then(takeUniqueOrThrow) + + const tasks = await ( + whereClause ? tasksQuery.where(whereClause) : tasksQuery + ) + .orderBy(...sortConditions) + .limit(limit) + .offset(offset) + + return { tasks, count: countResult.count } + } + + async getById(taskId: string) { + const result = await db + .select() + .from(tasksTable) + .where(eq(tasksTable.id, taskId)) + + if (result.length > 0) { + return result[0] + } + + return null + } + + async create(values: TaskCreate) { + return db.insert(tasksTable).values(values) + } + + async upsert( + values: TaskCreate, + onConflictSet?: (keyof Pick< + TaskCreate, + 'startedAt' | 'state' | 'queuedAt' + >)[] + ) { + if (!onConflictSet || onConflictSet?.length === 0) { + return db.insert(tasksTable).values(values).onConflictDoNothing({ + target: tasksTable.id + }) + } + + const set: Record = {} + if (onConflictSet) { + for (const key of onConflictSet) { + set[key] = values[key] + } + } + return db.insert(tasksTable).values(values).onConflictDoUpdate({ + target: tasksTable.id, + set + }) + } + + async update( + taskId: string, + values: { + startedAt?: Date | null + error?: string | null + executionTime?: number + finishedAt?: Date | null + returnValue?: { return_value: any } | null + state?: TaskState + } + ) { + return db.update(tasksTable).set(values).where(eq(tasksTable.id, taskId)) + } + + async deleteOld({ ttlMinutes }: { ttlMinutes: number }) { + const now_ = utcNow() + const dateToCompate = now_.subtract(ttlMinutes, 'minutes').toDate() + return db.delete(tasksTable).where(lte(tasksTable.queuedAt, dateToCompate)) + } + + async setAbandoned() { + return db + .update(tasksTable) + .set({ state: 'abandoned' }) + .where(eq(tasksTable.state, 'running')) + } + async promoteToRunning(id: string, startedAt: Date) { + return db + .update(tasksTable) + .set({ startedAt, state: 'running' }) + .where(and(eq(tasksTable.id, id), eq(tasksTable.state, 'queued'))) + } +} + +export const tasksRepository = new TasksRepository() diff --git a/server/tasks/delete-old.ts b/server/tasks/delete-old.ts new file mode 100644 index 0000000..db44394 --- /dev/null +++ b/server/tasks/delete-old.ts @@ -0,0 +1,33 @@ +import { defineTask } from '#imports' +import { tasksRepository } from '~~/server/repositories/tasks' +import { settingsRepository } from '~~/server/repositories/settings' + +export default defineTask<{ ttlMinutes?: number }, { result: string }>({ + meta: { + name: 'delete-old', + description: 'Delete old task information using the TTL parameter' + }, + async run({ payload }: { payload: void }) { + console.log('🗑️ delete-old task started') + + const settings = await settingsRepository.getAll() + if (!settings.delete_old_ttl_minutes) { + console.warn('⚠️ delete-old skipped: TTL not configured') + return { result: 'Skipped: TTL not configured' } + } + + console.log( + `🚩 Running delete-old for TTL ${settings.delete_old_ttl_minutes} minute(s) ...` + ) + try { + await tasksRepository.deleteOld({ + ttlMinutes: settings.delete_old_ttl_minutes + }) + console.log('✅ Old tasks deleted successfully') + return { result: 'Success' } + } catch (error) { + console.error('❌ Failed to delete old tasks', error) + throw error + } + } +}) diff --git a/server/tasks/settings-dispatcher.ts b/server/tasks/settings-dispatcher.ts new file mode 100644 index 0000000..847fc89 --- /dev/null +++ b/server/tasks/settings-dispatcher.ts @@ -0,0 +1,30 @@ +import { defineTask, runTask } from '#imports' +import { SETTINGS } from '~~/shared/constants/settings' +import { settingsRepository } from '~~/server/repositories/settings' + +const settingsToTasksMap = { + [SETTINGS.delete_old_ttl_minutes.key]: 'delete-old' +} + +export default defineTask({ + meta: { + name: 'settings-dispatcher', + description: + 'Reads taskiq_admin_settings entries and dispatches maintenance tasks' + }, + async run() { + console.log('DISPATCHER: Starting settings-dispatcher task...') + const settings = await settingsRepository.getAll() + + for (const [key, value] of Object.entries(settings)) { + if (value === null) continue + if (!(key in settingsToTasksMap)) continue + + const taskName = + settingsToTasksMap[key as keyof typeof settingsToTasksMap] + + runTask(taskName, { key: value }) + } + console.log('DISPATCHER: settings-dispatcher task completed.') + } +}) diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 0000000..b9ed69c --- /dev/null +++ b/server/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../.nuxt/tsconfig.server.json" +} diff --git a/shared/constants/settings.ts b/shared/constants/settings.ts new file mode 100644 index 0000000..b4b2e69 --- /dev/null +++ b/shared/constants/settings.ts @@ -0,0 +1,10 @@ +export const SETTINGS = { + delete_old_ttl_minutes: { + key: 'delete_old_ttl_minutes', + min: 1, + max: 60 * 24 * 365, // 1 year + defaultValue: null + } +} as const + +export type SettingKey = (typeof SETTINGS)[keyof typeof SETTINGS]['key'] diff --git a/shared/db/constants.ts b/shared/db/constants.ts new file mode 100644 index 0000000..0df35ce --- /dev/null +++ b/shared/db/constants.ts @@ -0,0 +1,26 @@ +export const DB_TABLE_NAMES = { + tasks: 'taskiq_admin_tasks', + settings: 'taskiq_admin_settings', + tasksFts: 'taskiq_admin_tasks_fts' +} as const + +export const DB_INDEX_NAMES = { + tasksState: 'idx_taskiq_admin_tasks__state', + tasksQueuedAt: 'idx_taskiq_admin_tasks__queued_at', + tasksStartedAt: 'idx_taskiq_admin_tasks__started_at', + tasksFinishedAt: 'idx_taskiq_admin_tasks__finished_at', + tasksExecutionTime: 'idx_taskiq_admin_tasks__execution_time', + tasksName: 'idx_taskiq_admin_tasks__name', + tasksWorker: 'idx_taskiq_admin_tasks__worker', + tasksStateQueuedAt: 'idx_taskiq_admin_tasks__state_queued_at', + tasksStateStartedAt: 'idx_taskiq_admin_tasks__state_started_at', + tasksStateExecutionTime: 'idx_taskiq_admin_tasks__state_execution_time', + tasksNameFts: 'idx_taskiq_admin_tasks__name_fts', + tasksNameTrgm: 'idx_taskiq_admin_tasks__name_trgm' +} as const + +export const DB_TRIGGER_NAMES = { + tasksFtsInsert: 'trg_taskiq_admin_tasks_fts_ai', + tasksFtsDelete: 'trg_taskiq_admin_tasks_fts_ad', + tasksFtsUpdate: 'trg_taskiq_admin_tasks_fts_au' +} as const diff --git a/shared/db/index.ts b/shared/db/index.ts new file mode 100644 index 0000000..e201297 --- /dev/null +++ b/shared/db/index.ts @@ -0,0 +1,90 @@ +import Database from 'better-sqlite3' +import { drizzle as drizzleSqlite } from 'drizzle-orm/better-sqlite3' +import { sql } from 'drizzle-orm' +import { drizzle as drizzlePostgres } from 'drizzle-orm/node-postgres' +import { mkdirSync } from 'node:fs' +import { dirname, isAbsolute, resolve } from 'node:path' +import { Pool } from 'pg' +import { envVariables } from '../env' +import { dbInitializationStatements } from './init' + +const isInMemorySqlitePath = (sqlitePath: string) => { + return sqlitePath === ':memory:' || sqlitePath.startsWith('file::memory:') +} + +const ensureSqliteFilePath = (sqlitePath: string) => { + if (isInMemorySqlitePath(sqlitePath) || sqlitePath.startsWith('file:')) { + return sqlitePath + } + + const resolvedPath = isAbsolute(sqlitePath) + ? sqlitePath + : resolve(process.cwd(), sqlitePath) + mkdirSync(dirname(resolvedPath), { recursive: true }) + return resolvedPath +} + +const sqliteClient = + envVariables.dbDriver === 'sqlite' + ? new Database(ensureSqliteFilePath(envVariables.dbFilePath)) + : null + +const postgresClient = + envVariables.dbDriver === 'postgres' + ? new Pool({ connectionString: envVariables.dbUrl }) + : null + +const sqliteDb = sqliteClient ? drizzleSqlite({ client: sqliteClient }) : null +const postgresDb = postgresClient + ? drizzlePostgres({ client: postgresClient }) + : null + +export const db: any = + envVariables.dbDriver === 'sqlite' ? sqliteDb! : postgresDb! + +const executeStatement = async (statement: string) => { + if (envVariables.dbDriver === 'sqlite') { + sqliteClient!.exec(statement) + return + } + await postgresDb!.execute(sql.raw(statement)) +} + +export const initializeDatabase = async () => { + const loggedWarnings = new Set() + for (const statement of dbInitializationStatements[envVariables.dbDriver]) { + if (typeof statement === 'string') { + await executeStatement(statement) + continue + } + try { + await executeStatement(statement.sql) + } catch { + if (!loggedWarnings.has(statement.warning)) { + loggedWarnings.add(statement.warning) + console.warn(`[taskiq-admin] ${statement.warning}`) + } + } + } +} + +export const backupDatabase = async (backupFilePath: string) => { + if (envVariables.dbDriver !== 'sqlite') { + throw new Error('Database backup is supported only with sqlite driver') + } + await sqliteClient!.backup(ensureSqliteFilePath(backupFilePath)) +} + +export const resetDatabaseForTests = async () => { + if (envVariables.dbDriver === 'sqlite') { + sqliteClient!.exec('PRAGMA foreign_keys = OFF') + sqliteClient!.exec('DROP TABLE IF EXISTS taskiq_admin_tasks') + sqliteClient!.exec('DROP TABLE IF EXISTS taskiq_admin_settings') + await initializeDatabase() + return + } + + await postgresDb!.execute(sql`DROP TABLE IF EXISTS taskiq_admin_tasks`) + await postgresDb!.execute(sql`DROP TABLE IF EXISTS taskiq_admin_settings`) + await initializeDatabase() +} diff --git a/shared/db/init.ts b/shared/db/init.ts new file mode 100644 index 0000000..ad7e0a8 --- /dev/null +++ b/shared/db/init.ts @@ -0,0 +1,66 @@ +import type { DBDriver } from '../env' +import { DB_INDEX_NAMES, DB_TABLE_NAMES, DB_TRIGGER_NAMES } from './constants' + +// `optional` statements are allowed to fail without aborting initialization +// (e.g. CREATE EXTENSION requires privileges the connected role may not have). +// `warning` explains the degradation to the operator; identical warnings are logged once. +export type DBInitStatement = + | string + | { sql: string; optional: true; warning: string } + +const PG_TRGM_WARNING = [ + 'the pg_trgm extension is not available, so task name search is not indexed', + 'and falls back to a sequential scan (results stay correct).', + 'To enable the index: install the postgresql-contrib package and let the', + 'role in TASKIQ_ADMIN_DB_URL run "CREATE EXTENSION pg_trgm" (database owner', + 'or superuser), or create the extension once by hand.' +].join(' ') + +export const dbInitializationStatements: Record = { + sqlite: [ + 'PRAGMA journal_mode = WAL', + 'PRAGMA synchronous = NORMAL', + 'PRAGMA journal_size_limit = 6144000', + `CREATE TABLE IF NOT EXISTS \`${DB_TABLE_NAMES.settings}\` (\`key\` text PRIMARY KEY NOT NULL, \`value\` text)`, + `CREATE TABLE IF NOT EXISTS \`${DB_TABLE_NAMES.tasks}\` (\`id\` text PRIMARY KEY NOT NULL, \`name\` text NOT NULL, \`state\` text NOT NULL, \`error\` text, \`worker\` text, \`execution_time\` real, \`queued_at\` integer NOT NULL, \`started_at\` integer, \`finished_at\` integer, \`args\` text, \`kwargs\` text, \`return_value\` text)`, + `CREATE INDEX IF NOT EXISTS \`${DB_INDEX_NAMES.tasksQueuedAt}\` ON \`${DB_TABLE_NAMES.tasks}\` (\`queued_at\`)`, + `CREATE INDEX IF NOT EXISTS \`${DB_INDEX_NAMES.tasksStartedAt}\` ON \`${DB_TABLE_NAMES.tasks}\` (\`started_at\`)`, + `CREATE INDEX IF NOT EXISTS \`${DB_INDEX_NAMES.tasksFinishedAt}\` ON \`${DB_TABLE_NAMES.tasks}\` (\`finished_at\`)`, + `CREATE INDEX IF NOT EXISTS \`${DB_INDEX_NAMES.tasksExecutionTime}\` ON \`${DB_TABLE_NAMES.tasks}\` (\`execution_time\`)`, + `CREATE INDEX IF NOT EXISTS \`${DB_INDEX_NAMES.tasksWorker}\` ON \`${DB_TABLE_NAMES.tasks}\` (worker COLLATE NOCASE)`, + `CREATE INDEX IF NOT EXISTS \`${DB_INDEX_NAMES.tasksStateQueuedAt}\` ON \`${DB_TABLE_NAMES.tasks}\` (\`state\`, \`queued_at\`)`, + `CREATE INDEX IF NOT EXISTS \`${DB_INDEX_NAMES.tasksStateStartedAt}\` ON \`${DB_TABLE_NAMES.tasks}\` (\`state\`, \`started_at\`)`, + `CREATE INDEX IF NOT EXISTS \`${DB_INDEX_NAMES.tasksStateExecutionTime}\` ON \`${DB_TABLE_NAMES.tasks}\` (\`state\`, \`execution_time\`)`, + // FTS5 external-content table over name with trigram tokenizer (substring match, preserves LIKE %x% semantics) + `CREATE VIRTUAL TABLE IF NOT EXISTS \`${DB_TABLE_NAMES.tasksFts}\` USING fts5(name, content='${DB_TABLE_NAMES.tasks}', content_rowid='rowid', tokenize='trigram')`, + `CREATE TRIGGER IF NOT EXISTS \`${DB_TRIGGER_NAMES.tasksFtsInsert}\` AFTER INSERT ON \`${DB_TABLE_NAMES.tasks}\` BEGIN INSERT INTO \`${DB_TABLE_NAMES.tasksFts}\`(rowid, name) VALUES (new.rowid, new.name); END`, + `CREATE TRIGGER IF NOT EXISTS \`${DB_TRIGGER_NAMES.tasksFtsDelete}\` AFTER DELETE ON \`${DB_TABLE_NAMES.tasks}\` BEGIN INSERT INTO \`${DB_TABLE_NAMES.tasksFts}\`(\`${DB_TABLE_NAMES.tasksFts}\`, rowid, name) VALUES('delete', old.rowid, old.name); END`, + `CREATE TRIGGER IF NOT EXISTS \`${DB_TRIGGER_NAMES.tasksFtsUpdate}\` AFTER UPDATE ON \`${DB_TABLE_NAMES.tasks}\` BEGIN INSERT INTO \`${DB_TABLE_NAMES.tasksFts}\`(\`${DB_TABLE_NAMES.tasksFts}\`, rowid, name) VALUES('delete', old.rowid, old.name); INSERT INTO \`${DB_TABLE_NAMES.tasksFts}\`(rowid, name) VALUES (new.rowid, new.name); END`, + // rebuild FTS index from existing rows (no-op when table empty; cheap on subsequent runs only if needed) + `INSERT INTO \`${DB_TABLE_NAMES.tasksFts}\`(\`${DB_TABLE_NAMES.tasksFts}\`) VALUES('rebuild')` + ], + postgres: [ + `CREATE TABLE IF NOT EXISTS "${DB_TABLE_NAMES.settings}" ("key" text PRIMARY KEY, "value" text)`, + `CREATE TABLE IF NOT EXISTS "${DB_TABLE_NAMES.tasks}" ("id" text PRIMARY KEY, "name" text NOT NULL, "state" text NOT NULL, "error" text, "worker" text, "execution_time" real, "queued_at" timestamp with time zone NOT NULL, "started_at" timestamp with time zone, "finished_at" timestamp with time zone, "args" jsonb, "kwargs" jsonb, "return_value" jsonb)`, + `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksQueuedAt}" ON "${DB_TABLE_NAMES.tasks}" ("queued_at")`, + `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksStartedAt}" ON "${DB_TABLE_NAMES.tasks}" ("started_at")`, + `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksFinishedAt}" ON "${DB_TABLE_NAMES.tasks}" ("finished_at")`, + `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksExecutionTime}" ON "${DB_TABLE_NAMES.tasks}" ("execution_time")`, + `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksWorker}" ON "${DB_TABLE_NAMES.tasks}" ("worker")`, + `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksStateQueuedAt}" ON "${DB_TABLE_NAMES.tasks}" ("state", "queued_at")`, + `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksStateStartedAt}" ON "${DB_TABLE_NAMES.tasks}" ("state", "started_at")`, + `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksStateExecutionTime}" ON "${DB_TABLE_NAMES.tasks}" ("state", "execution_time")`, + // both statements are optional: without pg_trgm the LIKE search still returns + // correct results, it just falls back to a sequential scan. + { + sql: 'CREATE EXTENSION IF NOT EXISTS pg_trgm', + optional: true, + warning: PG_TRGM_WARNING + }, + { + sql: `CREATE INDEX IF NOT EXISTS "${DB_INDEX_NAMES.tasksNameTrgm}" ON "${DB_TABLE_NAMES.tasks}" USING gin (lower("name") gin_trgm_ops)`, + optional: true, + warning: PG_TRGM_WARNING + } + ] +} diff --git a/shared/db/schema.postgres.ts b/shared/db/schema.postgres.ts new file mode 100644 index 0000000..3bee48a --- /dev/null +++ b/shared/db/schema.postgres.ts @@ -0,0 +1,58 @@ +import { sql, type InferSelectModel } from 'drizzle-orm' +import { + index, + jsonb, + pgTable, + real, + text, + timestamp +} from 'drizzle-orm/pg-core' +import { DB_INDEX_NAMES, DB_TABLE_NAMES } from './constants' + +export const tasksTable = pgTable( + DB_TABLE_NAMES.tasks, + { + id: text().primaryKey(), + name: text().notNull(), + state: text().notNull(), + error: text(), + worker: text(), + executionTime: real('execution_time'), + queuedAt: timestamp('queued_at', { + withTimezone: true, + mode: 'date' + }).notNull(), + startedAt: timestamp('started_at', { withTimezone: true, mode: 'date' }), + finishedAt: timestamp('finished_at', { withTimezone: true, mode: 'date' }), + args: jsonb().$type>(), + kwargs: jsonb().$type>(), + returnValue: jsonb('return_value').$type<{ + return_value: any + }>() + }, + (t) => [ + index(DB_INDEX_NAMES.tasksQueuedAt).on(t.queuedAt), + index(DB_INDEX_NAMES.tasksStartedAt).on(t.startedAt), + index(DB_INDEX_NAMES.tasksFinishedAt).on(t.finishedAt), + index(DB_INDEX_NAMES.tasksExecutionTime).on(t.executionTime), + index(DB_INDEX_NAMES.tasksWorker).on(t.worker), + index(DB_INDEX_NAMES.tasksStateQueuedAt).on(t.state, t.queuedAt), + index(DB_INDEX_NAMES.tasksStateStartedAt).on(t.state, t.startedAt), + index(DB_INDEX_NAMES.tasksStateExecutionTime).on(t.state, t.executionTime), + index(DB_INDEX_NAMES.tasksNameTrgm).using( + 'gin', + sql`lower(${t.name}) gin_trgm_ops` + ) + ] +) + +export type TaskSelect = InferSelectModel + +export const taskiqAdminSettingsTable = pgTable(DB_TABLE_NAMES.settings, { + key: text('key').primaryKey(), + value: text('value') +}) + +export type TaskiqAdminSettings = InferSelectModel< + typeof taskiqAdminSettingsTable +> diff --git a/shared/db/schema.sqlite.ts b/shared/db/schema.sqlite.ts new file mode 100644 index 0000000..8e6dca3 --- /dev/null +++ b/shared/db/schema.sqlite.ts @@ -0,0 +1,46 @@ +import { type InferSelectModel, sql } from 'drizzle-orm' +import { int, text, real, sqliteTable, index } from 'drizzle-orm/sqlite-core' +import { DB_INDEX_NAMES, DB_TABLE_NAMES } from './constants' + +export const tasksTable = sqliteTable( + DB_TABLE_NAMES.tasks, + { + id: text().primaryKey(), + name: text().notNull(), + state: text({ + enum: ['queued', 'running', 'success', 'failure', 'abandoned'] + }).notNull(), + error: text(), + worker: text(), + executionTime: real('execution_time'), + queuedAt: int('queued_at', { mode: 'timestamp_ms' }).notNull(), + startedAt: int('started_at', { mode: 'timestamp_ms' }), + finishedAt: int('finished_at', { mode: 'timestamp_ms' }), + args: text({ mode: 'json' }).$type>(), + kwargs: text({ mode: 'json' }).$type>(), + returnValue: text('return_value', { mode: 'json' }).$type<{ + return_value: any + }>() + }, + (t) => [ + index(DB_INDEX_NAMES.tasksQueuedAt).on(t.queuedAt), + index(DB_INDEX_NAMES.tasksStartedAt).on(t.startedAt), + index(DB_INDEX_NAMES.tasksFinishedAt).on(t.finishedAt), + index(DB_INDEX_NAMES.tasksExecutionTime).on(t.executionTime), + index(DB_INDEX_NAMES.tasksWorker).on(sql`worker COLLATE NOCASE`), + index(DB_INDEX_NAMES.tasksStateQueuedAt).on(t.state, t.queuedAt), + index(DB_INDEX_NAMES.tasksStateStartedAt).on(t.state, t.startedAt), + index(DB_INDEX_NAMES.tasksStateExecutionTime).on(t.state, t.executionTime) + ] +) + +export type TaskSelect = InferSelectModel + +export const taskiqAdminSettingsTable = sqliteTable(DB_TABLE_NAMES.settings, { + key: text('key').primaryKey(), + value: text('value') +}) + +export type TaskiqAdminSettings = InferSelectModel< + typeof taskiqAdminSettingsTable +> diff --git a/shared/db/schema.ts b/shared/db/schema.ts new file mode 100644 index 0000000..31fa4fc --- /dev/null +++ b/shared/db/schema.ts @@ -0,0 +1,14 @@ +import { envVariables } from '../env' +import * as sqliteSchema from './schema.sqlite' +import * as postgresSchema from './schema.postgres' + +const schema = + envVariables.dbDriver === 'sqlite' ? sqliteSchema : postgresSchema + +export const tasksTable = schema.tasksTable +export const taskiqAdminSettingsTable = schema.taskiqAdminSettingsTable + +export type TaskSelect = sqliteSchema.TaskSelect | postgresSchema.TaskSelect +export type TaskiqAdminSettings = + | sqliteSchema.TaskiqAdminSettings + | postgresSchema.TaskiqAdminSettings diff --git a/shared/env.ts b/shared/env.ts new file mode 100644 index 0000000..1ae4ebd --- /dev/null +++ b/shared/env.ts @@ -0,0 +1,41 @@ +export type DBDriver = 'sqlite' | 'postgres' + +const getRequiredEnv = (name: string) => { + const value = process.env[name] + if (!value) { + throw new Error(`Environment variable ${name} is required`) + } + return value +} + +const getDbDriver = (): DBDriver => { + const value = process.env.TASKIQ_ADMIN_DB_DRIVER + if (!value) { + throw new Error('Environment variable TASKIQ_ADMIN_DB_DRIVER is required') + } + if (value !== 'sqlite' && value !== 'postgres') { + throw new Error( + 'Environment variable TASKIQ_ADMIN_DB_DRIVER must be "sqlite" or "postgres"' + ) + } + return value +} + +const dbDriver = getDbDriver() + +export const envVariables = { + dbDriver, + dbFilePath: + dbDriver === 'sqlite' + ? getRequiredEnv('TASKIQ_ADMIN_DB_FILE_PATH') + : process.env.TASKIQ_ADMIN_DB_FILE_PATH || '', + dbUrl: + dbDriver === 'postgres' + ? getRequiredEnv('TASKIQ_ADMIN_DB_URL') + : process.env.TASKIQ_ADMIN_DB_URL || '', + backupFilePath: + dbDriver === 'sqlite' + ? getRequiredEnv('TASKIQ_ADMIN_BACKUP_FILE_PATH') + : process.env.TASKIQ_ADMIN_BACKUP_FILE_PATH || '', + taskiqAdminApiToken: getRequiredEnv('TASKIQ_ADMIN_API_TOKEN') +} diff --git a/shared/exceptions.ts b/shared/exceptions.ts new file mode 100644 index 0000000..5004fdc --- /dev/null +++ b/shared/exceptions.ts @@ -0,0 +1,8 @@ +export class NotFoundError extends Error { + status: number; + constructor(message: string, status = 404) { + super(message); + this.name = "ValidationError"; + this.status = status; + } +} diff --git a/shared/schemas/settings.ts b/shared/schemas/settings.ts new file mode 100644 index 0000000..69e6963 --- /dev/null +++ b/shared/schemas/settings.ts @@ -0,0 +1,13 @@ +import * as z from 'zod' +import { SETTINGS } from '../constants/settings' + +export const settingsSchema = z.object({ + [SETTINGS.delete_old_ttl_minutes.key]: z.coerce + .number() + .int() + .min(SETTINGS.delete_old_ttl_minutes.min) + .max(SETTINGS.delete_old_ttl_minutes.max) + .nullable() +}) + +export type SettingsSchema = z.infer diff --git a/shared/schemas/tasks.ts b/shared/schemas/tasks.ts new file mode 100644 index 0000000..1841e4e --- /dev/null +++ b/shared/schemas/tasks.ts @@ -0,0 +1,42 @@ +import * as z from 'zod' + +export const taskQueuedRequestSchema = z.object({ + taskName: z.string(), + queuedAt: z.coerce.date(), + args: z.array(z.unknown()), + worker: z.string().nullable(), + kwargs: z.record(z.string(), z.unknown()) +}) + +export const taskStartedRequestSchema = z.object({ + taskName: z.string(), + startedAt: z.coerce.date(), + args: z.array(z.unknown()), + worker: z.string().nullable(), + kwargs: z.record(z.string(), z.unknown()) +}) + +export const taskExecutedRequestSchema = z.object({ + error: z.string().nullable(), + executionTime: z.number(), + finishedAt: z.coerce.date(), + returnValue: z.record(z.string(), z.unknown()).nullable() +}) + +export const taskRouteParamsSchema = z.object({ + id: z.string() +}) + +export const getTasksQueryParamsSchema = z.object({ + search: z.string().optional(), + limit: z.coerce.number().gte(0), + offset: z.coerce.number().gte(0), + state: z + .enum(['queued', 'success', 'running', 'failure', 'abandoned']) + .optional(), + sortByRuntime: z.enum(['asc', 'desc']).optional(), + sortByStartedAt: z.enum(['asc', 'desc']).optional(), + sortByQueuedAt: z.enum(['asc', 'desc']).optional(), + startDate: z.coerce.date().optional(), + endDate: z.coerce.date().optional() +}) diff --git a/shared/types.ts b/shared/types.ts new file mode 100644 index 0000000..6d352a9 --- /dev/null +++ b/shared/types.ts @@ -0,0 +1,35 @@ +export type QueryParams = { + page: number + perPage: number + state?: string + search?: string + sortByRuntime?: string + sortByStartedAt?: string + sortByQueuedAt?: string + startDate?: string + endDate?: string +} + +export const StateEnum = { + queued: 'queued', + running: 'running', + success: 'success', + failure: 'failure', + abandoned: 'abandoned' +} as const +export const StateEnumValues = Object.values(StateEnum) +export type TaskState = (typeof StateEnum)[keyof typeof StateEnum] + +export type TaskCreate = { + id: string + name: string + args: Array + queuedAt: Date + startedAt: Date | null + worker: string | null + finishedAt: Date | null + kwargs: Record + executionTime: number | null + returnValue: { return_value: any } | null + state: TaskState +} diff --git a/shared/utils.ts b/shared/utils.ts new file mode 100644 index 0000000..fb33c2d --- /dev/null +++ b/shared/utils.ts @@ -0,0 +1,19 @@ +import dayjs from 'dayjs' +import utc from 'dayjs/plugin/utc.js' +import { NotFoundError } from './exceptions' + +dayjs.extend(utc) + +export const takeUniqueOrThrow = (values: T): T[number] => { + if (values.length !== 1) + throw new NotFoundError('Found non unique or inexistent value') + return values[0]! +} + +export const utcNow = () => { + return dayjs.utc() +} + +export const capitalize = (text: string) => { + return text[0]?.toUpperCase() + text.slice(1) +} diff --git a/src/app.vue b/src/app.vue deleted file mode 100644 index e2f0cbd..0000000 --- a/src/app.vue +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/src/components/header.vue b/src/components/header.vue deleted file mode 100644 index 0afec2e..0000000 --- a/src/components/header.vue +++ /dev/null @@ -1,10 +0,0 @@ - - diff --git a/src/pages/index.vue b/src/pages/index.vue deleted file mode 100644 index 1427be7..0000000 --- a/src/pages/index.vue +++ /dev/null @@ -1,5 +0,0 @@ - - diff --git a/src/pages/tasks/[id].vue b/src/pages/tasks/[id].vue deleted file mode 100644 index 1a16636..0000000 --- a/src/pages/tasks/[id].vue +++ /dev/null @@ -1,90 +0,0 @@ - - - - - diff --git a/src/pages/tasks/index.vue b/src/pages/tasks/index.vue deleted file mode 100644 index 5c5440f..0000000 --- a/src/pages/tasks/index.vue +++ /dev/null @@ -1,233 +0,0 @@ - - - - diff --git a/src/public/favicon.ico b/src/public/favicon.ico deleted file mode 100644 index 18993ad..0000000 Binary files a/src/public/favicon.ico and /dev/null differ diff --git a/src/server/api/tasks/[id]/started.post.ts b/src/server/api/tasks/[id]/started.post.ts deleted file mode 100644 index 550d3b2..0000000 --- a/src/server/api/tasks/[id]/started.post.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { - taskRouteParamsSchema, - taskStartedRequestSchema, -} from "../../../schemas/tasks" -import { tasksRepository } from "../../../repositories/tasks" -import { envVariables } from "~/server/env" - -export default defineEventHandler(async (event) => { - const accessToken = getRequestHeader(event, "access-token") - if (!accessToken || accessToken !== envVariables.taskiqAdminApiToken) { - throw createError({ - status: 401, - statusMessage: "Unauthorized", - message: "Invalid access token", - }) - } - const params = await getValidatedRouterParams( - event, - taskRouteParamsSchema.parse - ) - const body = await readValidatedBody(event, taskStartedRequestSchema.parse) - - await tasksRepository.create({ - finishedAt: null, - returnValue: null, - executionTime: null, - state: "running", - args: body.args, - id: params.id, - worker: body.worker, - kwargs: body.kwargs, - name: body.taskName, - startedAt: body.startedAt, - }) - return { - success: true, - } -}) diff --git a/src/server/api/tasks/backup.get.ts b/src/server/api/tasks/backup.get.ts deleted file mode 100644 index 9006c12..0000000 --- a/src/server/api/tasks/backup.get.ts +++ /dev/null @@ -1,13 +0,0 @@ -import fs from "fs" -import { db } from "~/server/db" -import { envVariables } from "~/server/env" - -export default defineEventHandler(async (event) => { - await db.$client.backup(envVariables.backupFilePath) - const stream = fs.createReadStream(envVariables.backupFilePath) - - setHeader(event, "Content-Type", "application/octet-stream") - setHeader(event, "Content-Disposition", 'attachment; filename="backup.db"') - - return sendStream(event, stream) -}) diff --git a/src/server/api/tasks/index.get.ts b/src/server/api/tasks/index.get.ts deleted file mode 100644 index 4cc1402..0000000 --- a/src/server/api/tasks/index.get.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineEventHandler, getValidatedQuery } from "h3" -import { tasksRepository } from "../../repositories/tasks" -import { getTasksQueryParamsSchema } from "../../schemas/tasks" - -export default defineEventHandler(async (event) => { - const query = await getValidatedQuery(event, getTasksQueryParamsSchema.parse) - - const { tasks, count } = await tasksRepository.getAll({ - name: query.search ? query.search : null, - limit: query.limit, - offset: query.offset, - state: query.state, - }) - - return { tasks, count } -}) diff --git a/src/server/db/index.ts b/src/server/db/index.ts deleted file mode 100644 index 7c20157..0000000 --- a/src/server/db/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { drizzle } from "drizzle-orm/better-sqlite3" - -export const db = drizzle({ - connection: { - source: process.env.DB_FILE_PATH!, - }, -}) diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts deleted file mode 100644 index b074cc2..0000000 --- a/src/server/db/schema.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { InferSelectModel } from "drizzle-orm" -import { int, text, real, sqliteTable, index } from "drizzle-orm/sqlite-core" - -export const tasksTable = sqliteTable( - "tasks", - { - id: text().primaryKey(), - name: text().notNull(), - state: text({ - enum: ["success", "running", "failure", "abandoned"], - }).notNull(), - error: text(), - worker: text(), - executionTime: real("execution_time"), - startedAt: int("started_at", { mode: "timestamp" }).notNull(), - finishedAt: int("finished_at", { mode: "timestamp" }), - args: text({ mode: "json" }).$type>(), - kwargs: text({ mode: "json" }).$type>(), - returnValue: text("return_value", { mode: "json" }).$type<{ - return_value: any - }>(), - }, - (t) => ({ - idxState: index("idx_tasks__state").on(t.state), - idxStartedAt: index("idx_tasks__started_at").on(t.startedAt), - idxFinishedAt: index("idx_tasks__finished_at").on(t.finishedAt), - idxExecutionTime: index("idx_tasks__execution_time").on(t.executionTime), - }) -) - -export type TaskSelect = InferSelectModel diff --git a/src/server/env.ts b/src/server/env.ts deleted file mode 100644 index b89f2dc..0000000 --- a/src/server/env.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const envVariables = { - dbFilePath: process.env.DB_FILE_PATH!, - backupFilePath: process.env.BACKUP_FILE_PATH!, - taskiqAdminApiToken: process.env.TASKIQ_ADMIN_API_TOKEN!, -} diff --git a/src/server/exceptions.ts b/src/server/exceptions.ts deleted file mode 100644 index e95af23..0000000 --- a/src/server/exceptions.ts +++ /dev/null @@ -1,8 +0,0 @@ -export class NotFoundError extends Error { - status: number - constructor(message: string, status = 404) { - super(message) - this.name = "ValidationError" - this.status = status - } -} diff --git a/src/server/plugins/shutdown.ts b/src/server/plugins/shutdown.ts deleted file mode 100644 index 3a050c5..0000000 --- a/src/server/plugins/shutdown.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { tasksRepository } from "~/server/repositories/tasks" - -export default defineNitroPlugin((nitroApp) => { - nitroApp.hooks.hook("close", async () => { - await tasksRepository.setAbandoned() - }) -}) diff --git a/src/server/plugins/startup.ts b/src/server/plugins/startup.ts deleted file mode 100644 index 37506db..0000000 --- a/src/server/plugins/startup.ts +++ /dev/null @@ -1,7 +0,0 @@ -import fs from "fs/promises" -import { db } from "~/server/db" - -export default defineNitroPlugin(async (nitroApp) => { - const sqlScript = await fs.readFile("dbschema.sql", "utf-8") - db.$client.exec(sqlScript) -}) diff --git a/src/server/repositories/tasks.ts b/src/server/repositories/tasks.ts deleted file mode 100644 index f61111f..0000000 --- a/src/server/repositories/tasks.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { db } from "../db" -import { tasksTable } from "../db/schema" -import { takeUniqueOrThrow } from "../utils" -import { count, eq, desc, like, and } from "drizzle-orm" - -export type TaskState = "running" | "success" | "failed" | "abandoned" - -class TasksRepository { - async getAll({ - name, - state, - limit, - offset, - }: { - limit: number - offset: number - name: string | null - state?: "success" | "running" | "failure" | "abandoned" - }) { - const whereCondition = name - ? like(tasksTable.name, `%${name.toLowerCase()}%`) - : undefined - - const countResult = await db - .select({ - count: count(), - }) - .from(tasksTable) - .where( - and(whereCondition, state ? eq(tasksTable.state, state) : undefined) - ) - .then(takeUniqueOrThrow) - - const tasks = await db - .select() - .from(tasksTable) - .where( - and(whereCondition, state ? eq(tasksTable.state, state) : undefined) - ) - .orderBy(desc(tasksTable.startedAt)) - .limit(limit) - .offset(offset) - - return { tasks, count: countResult.count } - } - - async getById(taskId: string) { - return db - .select() - .from(tasksTable) - .where(eq(tasksTable.id, taskId)) - .then(takeUniqueOrThrow) - } - - async create(values: { - id: string - name: string - worker: string - startedAt: Date - args: Array - finishedAt: Date | null - kwargs: Record - executionTime: number | null - returnValue: { return_value: any } | null - state: "success" | "running" | "failure" - }) { - return db.insert(tasksTable).values(values) - } - - async update( - taskId: string, - values: { - error?: string | null - executionTime?: number - finishedAt?: Date | null - returnValue?: { return_value: any } | null - state?: "success" | "running" | "failure" | "abandoned" - } - ) { - return db.update(tasksTable).set(values).where(eq(tasksTable.id, taskId)) - } - - async setAbandoned() { - return db - .update(tasksTable) - .set({ state: "abandoned" }) - .where(eq(tasksTable.state, "running")) - } -} - -export const tasksRepository = new TasksRepository() diff --git a/src/server/schemas/tasks.ts b/src/server/schemas/tasks.ts deleted file mode 100644 index d3871af..0000000 --- a/src/server/schemas/tasks.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { z } from "zod" - -export const taskStartedRequestSchema = z.object({ - worker: z.string(), - taskName: z.string(), - startedAt: z.coerce.date(), - args: z.array(z.unknown()), - kwargs: z.record(z.string(), z.unknown()), -}) - -export const taskExecutedRequestSchema = z.object({ - error: z.string().nullable(), - executionTime: z.number(), - finishedAt: z.coerce.date(), - returnValue: z.record(z.string(), z.unknown()).nullable(), -}) - -export const taskRouteParamsSchema = z.object({ - id: z.string(), -}) - -export const getTasksQueryParamsSchema = z.object({ - search: z.string().optional(), - limit: z.coerce.number().gte(0), - offset: z.coerce.number().gte(0), - state: z.enum(["success", "running", "failure", "abandoned"]).optional(), -}) diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json deleted file mode 100644 index 3c6e968..0000000 --- a/src/server/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../.nuxt/tsconfig.server.json" -} diff --git a/src/server/utils.ts b/src/server/utils.ts deleted file mode 100644 index bd977ca..0000000 --- a/src/server/utils.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NotFoundError } from "./exceptions" - -export const takeUniqueOrThrow = (values: T): T[number] => { - if (values.length !== 1) - throw new NotFoundError("Found non unique or inexistent value") - return values[0]! -} diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index 2e0faa4..0000000 --- a/src/utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -import dayjs from "dayjs" -import utc from "dayjs/plugin/utc" - -dayjs.extend(utc) - -export const formatDate = (date: string) => { - return dayjs.utc(date).local().format("MMM D, YYYY hh:mm A") -} diff --git a/tests/db-init.spec.ts b/tests/db-init.spec.ts new file mode 100644 index 0000000..9736e3d --- /dev/null +++ b/tests/db-init.spec.ts @@ -0,0 +1,52 @@ +// In-process sqlite checks for the initialization statements themselves: +// they must be re-runnable, and the FTS triggers must stay in sync with the +// tasks table (a stale FTS index silently returns wrong search results). +import { beforeAll, expect, test } from 'vitest' +import { DB_TABLE_NAMES } from '../shared/db/constants' + +process.env.TASKIQ_ADMIN_DB_DRIVER = 'sqlite' +process.env.TASKIQ_ADMIN_DB_FILE_PATH = ':memory:' +process.env.TASKIQ_ADMIN_BACKUP_FILE_PATH = ':memory:' +process.env.TASKIQ_ADMIN_API_TOKEN = 'supersecret' + +const { db, initializeDatabase } = await import('../shared/db') +const { tasksRepository } = await import('../server/repositories/tasks') +const { sql } = await import('drizzle-orm') + +const ftsCount = () => + db.get( + sql`SELECT count(*) AS c FROM ${sql.identifier(DB_TABLE_NAMES.tasksFts)}` + ).c as number + +const tasksCount = () => + db.get(sql`SELECT count(*) AS c FROM ${sql.identifier(DB_TABLE_NAMES.tasks)}`) + .c as number + +const createTask = (id: string, name: string) => + tasksRepository.create({ + id, + name, + state: 'queued', + queuedAt: new Date('2025-01-01T10:00:00Z') + } as any) + +beforeAll(async () => { + await initializeDatabase() +}) + +test('initialization statements are re-runnable', async () => { + await expect(initializeDatabase()).resolves.not.toThrow() + await expect(initializeDatabase()).resolves.not.toThrow() +}) + +test('fts index stays in sync on insert, update and delete', async () => { + await createTask('sync-1', 'myapp.tasks.send_email') + await createTask('sync-2', 'myapp.tasks.other') + expect(ftsCount()).toBe(tasksCount()) + + await tasksRepository.update('sync-2', { state: 'success' }) + expect(ftsCount()).toBe(tasksCount()) + + await db.delete((await import('../shared/db/schema')).tasksTable) + expect(ftsCount()).toBe(0) +}) diff --git a/tests/helpers/db-test-utils.ts b/tests/helpers/db-test-utils.ts new file mode 100644 index 0000000..11f0b27 --- /dev/null +++ b/tests/helpers/db-test-utils.ts @@ -0,0 +1,5 @@ +import { resetDatabaseForTests } from '../../shared/db' + +export async function resetDatabase() { + await resetDatabaseForTests() +} diff --git a/tests/helpers/search-fixtures.ts b/tests/helpers/search-fixtures.ts new file mode 100644 index 0000000..5cafff3 --- /dev/null +++ b/tests/helpers/search-fixtures.ts @@ -0,0 +1,61 @@ +// Shared task-name search fixtures, run against every db driver so a driver +// specific search implementation cannot silently diverge. +export const SEARCH_TASK_NAMES = [ + 'myapp.tasks.send_email', + 'myapp.tasks.SEND_sms', + 'other.pipeline.run', + 'weird%_name', + 'quote"name' +] as const + +export const SEARCH_CASES: { + title: string + query: string + expected: string[] +}[] = [ + { + title: 'matches a substring shorter than three characters', + query: 'se', + expected: ['myapp.tasks.SEND_sms', 'myapp.tasks.send_email'] + }, + { + title: 'matches a substring in the middle of a name', + query: 'send', + expected: ['myapp.tasks.SEND_sms', 'myapp.tasks.send_email'] + }, + { + title: 'is case insensitive', + query: 'SEND', + expected: ['myapp.tasks.SEND_sms', 'myapp.tasks.send_email'] + }, + { + title: 'matches a name part containing an underscore', + query: 'send_email', + expected: ['myapp.tasks.send_email'] + }, + { + title: 'matches a full dotted task name', + query: 'myapp.tasks.send_email', + expected: ['myapp.tasks.send_email'] + }, + { + title: 'treats % and _ as literal characters, not wildcards', + query: 'rd%_n', + expected: ['weird%_name'] + }, + { + title: 'does not let % act as a wildcard inside the query', + query: 'p%run', + expected: [] + }, + { + title: 'handles a double quote in the query', + query: 'quote"na', + expected: ['quote"name'] + }, + { + title: 'returns nothing for an unknown name', + query: 'nope', + expected: [] + } +] diff --git a/tests/helpers/search-suite.ts b/tests/helpers/search-suite.ts new file mode 100644 index 0000000..b52d764 --- /dev/null +++ b/tests/helpers/search-suite.ts @@ -0,0 +1,75 @@ +import { $fetch } from '@nuxt/test-utils' +import { beforeAll, describe, expect, test } from 'vitest' +import { SEARCH_CASES, SEARCH_TASK_NAMES } from './search-fixtures' + +const token = { 'access-token': 'supersecret' } + +type TasksResponse = { + count: number + tasks: { id: string; name: string; state: string }[] +} + +const fetchTasks = (query: Record) => + $fetch('/api/tasks', { + query: { limit: 100, offset: 0, ...query } + }) + +const seedTasks = async (idPrefix: string) => { + for (const [index, taskName] of SEARCH_TASK_NAMES.entries()) { + await $fetch(`/api/tasks/${idPrefix}-${index}/queued`, { + method: 'POST', + headers: token, + body: { + taskName, + args: [], + kwargs: {}, + worker: 'w', + queuedAt: new Date('2025-01-01T10:00:00Z').toISOString() + } + }) + } +} + +export const registerSearchTests = (driver: 'sqlite' | 'postgres') => { + describe(`task name search (${driver})`, () => { + beforeAll(async () => { + await seedTasks('search') + }) + + for (const { title, query, expected } of SEARCH_CASES) { + test(`${title}: ${JSON.stringify(query)}`, async () => { + const result = await fetchTasks({ search: query }) + expect(result.tasks.map((task) => task.name).sort()).toEqual( + [...expected].sort() + ) + }) + } + + test('count matches the number of returned rows', async () => { + const result = await fetchTasks({ search: 'send' }) + expect(result.count).toBe(result.tasks.length) + }) + + test('count reflects the filter, not the whole table', async () => { + const all = await fetchTasks({}) + const filtered = await fetchTasks({ search: 'send' }) + expect(all.count).toBe(SEARCH_TASK_NAMES.length) + expect(filtered.count).toBe(2) + }) + + test('name search combines with the state filter', async () => { + const matching = await fetchTasks({ search: 'send', state: 'queued' }) + expect(matching.count).toBe(2) + + const nonMatching = await fetchTasks({ search: 'send', state: 'success' }) + expect(nonMatching.count).toBe(0) + expect(nonMatching.tasks).toEqual([]) + }) + + test('pagination applies to the filtered set', async () => { + const firstPage = await fetchTasks({ search: 'send', limit: 1 }) + expect(firstPage.tasks).toHaveLength(1) + expect(firstPage.count).toBe(2) + }) + }) +} diff --git a/tests/task-flow.nuxt.spec.ts b/tests/task-flow.nuxt.spec.ts new file mode 100644 index 0000000..c6a149a --- /dev/null +++ b/tests/task-flow.nuxt.spec.ts @@ -0,0 +1,70 @@ +import { setup, $fetch } from '@nuxt/test-utils' +import { resolve } from 'path' +import { expect, test } from 'vitest' + +await setup({ + rootDir: resolve(__dirname, '../..'), + server: true, // up the Nitro server + env: { + NODE_ENV: 'test', + TASKIQ_ADMIN_DB_DRIVER: 'sqlite', + TASKIQ_ADMIN_DB_FILE_PATH: ':memory:', + TASKIQ_ADMIN_BACKUP_FILE_PATH: ':memory:', + TASKIQ_ADMIN_API_TOKEN: 'supersecret' + } +}) + +const id = 'nuxt-spec-1' +const token = { 'access-token': 'supersecret' } +const queued = new Date('2025-01-01T10:00:00Z') +const start = new Date('2025-01-01T10:00:02Z') +const finish = new Date('2025-01-01T10:00:05Z') + +test('started → queued → executed saves dates', async () => { + await $fetch(`/api/tasks/${id}/started`, { + method: 'POST', + headers: token, + body: { + taskName: 'demo', + args: [], + kwargs: {}, + worker: 'w', + startedAt: start.toISOString() + } + }) + + await $fetch(`/api/tasks/${id}/queued`, { + method: 'POST', + headers: token, + body: { + taskName: 'demo', + args: [], + kwargs: {}, + worker: 'w', + queuedAt: queued.toISOString() + } + }) + + await $fetch(`/api/tasks/${id}/executed`, { + method: 'POST', + headers: token, + body: { + error: null, + executionTime: 3, + finishedAt: finish.toISOString(), + returnValue: { return_value: 'ok' } + } + }) + + const task = await $fetch<{ + state: string + queuedAt: string + startedAt: string + finishedAt: string + }>(`/api/tasks/${id}`) + + expect(task?.state).toBe('success') + expect(task?.queuedAt).toBe(queued.toISOString()) + expect(task?.startedAt).toBe(start.toISOString()) + expect(task?.finishedAt).toBe(finish.toISOString()) +}) diff --git a/tests/task-search.nuxt.spec.ts b/tests/task-search.nuxt.spec.ts new file mode 100644 index 0000000..26daa06 --- /dev/null +++ b/tests/task-search.nuxt.spec.ts @@ -0,0 +1,17 @@ +import { setup } from '@nuxt/test-utils' +import { resolve } from 'path' +import { registerSearchTests } from './helpers/search-suite' + +await setup({ + rootDir: resolve(__dirname, '../..'), + server: true, + env: { + NODE_ENV: 'test', + TASKIQ_ADMIN_DB_DRIVER: 'sqlite', + TASKIQ_ADMIN_DB_FILE_PATH: ':memory:', + TASKIQ_ADMIN_BACKUP_FILE_PATH: ':memory:', + TASKIQ_ADMIN_API_TOKEN: 'supersecret' + } +}) + +registerSearchTests('sqlite') diff --git a/tests/task-search.postgres.nuxt.spec.ts b/tests/task-search.postgres.nuxt.spec.ts new file mode 100644 index 0000000..0d1486c --- /dev/null +++ b/tests/task-search.postgres.nuxt.spec.ts @@ -0,0 +1,36 @@ +// Runs the shared search suite against postgres. +// Skipped unless TASKIQ_ADMIN_TEST_DB_URL points at a disposable database, +// because the suite truncates the tasks table. +import { setup } from '@nuxt/test-utils' +import { resolve } from 'path' +import { describe, test } from 'vitest' +import { registerSearchTests } from './helpers/search-suite' + +const dbUrl = process.env.TASKIQ_ADMIN_TEST_DB_URL + +if (!dbUrl) { + describe.skip('task name search (postgres)', () => { + test('needs TASKIQ_ADMIN_TEST_DB_URL', () => {}) + }) +} else { + process.env.TASKIQ_ADMIN_DB_DRIVER = 'postgres' + process.env.TASKIQ_ADMIN_DB_URL = dbUrl + process.env.TASKIQ_ADMIN_API_TOKEN = 'supersecret' + + const { resetDatabaseForTests } = await import('../shared/db') + + await setup({ + rootDir: resolve(__dirname, '../..'), + server: true, + env: { + NODE_ENV: 'test', + TASKIQ_ADMIN_DB_DRIVER: 'postgres', + TASKIQ_ADMIN_DB_URL: dbUrl, + TASKIQ_ADMIN_API_TOKEN: 'supersecret' + } + }) + + await resetDatabaseForTests() + + registerSearchTests('postgres') +}