From 72f4d162a1c8e9dc8875aea85b9b0d5e74a1179a Mon Sep 17 00:00:00 2001 From: Elliot Braem Date: Mon, 26 Jan 2026 14:43:12 -0600 Subject: [PATCH 1/4] updates project --- .claude/skills/api/SKILL.md | 42 +- .claude/skills/host/SKILL.md | 81 +- .claude/skills/ui/SKILL.md | 65 +- host/.env.example => .env.example | 12 +- .gitignore | 2 + README.md | 91 +- api/README.md | 80 +- api/drizzle.config.ts | 10 +- api/package.json | 32 +- api/vitest.config.ts | 4 + bos.config.json | 30 +- bun.lock | 931 +++++++----------- host/README.md | 197 ++-- host/bootstrap.ts | 81 ++ host/index.html | 147 --- host/package.json | 50 +- host/rsbuild.config.ts | 163 +-- host/server.ts | 315 +----- host/src/components.tsx | 365 ------- host/src/config.ts | 78 -- host/src/db/index.ts | 14 - host/src/federation.server.ts | 44 - host/src/federation.ts | 53 - host/src/index.client.tsx | 29 - host/src/layers/index.ts | 20 + host/src/lib/api-client.server.ts | 27 - host/src/lib/auth.ts | 57 -- host/src/lib/rate-limit.ts | 85 -- host/src/main.tsx | 61 -- host/src/middleware/rate-limit.ts | 76 -- host/src/program.ts | 372 +++++++ {ui => host}/src/reportWebVitals.ts | 0 host/src/routers/index.ts | 24 - host/src/runtime.ts | 117 --- host/src/scripts/promote-admin.ts | 51 - host/src/services/auth.ts | 62 ++ host/src/services/config.ts | 194 ++++ host/src/services/context.ts | 35 + host/src/services/database.ts | 53 + host/src/services/errors.ts | 26 + host/src/services/federation.server.ts | 99 ++ host/src/services/plugins.ts | 125 +++ host/src/services/router.ts | 28 + host/src/ssr.tsx | 254 ----- host/src/types.ts | 17 + host/src/ui.tsx | 4 +- host/src/utils/logger.ts | 7 + host/tests/integration/seo.test.ts | 518 ++++++++++ host/tests/integration/ssr.test.ts | 360 +++++++ host/vitest.config.ts | 15 + package.json | 78 +- turbo.json | 38 - ui/.cta.json | 2 +- ui/README.md | 96 +- ui/index.html | 52 - ui/package.json | 74 +- ui/rsbuild.config.ts | 285 +++--- ui/src/assets/logo_full.png | Bin 79058 -> 0 bytes ui/src/bootstrap.tsx | 96 -- .../chat/{ChatInput.tsx => chat-input.tsx} | 0 .../{ChatMessage.tsx => chat-message.tsx} | 0 .../chat/{ChatPage.tsx => chat-page.tsx} | 4 +- .../kv/{KVEditor.tsx => kv-editor.tsx} | 0 ui/src/components/ui/markdown.tsx | 189 ++++ ui/src/components/user-nav.tsx | 49 + ui/src/env.d.ts | 9 +- ui/src/hydrate.tsx | 36 + ui/src/integrations/api/index.ts | 1 - .../tanstack-query/root-provider.tsx | 29 - ui/src/lib/auth-client.ts | 47 +- ui/src/lib/auth-utils.ts | 13 +- ui/src/lib/session.ts | 1 + ui/src/main.tsx | 16 - ui/src/providers/index.tsx | 52 +- ui/src/remote.tsx | 1 - ui/src/routeTree.gen.ts | 77 +- ui/src/router.server.tsx | 173 ++++ ui/src/router.tsx | 97 +- ui/src/routes/__root.tsx | 160 ++- ui/src/routes/_layout.tsx | 70 +- ui/src/routes/_layout/_authenticated.tsx | 3 +- .../routes/_layout/_authenticated/index.tsx | 2 +- .../_layout/_authenticated/settings.tsx | 2 +- ui/src/routes/_layout/_page.tsx | 13 - .../routes/_layout/_page/privacy-policy.tsx | 159 --- .../routes/_layout/_page/terms-of-service.tsx | 156 --- ui/src/routes/_layout/login.tsx | 48 +- ui/src/types/index.ts | 64 +- ui/src/utils/orpc.ts | 3 +- 89 files changed, 3954 insertions(+), 3844 deletions(-) rename host/.env.example => .env.example (65%) create mode 100644 host/bootstrap.ts delete mode 100644 host/index.html delete mode 100644 host/src/components.tsx delete mode 100644 host/src/config.ts delete mode 100644 host/src/db/index.ts delete mode 100644 host/src/federation.server.ts delete mode 100644 host/src/federation.ts delete mode 100644 host/src/index.client.tsx create mode 100644 host/src/layers/index.ts delete mode 100644 host/src/lib/api-client.server.ts delete mode 100644 host/src/lib/auth.ts delete mode 100644 host/src/lib/rate-limit.ts delete mode 100644 host/src/main.tsx delete mode 100644 host/src/middleware/rate-limit.ts create mode 100644 host/src/program.ts rename {ui => host}/src/reportWebVitals.ts (100%) delete mode 100644 host/src/routers/index.ts delete mode 100644 host/src/runtime.ts delete mode 100644 host/src/scripts/promote-admin.ts create mode 100644 host/src/services/auth.ts create mode 100644 host/src/services/config.ts create mode 100644 host/src/services/context.ts create mode 100644 host/src/services/database.ts create mode 100644 host/src/services/errors.ts create mode 100644 host/src/services/federation.server.ts create mode 100644 host/src/services/plugins.ts create mode 100644 host/src/services/router.ts delete mode 100644 host/src/ssr.tsx create mode 100644 host/src/types.ts create mode 100644 host/src/utils/logger.ts create mode 100644 host/tests/integration/seo.test.ts create mode 100644 host/tests/integration/ssr.test.ts create mode 100644 host/vitest.config.ts delete mode 100644 turbo.json delete mode 100644 ui/index.html delete mode 100644 ui/src/assets/logo_full.png delete mode 100644 ui/src/bootstrap.tsx rename ui/src/components/chat/{ChatInput.tsx => chat-input.tsx} (100%) rename ui/src/components/chat/{ChatMessage.tsx => chat-message.tsx} (100%) rename ui/src/components/chat/{ChatPage.tsx => chat-page.tsx} (98%) rename ui/src/components/kv/{KVEditor.tsx => kv-editor.tsx} (100%) create mode 100644 ui/src/components/ui/markdown.tsx create mode 100644 ui/src/components/user-nav.tsx create mode 100644 ui/src/hydrate.tsx delete mode 100644 ui/src/integrations/api/index.ts delete mode 100644 ui/src/integrations/tanstack-query/root-provider.tsx delete mode 100644 ui/src/main.tsx delete mode 100644 ui/src/remote.tsx create mode 100644 ui/src/router.server.tsx delete mode 100644 ui/src/routes/_layout/_page.tsx delete mode 100644 ui/src/routes/_layout/_page/privacy-policy.tsx delete mode 100644 ui/src/routes/_layout/_page/terms-of-service.tsx diff --git a/.claude/skills/api/SKILL.md b/.claude/skills/api/SKILL.md index da03fcd..48ee41d 100644 --- a/.claude/skills/api/SKILL.md +++ b/.claude/skills/api/SKILL.md @@ -14,14 +14,17 @@ Review the `api/` package for quality, consistency, and every-plugin best practi ``` api/ ├── src/ -│ ├── contract.ts # oRPC route definitions -│ ├── index.ts # Plugin definition (createPlugin) +│ ├── contract.ts # oRPC route definitions +│ ├── index.ts # Plugin definition (createPlugin) │ ├── db/ -│ │ └── schema.ts # Drizzle ORM schema -│ ├── services/ -│ │ └── agent.ts # NEAR AI integration -│ └── store.ts # Database connection -├── plugin.dev.ts # Local dev configuration +│ │ ├── index.ts # Database connection layer +│ │ ├── schema.ts # Drizzle ORM schema +│ │ └── migrations/ # SQL migration files +│ └── services/ +│ ├── index.ts # Service exports +│ └── agent.ts # NEAR AI integration +├── plugin.dev.ts # Local dev configuration +├── drizzle.config.ts # Drizzle config └── package.json ``` @@ -35,40 +38,43 @@ api/ ### 2. Plugin Structure - [ ] Uses `createPlugin()` from every-plugin -- [ ] Variables and secrets properly typed -- [ ] Context schema defined -- [ ] Initialize/shutdown handlers implemented +- [ ] Variables and secrets properly typed with Zod schemas +- [ ] Context schema defined (nearAccountId, role) +- [ ] Initialize returns `{ db, agentService }` +- [ ] Shutdown handler implemented ### 3. Database Schema -- [ ] Tables defined for core features (conversations, messages, key-value store) +- [ ] Tables defined: `conversation`, `message`, `kvStore` - [ ] Proper indexes for query performance - [ ] Relations defined correctly with cascading deletes -- [ ] Timestamps use Date type +- [ ] Per-user isolation via `nearAccountId` ### 4. Services -- [ ] AgentService integrates NEAR AI Cloud +- [ ] AgentService integrates NEAR AI Cloud via OpenAI SDK - [ ] Streaming chat implementation with async generators - [ ] Conversation history management (context window) - [ ] Graceful fallback when API key not configured ### 5. Router Handlers -- [ ] Authentication middleware applied +- [ ] `requireAuth` middleware for protected routes +- [ ] `requireAdmin` middleware for admin routes - [ ] Proper error handling with ORPCError - [ ] Input validation via contract - [ ] Date serialization to ISO strings ### 6. Configuration - [ ] `plugin.dev.ts` matches production config -- [ ] Secrets loaded from environment -- [ ] Default values are sensible +- [ ] Secrets: `API_DATABASE_URL`, `API_DATABASE_AUTH_TOKEN`, `NEAR_AI_API_KEY`, `NEAR_AI_BASE_URL` +- [ ] Variables: `NEAR_AI_MODEL`, `NEAR_AI_BASE_URL` ## Key Files to Check 1. `src/contract.ts` - API contract definitions 2. `src/index.ts` - Plugin implementation 3. `src/db/schema.ts` - Database tables -4. `src/services/agent.ts` - NEAR AI integration -5. `plugin.dev.ts` - Development configuration +4. `src/db/index.ts` - Database connection +5. `src/services/agent.ts` - NEAR AI integration +6. `plugin.dev.ts` - Development configuration ## Output Format diff --git a/.claude/skills/host/SKILL.md b/.claude/skills/host/SKILL.md index eda5162..42ef174 100644 --- a/.claude/skills/host/SKILL.md +++ b/.claude/skills/host/SKILL.md @@ -13,62 +13,91 @@ Review the `host/` package for quality, consistency, and Module Federation best ``` host/ -├── server.ts # HTTP server entry point +├── server.ts # Entry point +├── bootstrap.ts # Remote host loader ├── src/ -│ ├── config.ts # Runtime config loader (bos.config.json) -│ ├── runtime.ts # Plugin initialization -│ ├── routers/ # Route handlers -│ └── auth/ # Better-Auth setup -├── .env.example # Environment template +│ ├── program.ts # Main server program +│ ├── ui.tsx # UI rendering +│ ├── types.ts # Type definitions +│ ├── db/ +│ │ └── schema/ +│ │ └── auth.ts # Auth schema +│ ├── layers/ +│ │ └── index.ts # Effect layers composition +│ ├── lib/ +│ │ └── schemas.ts # Shared schemas +│ ├── services/ +│ │ ├── auth.ts # Better-Auth setup +│ │ ├── config.ts # Runtime config loader (bos.config.json) +│ │ ├── context.ts # Request context +│ │ ├── database.ts # Database connection +│ │ ├── errors.ts # Error types +│ │ ├── federation.server.ts # UI module loading +│ │ ├── plugins.ts # API plugin loading +│ │ └── router.ts # Router creation +│ └── utils/ +│ └── logger.ts # Logging utility +├── migrations/ # Drizzle migrations +├── drizzle.config.ts # Drizzle config +├── rsbuild.config.ts # Build configuration └── package.json -bos.config.json # Central runtime configuration (root level) +bos.config.json # Central runtime configuration (root level) ``` ## Review Checklist ### 1. Server Setup -- [ ] Hono.js configured correctly -- [ ] CORS and security headers -- [ ] Static file serving +- [ ] Hono.js configured correctly in `src/program.ts` +- [ ] CORS configured with `CORS_ORIGIN` or config URLs +- [ ] Health endpoint at `/health` - [ ] Error handling middleware ### 2. Configuration Loading -- [ ] `bos.config.json` parsed correctly +- [ ] `src/services/config.ts` parses `bos.config.json` correctly - [ ] Environment-based URL switching (dev/prod) -- [ ] Secret template injection (`{{VAR_NAME}}`) +- [ ] Secret loading from environment variables - [ ] Variables vs secrets distinction ### 3. Plugin Runtime -- [ ] Uses `createPluginRuntime()` from every-plugin +- [ ] `src/services/plugins.ts` uses every-plugin runtime - [ ] Secrets extracted from environment -- [ ] Plugin URL resolved correctly +- [ ] Plugin URL resolved from config - [ ] Error handling for plugin load failures ### 4. Authentication -- [ ] Better-Auth configured -- [ ] NEAR Protocol auth (better-near-auth) +- [ ] `src/services/auth.ts` uses Better-Auth +- [ ] NEAR Protocol auth via better-near-auth - [ ] Session management -- [ ] Protected routes +- [ ] Auth routes at `/api/auth/*` ### 5. Module Federation -- [ ] UI remote loaded correctly -- [ ] SSR/CSR handling -- [ ] Fallback behavior +- [ ] `src/services/federation.server.ts` loads UI remote +- [ ] SSR rendering via `loadRouterModule` +- [ ] Fallback behavior when module not loaded ### 6. bos.config.json - [ ] All apps configured (host, ui, api) - [ ] Development and production URLs - [ ] API variables include NEAR_AI_MODEL - [ ] API secrets include all required keys +- [ ] Host secrets include auth secrets + +### 7. Effect-TS Architecture +- [ ] Services use Effect Service pattern +- [ ] Layers composed in `src/layers/index.ts` +- [ ] Proper error handling with ConfigError, etc. ## Key Files to Check -1. `server.ts` - Main entry point -2. `src/config.ts` - Configuration loader -3. `src/runtime.ts` - Plugin initialization -4. `src/routers/index.ts` - Route merging -5. `../bos.config.json` - Central config -6. `.env.example` - Required environment variables +1. `server.ts` - Entry point +2. `src/program.ts` - Main server logic +3. `src/services/config.ts` - Configuration loader +4. `src/services/auth.ts` - Authentication setup +5. `src/services/plugins.ts` - Plugin loading +6. `src/services/federation.server.ts` - UI module loading +7. `src/services/router.ts` - Route creation +8. `src/layers/index.ts` - Layer composition +9. `../bos.config.json` - Central config ## Output Format diff --git a/.claude/skills/ui/SKILL.md b/.claude/skills/ui/SKILL.md index bdae1b1..5da75ad 100644 --- a/.claude/skills/ui/SKILL.md +++ b/.claude/skills/ui/SKILL.md @@ -14,11 +14,44 @@ Review the `ui/` package for quality, consistency, and best practices. ``` ui/ ├── src/ -│ ├── components/ # React components (chat) -│ ├── routes/ # TanStack Router file-based routes -│ ├── integrations/ # API client setup -│ └── utils/ # Utilities (orpc client) -├── rsbuild.config.ts # Build configuration +│ ├── router.tsx # Client router +│ ├── router.server.tsx # Server router (SSR) +│ ├── hydrate.tsx # Client hydration entry +│ ├── components/ +│ │ ├── index.ts # Public component exports +│ │ ├── chat/ # Chat feature components +│ │ │ ├── chat-input.tsx +│ │ │ ├── chat-message.tsx +│ │ │ └── chat-page.tsx +│ │ ├── kv/ # Key-value editor +│ │ │ └── kv-editor.tsx +│ │ └── ui/ # shadcn/ui primitives +│ ├── hooks/ +│ │ ├── index.ts +│ │ └── use-client.ts +│ ├── lib/ +│ │ ├── auth-client.ts # better-auth client +│ │ ├── auth-utils.ts # Auth utilities +│ │ ├── session.ts # Session management +│ │ └── utils.ts # General utilities (cn) +│ ├── providers/ +│ │ └── index.tsx # Context providers +│ ├── routes/ # TanStack file-based routes +│ │ ├── __root.tsx +│ │ ├── _layout.tsx +│ │ └── _layout/ +│ │ ├── _authenticated.tsx +│ │ ├── login.tsx +│ │ └── _authenticated/ +│ ├── types/ +│ │ └── index.ts +│ ├── utils/ +│ │ ├── orpc.ts # oRPC client setup +│ │ └── stream.ts # Streaming utilities +│ └── integrations/ +│ └── tanstack-query/ +│ └── devtools.tsx +├── rsbuild.config.ts # Build configuration └── package.json ``` @@ -29,35 +62,47 @@ ui/ - [ ] Props are properly typed with TypeScript - [ ] No unused imports or variables - [ ] Proper error boundaries and loading states +- [ ] Files follow **kebab-case** naming convention ### 2. Route Structure - [ ] Routes follow TanStack Router conventions - [ ] Protected routes use `_authenticated` layout +- [ ] Admin routes use `_authenticated/_admin` layout - [ ] Route components are properly exported ### 3. API Integration - [ ] Uses oRPC client from `utils/orpc.ts` - [ ] TanStack Query for data fetching +- [ ] Streaming via `utils/stream.ts` - [ ] Proper error handling with toast notifications ### 4. Styling - [ ] Semantic color tokens (not hardcoded colors) - [ ] Responsive design patterns - [ ] shadcn/ui components used consistently +- [ ] Tailwind CSS v4 conventions -### 5. Performance +### 5. Module Federation +- [ ] Exports defined in `rsbuild.config.ts` +- [ ] Shared dependencies configured correctly +- [ ] SSR build separate from client build + +### 6. Performance - [ ] Proper use of `useMemo` and `useCallback` - [ ] No unnecessary re-renders - [ ] Lazy loading for heavy components ## Key Files to Check -1. `src/routes/_layout/_authenticated/chat/index.tsx` - Main chat page -2. `src/components/chat/ChatPage.tsx` - Chat page component -3. `src/components/chat/ChatInput.tsx` - Chat input component -4. `src/components/chat/ChatMessage.tsx` - Message display +1. `src/router.tsx` - Client router setup +2. `src/router.server.tsx` - SSR router +3. `src/components/index.ts` - Public exports +4. `src/components/chat/chat-page.tsx` - Chat feature 5. `src/utils/orpc.ts` - API client setup 6. `src/utils/stream.ts` - Streaming utilities +7. `src/lib/auth-client.ts` - Auth client +8. `src/routes/_layout/_authenticated.tsx` - Auth guard +9. `rsbuild.config.ts` - Build configuration ## Output Format diff --git a/host/.env.example b/.env.example similarity index 65% rename from host/.env.example rename to .env.example index 61b593b..1b6ffce 100644 --- a/host/.env.example +++ b/.env.example @@ -1,13 +1,17 @@ -# Better Auth BETTER_AUTH_SECRET= -BETTER_AUTH_URL=http://localhost:3001 -# CORS -CORS_ORIGIN=http://localhost:3001,http://localhost:3002 +# Host Database +HOST_DATABASE_URL=file:./database.db +HOST_DATABASE_AUTH_TOKEN= # for Turso + +# API Plugin Database (path relative to host/) +API_DATABASE_URL=file:../api/api.db +API_DATABASE_AUTH_TOKEN= # for Turso # Host Database HOST_DATABASE_URL=file:./database.db HOST_DATABASE_AUTH_TOKEN= # for Turso + # API Plugin Database (path relative to host/) API_DATABASE_URL=file:../api/api.db API_DATABASE_AUTH_TOKEN= # for Turso diff --git a/.gitignore b/.gitignore index 7920b4a..61f2c83 100644 --- a/.gitignore +++ b/.gitignore @@ -292,9 +292,11 @@ fabric.properties # near .near/data +.bos # db /**/*.db .turbo **/*.sqlite + diff --git a/README.md b/README.md index e8fb3fe..32dfaa2 100644 --- a/README.md +++ b/README.md @@ -13,23 +13,24 @@ Built with React, Hono.js, oRPC, Better-Auth, Module Federation, and NEAR AI Clo git clone https://github.com/NEARBuilders/cyborg.git && cd cyborg bun install -# 2. Create environment files -cp host/.env.example host/.env -cp api/.env.example api/.env +# 2. Create environment file +cp .env.example .env -# 3. Initialize database -bun db:migrate +# 3. Initialize (runs database migrations) +bun init # 4. Start development server bun dev ``` -Visit [http://localhost:3001](http://localhost:3001) to see the application. +> **Note:** You may see some warnings during startup - this is normal and the application will still function correctly. + +Visit [http://localhost:3000](http://localhost:3000) to see the application. ### Enable AI Chat 1. Get an API key from [cloud.near.ai](https://cloud.near.ai) -2. Add to `api/.env`: `NEAR_AI_API_KEY=your_key_here` +2. Add to `.env`: `NEAR_AI_API_KEY=your_key_here` 3. Restart with `bun dev` ## Documentation @@ -102,23 +103,39 @@ All runtime configuration lives in `bos.config.json`: ```json { "account": "example.near", + "create": { + "project": "yourorg/yourproject", + "ui": "yourorg/yourproject/ui", + "api": "yourorg/yourproject/api", + "host": "yourorg/yourproject/host" + }, "app": { "host": { "title": "App Title", - "development": "http://localhost:3001", - "production": "https://example.com" + "description": "App description", + "development": "http://localhost:3000", + "production": "https://example.com", + "secrets": ["HOST_DATABASE_URL", "HOST_DATABASE_AUTH_TOKEN", "BETTER_AUTH_SECRET", "BETTER_AUTH_URL"] }, "ui": { "name": "ui", "development": "http://localhost:3002", - "production": "https://cdn.example.com/ui/remoteEntry.js" + "production": "https://cdn.example.com/ui/remoteEntry.js", + "exposes": { + "App": "./App", + "components": "./components", + "providers": "./providers", + "types": "./types" + } }, "api": { "name": "api", "development": "http://localhost:3014", "production": "https://cdn.example.com/api/remoteEntry.js", - "variables": {}, - "secrets": ["API_DATABASE_URL", "API_DATABASE_AUTH_TOKEN"] + "variables": { + "NEAR_AI_MODEL": "deepseek-ai/DeepSeek-V3.1" + }, + "secrets": ["API_DATABASE_URL", "API_DATABASE_AUTH_TOKEN", "NEAR_AI_API_KEY", "NEAR_AI_BASE_URL"] } } } @@ -130,53 +147,21 @@ All runtime configuration lives in `bos.config.json`: - Update CDN URLs without code changes - Template injection for secrets -## Rate Limiting - -Built-in rate limiting protects against abuse: - -| Endpoint | Limit | Window | -| --------- | ------------- | -------- | -| Chat/AI | 20 requests | 1 minute | -| Key-Value | 100 requests | 1 minute | -| Auth | 100 requests | 1 minute | -| Global | 1000 requests | 1 minute | - -Rate limit headers included in responses: - -- `X-RateLimit-Limit`: Maximum requests allowed -- `X-RateLimit-Remaining`: Requests remaining -- `X-RateLimit-Reset`: Unix timestamp when window resets - ## Health Checks -Two health endpoints are available: +Health endpoint is available: -- `GET /health` - Basic liveness check (always returns 200 if server is running) -- `GET /health/ready` - Readiness check with dependency status - -Example readiness response: - -```json -{ - "status": "ready", - "checks": { - "database": true, - "ai": true - }, - "timestamp": "2025-01-17T12:00:00.000Z" -} -``` - -Use `/health/ready` for load balancer health checks. +- `GET /health` - Basic liveness check (returns "OK" if server is running) ## Available Scripts ```bash # Development -bun dev # All services (API: 3014, UI: 3002, Host: 3001) -bun dev:api # API plugin only +bun dev # All services (API: 3014, UI: 3002, Host: 3000) bun dev:ui # UI remote only +bun dev:api # API plugin only bun dev:host # Host server only +bun dev:proxy # Host with API proxied to production # Production bun build # Build all packages @@ -185,13 +170,14 @@ bun build:ui # Build UI remote → uploads to CDN bun build:host # Build host server # Database +bun init # Initialize database (runs migrations) bun db:migrate # Run migrations bun db:push # Push schema changes bun db:studio # Open Drizzle Studio +bun db:generate # Generate migrations # Testing -bun test # Run all tests -bun typecheck # Type checking +bun typecheck # Type checking all workspaces ``` ## Development Workflow @@ -218,10 +204,9 @@ This project evolved from the [every-plugin template](https://github.com/near-ev ### Authentication & Roles -- **Better-Auth** with admin plugin (`host/src/lib/auth.ts`) +- **Better-Auth** with admin plugin (`host/src/services/auth.ts`) - **User roles** - "user" (default) and "admin" - **Admin routes** - Protected via TanStack Router (`ui/src/routes/_layout/_authenticated/_admin.tsx`) -- **Role management** - Promote users via: `bun run promote-admin ` ### Database diff --git a/api/README.md b/api/README.md index 0feb48c..b7c54e8 100644 --- a/api/README.md +++ b/api/README.md @@ -1,19 +1,19 @@ # api -[every-plugin](https://github.com/near-everything/every-plugin) based API. +[every-plugin](https://github.com/near-everything/every-plugin) based API with NEAR AI Cloud integration. ## Plugin Architecture Built with **every-plugin** framework (Rspack + Module Federation): -``` +```bash ┌─────────────────────────────────────────────────────────┐ │ createPlugin() │ ├─────────────────────────────────────────────────────────┤ -│ variables: { ... } │ -│ secrets: { ... } │ +│ variables: { NEAR_AI_MODEL, NEAR_AI_BASE_URL } │ +│ secrets: { API_DATABASE_URL, NEAR_AI_API_KEY, ... } │ │ contract: oRPC route definitions │ -│ initialize(): Effect → services │ +│ initialize(): Effect → { db, agentService } │ │ createRouter(): handlers using services │ └─────────────────────────────────────────────────────────┘ ↓ @@ -21,45 +21,51 @@ Built with **every-plugin** framework (Rspack + Module Federation): │ Host Integration │ ├─────────────────────────────────────────────────────────┤ │ bos.config.json → plugin URL + secrets │ -│ runtime.ts → createPluginRuntime().usePlugin() │ -│ routers/index.ts → merge plugin.router into AppRouter │ +│ host/src/services/plugins.ts → loadPlugin() │ +│ host/src/services/router.ts → merge plugin router │ └─────────────────────────────────────────────────────────┘ ``` -**Plugin Structure:** - -- `contract.ts` - oRPC contract definition (routes, schemas) -- `index.ts` - Plugin initialization + router handlers -- `db/schema.ts` - Database schema (conversations, messages, KV store) -- `services/` - Business logic (agent service for AI chat) -- `db/migrations/` - Database migrations - -**Extending with more plugins:** +## Directory Structure -Each domain can be its own plugin with independent: - -- Contract definition -- Initialization logic -- Router handlers -- Database schema +``` +api/ +├── src/ +│ ├── contract.ts # oRPC contract definition +│ ├── index.ts # Plugin definition (createPlugin) +│ ├── db/ +│ │ ├── index.ts # Database connection layer +│ │ ├── schema.ts # Drizzle ORM schema +│ │ └── migrations/ # SQL migration files +│ └── services/ +│ ├── index.ts # Service exports +│ └── agent.ts # NEAR AI integration +├── plugin.dev.ts # Local dev configuration +├── drizzle.config.ts # Drizzle Kit config +└── package.json +``` ## Tech Stack - **Framework**: every-plugin + oRPC - **Effects**: Effect-TS for service composition - **Database**: SQLite (libsql) + Drizzle ORM +- **AI**: OpenAI SDK (NEAR AI Cloud compatible) ## Available Scripts -- `bun dev` - Start dev server -- `bun build` - Build plugin +- `bun dev` - Start dev server (port 3014) +- `bun build` - Build plugin (deploys to CDN) - `bun test` - Run tests +- `bun typecheck` - Type checking - `bun db:push` - Push schema to database +- `bun db:generate` - Generate migrations +- `bun db:migrate` - Run migrations - `bun db:studio` - Open Drizzle Studio ## Configuration -**Root config** (`bos.config.json`): +**bos.config.json**: ```json { @@ -67,9 +73,10 @@ Each domain can be its own plugin with independent: "api": { "name": "api", "development": "http://localhost:3014", - "production": "https://", + "production": "https://cdn.example.com/api", "variables": { - "NEAR_AI_MODEL": "deepseek-ai/DeepSeek-V3.1" + "NEAR_AI_MODEL": "deepseek-ai/DeepSeek-V3.1", + "NEAR_AI_BASE_URL": "https://cloud-api.near.ai/v1" }, "secrets": [ "API_DATABASE_URL", @@ -81,3 +88,22 @@ Each domain can be its own plugin with independent: } } ``` + +## API Endpoints + +| Route | Method | Description | +|-------|--------|-------------| +| `/api/ping` | GET | Health check | +| `/api/protected` | GET | Auth test endpoint | +| `/api/admin/stats` | GET | Admin statistics | +| `/api/kv/:key` | GET | Get key-value entry | +| `/api/kv` | POST | Set key-value entry | +| `/api/chat` | POST | Send chat message | +| `/api/chat/stream` | POST | Stream chat response | +| `/api/conversation/:id` | GET | Get conversation history | + +## Database Schema + +- **conversation** - Chat conversations per user +- **message** - Messages within conversations +- **kvStore** - Per-user key-value storage (composite key: `key + nearAccountId`) diff --git a/api/drizzle.config.ts b/api/drizzle.config.ts index 5cee85f..327cd25 100644 --- a/api/drizzle.config.ts +++ b/api/drizzle.config.ts @@ -1,11 +1,11 @@ -import { defineConfig } from "drizzle-kit"; +import { defineConfig } from 'drizzle-kit'; export default defineConfig({ - schema: "./src/db/schema.ts", - out: "./src/db/migrations", - dialect: "turso", + schema: './src/db/schema.ts', + out: './src/db/migrations', + dialect: 'turso', dbCredentials: { - url: process.env.API_DATABASE_URL || "file:./api.db", + url: process.env.API_DATABASE_URL || 'file:./database.db', authToken: process.env.API_DATABASE_AUTH_TOKEN, }, verbose: true, diff --git a/api/package.json b/api/package.json index 5b4493d..58a69db 100644 --- a/api/package.json +++ b/api/package.json @@ -9,27 +9,28 @@ } }, "peerDependencies": { - "typescript": "^5.9.3" + "typescript": "catalog:" }, "dependencies": { - "@libsql/client": "^0.15.15", - "drizzle-kit": "^0.31.8", - "drizzle-orm": "^0.45.1", + "@libsql/client": "catalog:", + "drizzle-kit": "catalog:", + "drizzle-orm": "catalog:", + "effect": "catalog:", "nanoid": "^5.1.6", - "near-kit": "^0.6.3", + "near-kit": "catalog:", "openai": "^6.16.0" }, "devDependencies": { - "@effect/language-service": "^0.41.1", - "@module-federation/node": "^2.7.27", - "@rspack/cli": "^1.7.2", - "@rspack/core": "^1.7.2", + "@effect/language-service": "^0.72.0", + "@module-federation/node": "^2.7.25", + "@rspack/cli": "^1.7.3", + "@rspack/core": "^1.7.3", + "@types/node": "catalog:", "dotenv": "^17.2.3", - "every-plugin": "^0.8.8", - "tsx": "^4.21.0", - "vite-tsconfig-paths": "^5.1.4", - "vitest": "^3.2.4", - "zephyr-rspack-plugin": "^0.1.4" + "every-plugin": "0.8.8", + "vite-tsconfig-paths": "^6.0.5", + "vitest": "catalog:", + "zephyr-rspack-plugin": "^0.1.2" }, "scripts": { "build": "rspack build", @@ -41,7 +42,6 @@ "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", "db:push": "drizzle-kit push", - "db:studio": "drizzle-kit studio", - "db:seed": "tsx src/seed.ts" + "db:studio": "drizzle-kit studio" } } diff --git a/api/vitest.config.ts b/api/vitest.config.ts index 5821b1f..37aa62c 100644 --- a/api/vitest.config.ts +++ b/api/vitest.config.ts @@ -8,6 +8,10 @@ export default defineConfig({ include: ['tests/**/*.test.ts'], exclude: ['node_modules/**', 'dist/**'], testTimeout: 30000, + fileParallelism: false, + sequence: { + hooks: 'stack', + }, }, plugins: [ tsconfigPaths({ diff --git a/bos.config.json b/bos.config.json index 88f1bfe..985690a 100644 --- a/bos.config.json +++ b/bos.config.json @@ -1,27 +1,41 @@ { - "account": "agency.near", + "account": "example.near", + "create": { + "project": "nearbuilders/cyborg", + "ui": "nearbuilders/cyborg/ui", + "api": "nearbuilders/cyborg/api", + "host": "nearbuilders/cyborg/host" + }, "app": { "host": { - "title": "agent", - "description": "template for building NEAR AI applications", - "development": "http://localhost:3001", - "production": "https://" + "title": "NEAR Agent", + "description": "Template for building NEAR AI applications", + "development": "http://localhost:3000", + "production": "https://elliot-braem-1733-host-cyborg-near-everythi-33abe003c-ze.zephyrcloud.app", + "secrets": [ + "HOST_DATABASE_URL", + "HOST_DATABASE_AUTH_TOKEN", + "BETTER_AUTH_SECRET", + "BETTER_AUTH_URL" + ], + "remote": "https://elliot-braem-1742-host-cyborg-near-everythi-0068d5f00-ze.zephyrcloud.app" }, "ui": { "name": "ui", "development": "http://localhost:3002", - "production": "https://jlwaugh-73-ui-agency-multiversityai-5854da94d-ze.zephyrcloud.app", + "production": "https://elliot-braem-1743-ui-cyborg-nearbuilders-a7a278431-ze.zephyrcloud.app", "exposes": { "App": "./App", "components": "./components", "providers": "./providers", "types": "./types" - } + }, + "ssr": "https://elliot-braem-1784-ui-cyborg-nearbuilders-3d795fd44-ze.zephyrcloud.app" }, "api": { "name": "api", "development": "http://localhost:3014", - "production": "https://jlwaugh-74-api-agency-multiversityai-18dcc54b0-ze.zephyrcloud.app", + "production": "https://elliot-braem-1745-api-cyborg-near-everythin-330ba1944-ze.zephyrcloud.app", "variables": { "NEAR_AI_MODEL": "deepseek-ai/DeepSeek-V3.1" }, diff --git a/bun.lock b/bun.lock index 2692ae3..5818811 100644 --- a/bun.lock +++ b/bun.lock @@ -5,83 +5,78 @@ "": { "name": "monorepo", "dependencies": { - "@tanstack/router-plugin": "^1.151.1", - "drizzle-kit": "^0.31.8", - "esbuild": "^0.27.2", - "hono": "^4.11.4", - "tsx": "^4.21.0", - "vite-tsconfig-paths": "^6.0.4", - "vitest": "^4.0.17", - }, - "devDependencies": { - "@types/node": "^25.0.9", - "turbo": "^2.7.5", + "@types/bun": "^1.3.6", }, }, "api": { "name": "api", "version": "0.0.1", "dependencies": { - "@libsql/client": "^0.15.15", - "drizzle-kit": "^0.31.8", - "drizzle-orm": "^0.45.1", + "@libsql/client": "catalog:", + "drizzle-kit": "catalog:", + "drizzle-orm": "catalog:", + "effect": "catalog:", "nanoid": "^5.1.6", - "near-kit": "^0.6.3", + "near-kit": "catalog:", "openai": "^6.16.0", }, "devDependencies": { - "@effect/language-service": "^0.41.1", - "@module-federation/node": "^2.7.27", - "@rspack/cli": "^1.7.2", - "@rspack/core": "^1.7.2", + "@effect/language-service": "^0.72.0", + "@module-federation/node": "^2.7.25", + "@rspack/cli": "^1.7.3", + "@rspack/core": "^1.7.3", + "@types/node": "catalog:", "dotenv": "^17.2.3", - "every-plugin": "^0.8.8", - "tsx": "^4.21.0", - "vite-tsconfig-paths": "^5.1.4", - "vitest": "^3.2.4", - "zephyr-rspack-plugin": "^0.1.4", + "every-plugin": "0.8.8", + "vite-tsconfig-paths": "^6.0.5", + "vitest": "catalog:", + "zephyr-rspack-plugin": "^0.1.2", }, "peerDependencies": { - "typescript": "^5.9.3", + "typescript": "catalog:", }, }, "host": { "name": "host", + "version": "1.0.0", "dependencies": { "@hono/node-server": "^1.19.9", "@hot-labs/near-connect": "^0.8.2", - "@libsql/client": "^0.15.15", - "@module-federation/enhanced": "^0.21.6", - "@module-federation/node": "^2.7.27", - "@module-federation/rsbuild-plugin": "^0.21.6", - "@module-federation/runtime": "^0.21.6", - "@module-federation/runtime-core": "^0.21.6", + "@libsql/client": "^0.17.0", + "@module-federation/enhanced": "^0.23.0", + "@module-federation/node": "^2.7.28", + "@module-federation/runtime-core": "^0.23.0", "@orpc/openapi": "^1.13.4", "@orpc/server": "^1.13.4", "@orpc/zod": "^1.13.4", "@t3-oss/env-core": "^0.13.10", - "@tanstack/react-query": "^5.90.19", - "@tanstack/react-router": "^1.151.1", - "better-auth": "^1.4.14", - "better-near-auth": "^0.3.4", + "@tanstack/react-query": "catalog:", + "@tanstack/react-router": "catalog:", + "better-auth": "catalog:", + "better-near-auth": "catalog:", "dotenv": "^17.2.3", "drizzle-kit": "^0.31.8", "drizzle-orm": "^0.45.1", - "every-plugin": "^0.8.8", - "hono": "^4.11.4", - "near-kit": "^0.6.3", - "react": "^19.2.3", - "react-dom": "^19.2.3", + "effect": "catalog:", + "every-plugin": "catalog:", + "hono": "^4.11.6", + "near-kit": "catalog:", + "react": "^19.2.4", + "react-dom": "^19.2.4", }, "devDependencies": { + "@module-federation/rsbuild-plugin": "^0.23.0", "@rsbuild/core": "^1.7.2", "@rsbuild/plugin-react": "^1.4.3", - "@types/node": "^22.19.7", - "@types/react": "^19.2.8", + "@types/node": "^25.0.10", + "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "tsx": "^4.21.0", - "typescript": "^5.9.3", - "zephyr-rsbuild-plugin": "^0.1.4", + "typescript": "catalog:", + "vite-tsconfig-paths": "^6.0.5", + "vitest": "^4.0.18", + "web-vitals": "^5.1.0", + "zephyr-rsbuild-plugin": "^0.1.8", }, }, "ui": { @@ -89,11 +84,8 @@ "version": "0.1.0", "dependencies": { "@hot-labs/near-connect": "^0.8.2", - "@orpc/client": "^1.13.4", + "@orpc/client": "^1.12.3", "@orpc/contract": "^1.13.4", - "@orpc/react-query": "^1.13.4", - "@orpc/server": "^1.13.4", - "@orpc/tanstack-query": "^1.13.4", "@radix-ui/react-aspect-ratio": "^1.1.8", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-checkbox": "^1.3.3", @@ -107,59 +99,76 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", - "@reactflow/background": "^11.3.14", - "@reactflow/controls": "^11.2.14", - "@reactflow/minimap": "^11.7.14", - "@tanstack/react-devtools": "^0.7.11", - "@tanstack/react-query": "^5.90.19", - "@tanstack/react-query-devtools": "^5.91.2", - "@tanstack/react-router": "^1.151.1", - "@tanstack/react-router-devtools": "^1.151.1", + "@tanstack/react-devtools": "^0.9.2", + "@tanstack/react-query": "catalog:", + "@tanstack/react-query-devtools": "^5.91.1", + "@tanstack/react-router": "catalog:", + "@tanstack/react-router-devtools": "^1.157.15", "@tanstack/react-table": "^8.21.3", - "better-auth": "^1.4.14", - "better-near-auth": "^0.3.4", + "better-auth": "catalog:", + "better-near-auth": "catalog:", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.544.0", - "near-kit": "^0.6.3", + "lucide-react": "^0.563.0", + "near-kit": "^0.10.0", "next-themes": "^0.4.6", "react": "^19.2.3", "react-dom": "^19.2.3", - "reactflow": "^11.11.4", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "tw-animate-css": "^1.4.0", - "zustand": "^5.0.10", + "zustand": "^5.0.9", }, "devDependencies": { - "@module-federation/enhanced": "^0.21.6", - "@module-federation/rsbuild-plugin": "^0.21.6", - "@rsbuild/core": "^1.7.2", - "@rsbuild/plugin-react": "^1.4.3", - "@tailwindcss/postcss": "^4.1.18", - "@tanstack/router-plugin": "^1.151.1", + "@module-federation/enhanced": "^0.23.0", + "@module-federation/node": "^2.7.26", + "@module-federation/rsbuild-plugin": "^0.23.0", + "@rsbuild/core": "^1.6.12", + "@rsbuild/plugin-react": "^1.4.2", + "@tailwindcss/postcss": "^4.1.17", + "@tanstack/router-plugin": "^1.157.15", "@testing-library/dom": "^10.4.1", - "@testing-library/react": "^16.3.1", - "@types/node": "^22.19.7", - "@types/react": "^19.2.8", - "@types/react-dom": "^19.2.3", - "jsdom": "^27.4.0", - "tailwindcss": "^4.1.18", - "typescript": "^5.9.3", - "vitest": "^3.2.4", - "web-vitals": "^5.1.0", - "zephyr-rsbuild-plugin": "^0.1.4", + "@testing-library/react": "^16.3.2", + "@types/node": "catalog:", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "every-plugin": "catalog:", + "jsdom": "^27.2.0", + "tailwindcss": "^4.1.17", + "typescript": "catalog:", + "vitest": "catalog:", + "zephyr-rsbuild-plugin": "^0.1.2", }, "peerDependencies": { - "@hot-labs/near-connect": "^0.8.2", + "@hot-labs/near-connect": "^0.8.x", "@tanstack/react-query": "^5.x", "@tanstack/react-router": "^1.x", - "near-kit": "^0.6.x", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "near-kit": "^0.10.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", }, }, }, + "catalog": { + "@hot-labs/near-connect": "^0.8.2", + "@libsql/client": "^0.17.0", + "@tanstack/react-query": "^5.90.11", + "@tanstack/react-router": "^1.153.2", + "@types/node": "^25.0.3", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "better-auth": "^1.4.15", + "better-near-auth": "^0.3.4", + "drizzle-kit": "^0.31.8", + "drizzle-orm": "^0.45.1", + "effect": "^3.19.15", + "every-plugin": "0.8.8", + "near-kit": "^0.10.0", + "react": "^19.2.3", + "react-dom": "^19.2.3", + "typescript": "^5.9.3", + "vitest": "^4.0.17", + }, "packages": { "@acemir/cssom": ["@acemir/cssom@0.9.31", "", {}, "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA=="], @@ -211,9 +220,9 @@ "@babel/types": ["@babel/types@7.28.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg=="], - "@better-auth/core": ["@better-auth/core@1.4.14", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "zod": "^4.1.12" }, "peerDependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21", "better-call": "1.1.8", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" } }, "sha512-2zskCRAd+oaMwgf4joC/tJVuKl+BUB9OhH6nhDHJsoe69Xkxaf/XyRpKpU7Cjeth8SVAUNKaCInF21zBBrj6Ow=="], + "@better-auth/core": ["@better-auth/core@1.4.17", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "zod": "^4.3.5" }, "peerDependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21", "better-call": "1.1.8", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" } }, "sha512-WSaEQDdUO6B1CzAmissN6j0lx9fM9lcslEYzlApB5UzFaBeAOHNUONTdglSyUs6/idiZBoRvt0t/qMXCgIU8ug=="], - "@better-auth/telemetry": ["@better-auth/telemetry@1.4.14", "", { "dependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21" }, "peerDependencies": { "@better-auth/core": "1.4.14" } }, "sha512-tIOvLT9vwPhbxT4rJIsHjxqcjlTX/eHHs0gXrKM90Dot71DqM9Cwse9C5IHQxJ1WLfPhc62laby4fbgcu5XSIA=="], + "@better-auth/telemetry": ["@better-auth/telemetry@1.4.17", "", { "dependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21" }, "peerDependencies": { "@better-auth/core": "1.4.17" } }, "sha512-R1BC4e/bNjQbXu7lG6ubpgmsPj7IMqky5DvMlzAtnAJWJhh99pMh/n6w5gOHa0cqDZgEAuj75IPTxv+q3YiInA=="], "@better-auth/utils": ["@better-auth/utils@0.3.0", "", {}, "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw=="], @@ -227,7 +236,7 @@ "@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@3.0.5", "", { "peerDependencies": { "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ=="], - "@csstools/css-syntax-patches-for-csstree": ["@csstools/css-syntax-patches-for-csstree@1.0.25", "", {}, "sha512-g0Kw9W3vjx5BEBAF8c5Fm2NcB/Fs8jJXh85aXqwEXiL+tqtOut07TWgyaGzAAfTM+gKckrrncyeGEZPcaRgm2Q=="], + "@csstools/css-syntax-patches-for-csstree": ["@csstools/css-syntax-patches-for-csstree@1.0.26", "", {}, "sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA=="], "@csstools/css-tokenizer": ["@csstools/css-tokenizer@3.0.4", "", {}, "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw=="], @@ -235,7 +244,7 @@ "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], - "@effect/language-service": ["@effect/language-service@0.41.1", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-BZaFkF1JdoTIJuzT7mNfUnfQG2MLxkQtn5b9y1z0BZUIcNfs5p7yR0ekYfTkPkt+TVD+9HE12VC1SsG5DReKww=="], + "@effect/language-service": ["@effect/language-service@0.72.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-MWkyTPCXSs5Q3OIBWR3q24SA+ipkdWW7EBJBt6EPUzlzZxjJLXtLBhXpMoCFheSEM0FTWOHT4BRLh5lufsmjVw=="], "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], @@ -247,59 +256,59 @@ "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], - "@exodus/bytes": ["@exodus/bytes@1.8.0", "", { "peerDependencies": { "@exodus/crypto": "^1.0.0-rc.4" }, "optionalPeers": ["@exodus/crypto"] }, "sha512-8JPn18Bcp8Uo1T82gR8lh2guEOa5KKU/IEKvvdp0sgmi7coPBWf1Doi1EXsGZb2ehc8ym/StJCjffYV+ne7sXQ=="], + "@exodus/bytes": ["@exodus/bytes@1.10.0", "", { "peerDependencies": { "@noble/hashes": "^1.8.0 || ^2.0.0" }, "optionalPeers": ["@noble/hashes"] }, "sha512-tf8YdcbirXdPnJ+Nd4UN1EXnz+IP2DI45YVEr3vvzcVTOyrApkmIB4zvOQVd3XPr7RXnfBtAx+PXImXOIU0Ajg=="], "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], @@ -329,10 +338,26 @@ "@jsonjoy.com/base64": ["@jsonjoy.com/base64@1.1.2", "", { "peerDependencies": { "tslib": "2" } }, "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA=="], - "@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@1.2.1", "", { "peerDependencies": { "tslib": "2" } }, "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA=="], + "@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@17.65.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-eBrIXd0/Ld3p9lpDDlMaMn6IEfWqtHMD+z61u0JrIiPzsV1r7m6xDZFRxJyvIFTEO+SWdYF9EiQbXZGd8BzPfA=="], "@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@1.0.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g=="], + "@jsonjoy.com/fs-core": ["@jsonjoy.com/fs-core@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-PyAEA/3cnHhsGcdY+AmIU+ZPqTuZkDhCXQ2wkXypdLitSpd6d5Ivxhnq4wa2ETRWFVJGabYynBWxIijOswSmOw=="], + + "@jsonjoy.com/fs-fsa": ["@jsonjoy.com/fs-fsa@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.56.10", "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-/FVK63ysNzTPOnCCcPoPHt77TOmachdMS422txM4KhxddLdbW1fIbFMYH0AM0ow/YchCyS5gqEjKLNyv71j/5Q=="], + + "@jsonjoy.com/fs-node": ["@jsonjoy.com/fs-node@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.56.10", "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10", "@jsonjoy.com/fs-print": "4.56.10", "@jsonjoy.com/fs-snapshot": "4.56.10", "glob-to-regex.js": "^1.0.0", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-7R4Gv3tkUdW3dXfXiOkqxkElxKNVdd8BDOWC0/dbERd0pXpPY+s2s1Mino+aTvkGrFPiY+mmVxA7zhskm4Ue4Q=="], + + "@jsonjoy.com/fs-node-builtins": ["@jsonjoy.com/fs-node-builtins@4.56.10", "", { "peerDependencies": { "tslib": "2" } }, "sha512-uUnKz8R0YJyKq5jXpZtkGV9U0pJDt8hmYcLRrPjROheIfjMXsz82kXMgAA/qNg0wrZ1Kv+hrg7azqEZx6XZCVw=="], + + "@jsonjoy.com/fs-node-to-fsa": ["@jsonjoy.com/fs-node-to-fsa@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-fsa": "4.56.10", "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10" }, "peerDependencies": { "tslib": "2" } }, "sha512-oH+O6Y4lhn9NyG6aEoFwIBNKZeYy66toP5LJcDOMBgL99BKQMUf/zWJspdRhMdn/3hbzQsZ8EHHsuekbFLGUWw=="], + + "@jsonjoy.com/fs-node-utils": ["@jsonjoy.com/fs-node-utils@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-node-builtins": "4.56.10" }, "peerDependencies": { "tslib": "2" } }, "sha512-8EuPBgVI2aDPwFdaNQeNpHsyqPi3rr+85tMNG/lHvQLiVjzoZsvxA//Xd8aB567LUhy4QS03ptT+unkD/DIsNg=="], + + "@jsonjoy.com/fs-print": ["@jsonjoy.com/fs-print@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-node-utils": "4.56.10", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-JW4fp5mAYepzFsSGrQ48ep8FXxpg4niFWHdF78wDrFGof7F3tKDJln72QFDEn/27M1yHd4v7sKHHVPh78aWcEw=="], + + "@jsonjoy.com/fs-snapshot": ["@jsonjoy.com/fs-snapshot@4.56.10", "", { "dependencies": { "@jsonjoy.com/buffers": "^17.65.0", "@jsonjoy.com/fs-node-utils": "4.56.10", "@jsonjoy.com/json-pack": "^17.65.0", "@jsonjoy.com/util": "^17.65.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-DkR6l5fj7+qj0+fVKm/OOXMGfDFCGXLfyHkORH3DF8hxkpDgIHbhf/DwncBMs2igu/ST7OEkexn1gIqoU6Y+9g=="], + "@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@1.21.0", "", { "dependencies": { "@jsonjoy.com/base64": "^1.1.2", "@jsonjoy.com/buffers": "^1.2.0", "@jsonjoy.com/codegen": "^1.0.0", "@jsonjoy.com/json-pointer": "^1.0.2", "@jsonjoy.com/util": "^1.9.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg=="], "@jsonjoy.com/json-pointer": ["@jsonjoy.com/json-pointer@1.0.2", "", { "dependencies": { "@jsonjoy.com/codegen": "^1.0.0", "@jsonjoy.com/util": "^1.9.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg=="], @@ -341,17 +366,15 @@ "@leichtgewicht/ip-codec": ["@leichtgewicht/ip-codec@2.0.5", "", {}, "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw=="], - "@libsql/client": ["@libsql/client@0.15.15", "", { "dependencies": { "@libsql/core": "^0.15.14", "@libsql/hrana-client": "^0.7.0", "js-base64": "^3.7.5", "libsql": "^0.5.22", "promise-limit": "^2.7.0" } }, "sha512-twC0hQxPNHPKfeOv3sNT6u2pturQjLcI+CnpTM0SjRpocEGgfiZ7DWKXLNnsothjyJmDqEsBQJ5ztq9Wlu470w=="], + "@libsql/client": ["@libsql/client@0.17.0", "", { "dependencies": { "@libsql/core": "^0.17.0", "@libsql/hrana-client": "^0.9.0", "js-base64": "^3.7.5", "libsql": "^0.5.22", "promise-limit": "^2.7.0" } }, "sha512-TLjSU9Otdpq0SpKHl1tD1Nc9MKhrsZbCFGot3EbCxRa8m1E5R1mMwoOjKMMM31IyF7fr+hPNHLpYfwbMKNusmg=="], - "@libsql/core": ["@libsql/core@0.15.15", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-C88Z6UKl+OyuKKPwz224riz02ih/zHYI3Ho/LAcVOgjsunIRZoBw7fjRfaH9oPMmSNeQfhGklSG2il1URoOIsA=="], + "@libsql/core": ["@libsql/core@0.17.0", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-hnZRnJHiS+nrhHKLGYPoJbc78FE903MSDrFJTbftxo+e52X+E0Y0fHOCVYsKWcg6XgB7BbJYUrz/xEkVTSaipw=="], "@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.5.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4B8ZlX3nIDPndfct7GNe0nI3Yw6ibocEicWdC4fvQbSs/jdq/RC2oCsoJxJ4NzXkvktX70C1J4FcmmoBy069UA=="], "@libsql/darwin-x64": ["@libsql/darwin-x64@0.5.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-ny2HYWt6lFSIdNFzUFIJ04uiW6finXfMNJ7wypkAD8Pqdm6nAByO+Fdqu8t7sD0sqJGeUCiOg480icjyQ2/8VA=="], - "@libsql/hrana-client": ["@libsql/hrana-client@0.7.0", "", { "dependencies": { "@libsql/isomorphic-fetch": "^0.3.1", "@libsql/isomorphic-ws": "^0.1.5", "js-base64": "^3.7.5", "node-fetch": "^3.3.2" } }, "sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw=="], - - "@libsql/isomorphic-fetch": ["@libsql/isomorphic-fetch@0.3.1", "", {}, "sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw=="], + "@libsql/hrana-client": ["@libsql/hrana-client@0.9.0", "", { "dependencies": { "@libsql/isomorphic-ws": "^0.1.5", "cross-fetch": "^4.0.0", "js-base64": "^3.7.5", "node-fetch": "^3.3.2" } }, "sha512-pxQ1986AuWfPX4oXzBvLwBnfgKDE5OMhAdR/5cZmRaB4Ygz5MecQybvwZupnRz341r2CtFmbk/BhSu7k2Lm+Jw=="], "@libsql/isomorphic-ws": ["@libsql/isomorphic-ws@0.1.5", "", { "dependencies": { "@types/ws": "^8.5.4", "ws": "^8.13.0" } }, "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg=="], @@ -371,39 +394,39 @@ "@module-federation/automatic-vendor-federation": ["@module-federation/automatic-vendor-federation@1.2.1", "", { "dependencies": { "find-package-json": "^1.2.0" }, "peerDependencies": { "webpack": "^5.0.0-beta.16" } }, "sha512-73wxkXM7pbRZ6GGM90JP5IPTPvY3fvrhQyTVdMCUx85cQRWqnbzbibcsz3pkOMOeXyYAO4tXXsG13yNaEEGhJA=="], - "@module-federation/bridge-react-webpack-plugin": ["@module-federation/bridge-react-webpack-plugin@0.21.6", "", { "dependencies": { "@module-federation/sdk": "0.21.6", "@types/semver": "7.5.8", "semver": "7.6.3" } }, "sha512-lJMmdhD4VKVkeg8RHb+Jwe6Ou9zKVgjtb1inEURDG/sSS2ksdZA8pVKLYbRPRbdmjr193Y8gJfqFbI2dqoyc/g=="], + "@module-federation/bridge-react-webpack-plugin": ["@module-federation/bridge-react-webpack-plugin@0.23.0", "", { "dependencies": { "@module-federation/sdk": "0.23.0", "@types/semver": "7.5.8", "semver": "7.6.3" } }, "sha512-miZmMCl7OS1CH2tQbqijWK85qThg4TBDkI25Vx4G2du4ehg47mPKfeuft6/KWV/eJ7ZS4C534Oq/6lom1ncTOQ=="], - "@module-federation/cli": ["@module-federation/cli@0.21.6", "", { "dependencies": { "@module-federation/dts-plugin": "0.21.6", "@module-federation/sdk": "0.21.6", "chalk": "3.0.0", "commander": "11.1.0", "jiti": "2.4.2" }, "bin": { "mf": "bin/mf.js" } }, "sha512-qNojnlc8pTyKtK7ww3i/ujLrgWwgXqnD5DcDPsjADVIpu7STaoaVQ0G5GJ7WWS/ajXw6EyIAAGW/AMFh4XUxsQ=="], + "@module-federation/cli": ["@module-federation/cli@0.23.0", "", { "dependencies": { "@module-federation/dts-plugin": "0.23.0", "@module-federation/sdk": "0.23.0", "chalk": "3.0.0", "commander": "11.1.0", "jiti": "2.4.2" }, "bin": { "mf": "bin/mf.js" } }, "sha512-5OfdKUslS/kb6pycJPOtutMzIXSdmYcLoTSjhrWD7/68qFt2SGV7JD1l0RAhq3+fTuXryxctusTl4or2vCgBJw=="], - "@module-federation/data-prefetch": ["@module-federation/data-prefetch@0.21.6", "", { "dependencies": { "@module-federation/runtime": "0.21.6", "@module-federation/sdk": "0.21.6", "fs-extra": "9.1.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-8HD7ZhtWZ9vl6i3wA7M8cEeCRdtvxt09SbMTfqIPm+5eb/V4ijb8zGTYSRhNDb5RCB+BAixaPiZOWKXJ63/rVw=="], + "@module-federation/data-prefetch": ["@module-federation/data-prefetch@0.23.0", "", { "dependencies": { "@module-federation/runtime": "0.23.0", "@module-federation/sdk": "0.23.0", "fs-extra": "9.1.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-oTzdHo8xe0t1pA6KvTeEZAMcnvMRgE2rUwUrgFuGUqbQoTdndEt/A1X9eayJ5s/8ARDT5hoam4LcZYXpXPYbjg=="], - "@module-federation/dts-plugin": ["@module-federation/dts-plugin@0.21.6", "", { "dependencies": { "@module-federation/error-codes": "0.21.6", "@module-federation/managers": "0.21.6", "@module-federation/sdk": "0.21.6", "@module-federation/third-party-dts-extractor": "0.21.6", "adm-zip": "^0.5.10", "ansi-colors": "^4.1.3", "axios": "^1.12.0", "chalk": "3.0.0", "fs-extra": "9.1.0", "isomorphic-ws": "5.0.0", "koa": "3.0.3", "lodash.clonedeepwith": "4.5.0", "log4js": "6.9.1", "node-schedule": "2.1.1", "rambda": "^9.1.0", "ws": "8.18.0" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["vue-tsc"] }, "sha512-YIsDk8/7QZIWn0I1TAYULniMsbyi2LgKTi9OInzVmZkwMC6644x/ratTWBOUDbdY1Co+feNkoYeot1qIWv2L7w=="], + "@module-federation/dts-plugin": ["@module-federation/dts-plugin@0.23.0", "", { "dependencies": { "@module-federation/error-codes": "0.23.0", "@module-federation/managers": "0.23.0", "@module-federation/sdk": "0.23.0", "@module-federation/third-party-dts-extractor": "0.23.0", "adm-zip": "^0.5.10", "ansi-colors": "^4.1.3", "axios": "^1.12.0", "chalk": "3.0.0", "fs-extra": "9.1.0", "isomorphic-ws": "5.0.0", "koa": "3.0.3", "lodash.clonedeepwith": "4.5.0", "log4js": "6.9.1", "node-schedule": "2.1.1", "rambda": "^9.1.0", "ws": "8.18.0" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["vue-tsc"] }, "sha512-DIA2ht2SkGgdRWSVnxBGBS4XqeSiWIFPwyULZVZ0TTYr/47betlSVSRU6CTPokalrlryzMhEiqcvYJPCkOVP5w=="], - "@module-federation/enhanced": ["@module-federation/enhanced@0.21.6", "", { "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.21.6", "@module-federation/cli": "0.21.6", "@module-federation/data-prefetch": "0.21.6", "@module-federation/dts-plugin": "0.21.6", "@module-federation/error-codes": "0.21.6", "@module-federation/inject-external-runtime-core-plugin": "0.21.6", "@module-federation/managers": "0.21.6", "@module-federation/manifest": "0.21.6", "@module-federation/rspack": "0.21.6", "@module-federation/runtime-tools": "0.21.6", "@module-federation/sdk": "0.21.6", "btoa": "^1.2.1", "schema-utils": "^4.3.0", "upath": "2.0.1" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24", "webpack": "^5.0.0" }, "optionalPeers": ["typescript", "vue-tsc", "webpack"], "bin": { "mf": "bin/mf.js" } }, "sha512-8PFQxtmXc6ukBC4CqGIoc96M2Ly9WVwCPu4Ffvt+K/SB6rGbeFeZoYAwREV1zGNMJ5v5ly6+AHIEOBxNuSnzSg=="], + "@module-federation/enhanced": ["@module-federation/enhanced@0.23.0", "", { "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.23.0", "@module-federation/cli": "0.23.0", "@module-federation/data-prefetch": "0.23.0", "@module-federation/dts-plugin": "0.23.0", "@module-federation/error-codes": "0.23.0", "@module-federation/inject-external-runtime-core-plugin": "0.23.0", "@module-federation/managers": "0.23.0", "@module-federation/manifest": "0.23.0", "@module-federation/rspack": "0.23.0", "@module-federation/runtime-tools": "0.23.0", "@module-federation/sdk": "0.23.0", "btoa": "^1.2.1", "schema-utils": "^4.3.0", "upath": "2.0.1" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24", "webpack": "^5.0.0" }, "optionalPeers": ["typescript", "vue-tsc", "webpack"], "bin": { "mf": "bin/mf.js" } }, "sha512-GPfipQc0/rgwYp48hkru0cqvjtRKPVC/ZlUFptrbr2LTLM5mxW3ig1rggUAH2QSQoNvDuhY/kqG8u71MZROi3w=="], - "@module-federation/error-codes": ["@module-federation/error-codes@0.21.6", "", {}, "sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ=="], + "@module-federation/error-codes": ["@module-federation/error-codes@0.23.0", "", {}, "sha512-CzcKOPKh/qB1wPkVBC0iEK/Cg4jRAS1DnZsTx7b3JUCIXDcIaRq/XkTdo+EQ0cAsF5Os9lQ0f50O9DC/uFC8eA=="], - "@module-federation/inject-external-runtime-core-plugin": ["@module-federation/inject-external-runtime-core-plugin@0.21.6", "", { "peerDependencies": { "@module-federation/runtime-tools": "0.21.6" } }, "sha512-DJQne7NQ988AVi3QB8byn12FkNb+C2lBeU1NRf8/WbL0gmHsr6kW8hiEJCm8LYaURwtsQqtsEV7i+8+51qjSmQ=="], + "@module-federation/inject-external-runtime-core-plugin": ["@module-federation/inject-external-runtime-core-plugin@0.23.0", "", { "peerDependencies": { "@module-federation/runtime-tools": "0.23.0" } }, "sha512-xxQrqtjbAUHY826ZtpvqgzANXhEibbloaiAOLZXhfIJd9wbYzK9m9zcHmIKOc5PQ5p1bBI5OJ+9XxXQmSBAtuw=="], - "@module-federation/managers": ["@module-federation/managers@0.21.6", "", { "dependencies": { "@module-federation/sdk": "0.21.6", "find-pkg": "2.0.0", "fs-extra": "9.1.0" } }, "sha512-BeV6m2/7kF5MDVz9JJI5T8h8lMosnXkH2bOxxFewcra7ZjvDOgQu7WIio0mgk5l1zjNPvnEVKhnhrenEdcCiWg=="], + "@module-federation/managers": ["@module-federation/managers@0.23.0", "", { "dependencies": { "@module-federation/sdk": "0.23.0", "find-pkg": "2.0.0", "fs-extra": "9.1.0" } }, "sha512-Stqu04QUiYBhWLW+0+EoZ4e5pFrrTxcEI4StJ7jOPtn2Ll6ImvGWk2KVNfbTjz0TRhIx5rl2wc+YPnYJ9tdVag=="], - "@module-federation/manifest": ["@module-federation/manifest@0.21.6", "", { "dependencies": { "@module-federation/dts-plugin": "0.21.6", "@module-federation/managers": "0.21.6", "@module-federation/sdk": "0.21.6", "chalk": "3.0.0", "find-pkg": "2.0.0" } }, "sha512-yg93+I1qjRs5B5hOSvjbjmIoI2z3th8/yst9sfwvx4UDOG1acsE3HHMyPN0GdoIGwplC/KAnU5NmUz4tREUTGQ=="], + "@module-federation/manifest": ["@module-federation/manifest@0.23.0", "", { "dependencies": { "@module-federation/dts-plugin": "0.23.0", "@module-federation/managers": "0.23.0", "@module-federation/sdk": "0.23.0", "chalk": "3.0.0", "find-pkg": "2.0.0" } }, "sha512-tzeq67oeTXM+ukzaC2qcaft5Gvu8T/hYiFGE/jopOOTVH8glTebKDg+xOABcN+EeP6UDmf6vDVq7dYmXTC6e/w=="], - "@module-federation/node": ["@module-federation/node@2.7.27", "", { "dependencies": { "@module-federation/enhanced": "0.22.1", "@module-federation/runtime": "0.22.1", "@module-federation/sdk": "0.22.1", "btoa": "1.2.1", "encoding": "^0.1.13", "node-fetch": "2.7.0" }, "peerDependencies": { "react": "^16||^17||^18||^19", "react-dom": "^16||^17||^18||^19", "webpack": "^5.40.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-Lv/H5g6vd7tADx/fCfhv0LyKVPWaJEquMdQaf0aTSnWgatg2ljPZrOoBdNMA68T5Ll+3kbUiDXuQb4ODmjdEgw=="], + "@module-federation/node": ["@module-federation/node@2.7.28", "", { "dependencies": { "@module-federation/enhanced": "0.23.0", "@module-federation/runtime": "0.23.0", "@module-federation/sdk": "0.23.0", "btoa": "1.2.1", "encoding": "^0.1.13", "node-fetch": "2.7.0" }, "peerDependencies": { "react": "^16||^17||^18||^19", "react-dom": "^16||^17||^18||^19", "webpack": "^5.40.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-AoYSak1bgUUs1COcbf330ONRqmNJ5pSSMLjeOVLyRjROCsoXwSnIiWVxSTi0MENHd3B6k+T0oFPQWi9nRKK3lQ=="], - "@module-federation/rsbuild-plugin": ["@module-federation/rsbuild-plugin@0.21.6", "", { "dependencies": { "@module-federation/enhanced": "0.21.6", "@module-federation/node": "2.7.25", "@module-federation/sdk": "0.21.6", "fs-extra": "11.3.0" }, "peerDependencies": { "@rsbuild/core": "^1.3.21" }, "optionalPeers": ["@rsbuild/core"] }, "sha512-Whbj8wy9p/YPea+yN0oW1PbPq3qYG9uZzPZ0UfNHswpZE7fpPUu/kGjmTosRpkMAWMraPH4bCh03y3Masz9eVQ=="], + "@module-federation/rsbuild-plugin": ["@module-federation/rsbuild-plugin@0.23.0", "", { "dependencies": { "@module-federation/enhanced": "0.23.0", "@module-federation/node": "2.7.28", "@module-federation/sdk": "0.23.0", "fs-extra": "11.3.0" }, "peerDependencies": { "@rsbuild/core": "^1.3.21" }, "optionalPeers": ["@rsbuild/core"] }, "sha512-Kwk/GoCVEd4u6RH6i4dj7na9gZmHZD4JPBoTwLVgo5zM9HuouIjSfOVBrcbJG4TgVZB4n4F+O02tbJpWxPY57w=="], - "@module-federation/rspack": ["@module-federation/rspack@0.21.6", "", { "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.21.6", "@module-federation/dts-plugin": "0.21.6", "@module-federation/inject-external-runtime-core-plugin": "0.21.6", "@module-federation/managers": "0.21.6", "@module-federation/manifest": "0.21.6", "@module-federation/runtime-tools": "0.21.6", "@module-federation/sdk": "0.21.6", "btoa": "1.2.1" }, "peerDependencies": { "@rspack/core": ">=0.7", "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["typescript", "vue-tsc"] }, "sha512-SB+z1P+Bqe3R6geZje9dp0xpspX6uash+zO77nodmUy8PTTBlkL7800Cq2FMLKUdoTZHJTBVXf0K6CqQWSlItg=="], + "@module-federation/rspack": ["@module-federation/rspack@0.23.0", "", { "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.23.0", "@module-federation/dts-plugin": "0.23.0", "@module-federation/inject-external-runtime-core-plugin": "0.23.0", "@module-federation/managers": "0.23.0", "@module-federation/manifest": "0.23.0", "@module-federation/runtime-tools": "0.23.0", "@module-federation/sdk": "0.23.0", "btoa": "1.2.1" }, "peerDependencies": { "@rspack/core": ">=0.7", "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["typescript", "vue-tsc"] }, "sha512-Le1ep9NTgEGpbYhFsko/HkHS3To/jpEQ0Wvkugxix7pxA8ynhJCpflD2y+iN8CCfGq+Y49dACAmqLvifPc5OfA=="], - "@module-federation/runtime": ["@module-federation/runtime@0.21.6", "", { "dependencies": { "@module-federation/error-codes": "0.21.6", "@module-federation/runtime-core": "0.21.6", "@module-federation/sdk": "0.21.6" } }, "sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ=="], + "@module-federation/runtime": ["@module-federation/runtime@0.23.0", "", { "dependencies": { "@module-federation/error-codes": "0.23.0", "@module-federation/runtime-core": "0.23.0", "@module-federation/sdk": "0.23.0" } }, "sha512-ZHJcfM1O8RqYVrlIbhyeQ3S6gJW3mqHso3/QY7cKs1za+UvOgB8aTsDwq7Fv+aJZWSmtGzWa4zbSuxthyucw3g=="], - "@module-federation/runtime-core": ["@module-federation/runtime-core@0.21.6", "", { "dependencies": { "@module-federation/error-codes": "0.21.6", "@module-federation/sdk": "0.21.6" } }, "sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw=="], + "@module-federation/runtime-core": ["@module-federation/runtime-core@0.23.0", "", { "dependencies": { "@module-federation/error-codes": "0.23.0", "@module-federation/sdk": "0.23.0" } }, "sha512-+Orumtyg6Q2v19Gz15P3kDmRf4Q6KEpv8DggKWHdM8AX4xyVT8dMRJxdIxaVddbIYTd7aL7o2U3LLK6EjUe4UA=="], "@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.22.0", "", { "dependencies": { "@module-federation/runtime": "0.22.0", "@module-federation/webpack-bundler-runtime": "0.22.0" } }, "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA=="], - "@module-federation/sdk": ["@module-federation/sdk@0.22.1", "", {}, "sha512-e+xcroeeZwb1lXK0tM6E7YmGr8lYHm3QzplWVM/q0Hs8SlvQMcM9Lv+JF6y9UQmhVSaMKW40PyPyqL0Y1rIeVw=="], + "@module-federation/sdk": ["@module-federation/sdk@0.23.0", "", {}, "sha512-1+DICHIF1z6yggtsZypmcn1gL35iitiSDXcsaqWynK4v5aw9MBRUS4zP3kG7eQDFTMmIo+rGbPN37AUsOq/RRQ=="], - "@module-federation/third-party-dts-extractor": ["@module-federation/third-party-dts-extractor@0.21.6", "", { "dependencies": { "find-pkg": "2.0.0", "fs-extra": "9.1.0", "resolve": "1.22.8" } }, "sha512-Il6x4hLsvCgZNk1DFwuMBNeoxD1BsZ5AW2BI/nUgu0k5FiAvfcz1OFawRFEHtaM/kVrCsymMOW7pCao90DaX3A=="], + "@module-federation/third-party-dts-extractor": ["@module-federation/third-party-dts-extractor@0.23.0", "", { "dependencies": { "find-pkg": "2.0.0", "fs-extra": "9.1.0", "resolve": "1.22.8" } }, "sha512-/oiLf6QQblhQKuHf89Wd475nUva+PWz5G01wxldy4lXaSTvz5XayCCBDek2SX8Gs4XnqATCm6IriAQ+ORzsgmQ=="], "@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.22.0", "", { "dependencies": { "@module-federation/runtime": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA=="], @@ -563,97 +586,85 @@ "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], - "@reactflow/background": ["@reactflow/background@11.3.14", "", { "dependencies": { "@reactflow/core": "11.11.4", "classcat": "^5.0.3", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-Gewd7blEVT5Lh6jqrvOgd4G6Qk17eGKQfsDXgyRSqM+CTwDqRldG2LsWN4sNeno6sbqVIC2fZ+rAUBFA9ZEUDA=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.56.0", "", { "os": "android", "cpu": "arm" }, "sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw=="], - "@reactflow/controls": ["@reactflow/controls@11.2.14", "", { "dependencies": { "@reactflow/core": "11.11.4", "classcat": "^5.0.3", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-MiJp5VldFD7FrqaBNIrQ85dxChrG6ivuZ+dcFhPQUwOK3HfYgX2RHdBua+gx+40p5Vw5It3dVNp/my4Z3jF0dw=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.56.0", "", { "os": "android", "cpu": "arm64" }, "sha512-lfbVUbelYqXlYiU/HApNMJzT1E87UPGvzveGg2h0ktUNlOCxKlWuJ9jtfvs1sKHdwU4fzY7Pl8sAl49/XaEk6Q=="], - "@reactflow/core": ["@reactflow/core@11.11.4", "", { "dependencies": { "@types/d3": "^7.4.0", "@types/d3-drag": "^3.0.1", "@types/d3-selection": "^3.0.3", "@types/d3-zoom": "^3.0.1", "classcat": "^5.0.3", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-H4vODklsjAq3AMq6Np4LE12i1I4Ta9PrDHuBR9GmL8uzTt2l2jh4CiQbEMpvMDcp7xi4be0hgXj+Ysodde/i7Q=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.56.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EgxD1ocWfhoD6xSOeEEwyE7tDvwTgZc8Bss7wCWe+uc7wO8G34HHCUH+Q6cHqJubxIAnQzAsyUsClt0yFLu06w=="], - "@reactflow/minimap": ["@reactflow/minimap@11.7.14", "", { "dependencies": { "@reactflow/core": "11.11.4", "@types/d3-selection": "^3.0.3", "@types/d3-zoom": "^3.0.1", "classcat": "^5.0.3", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-mpwLKKrEAofgFJdkhwR5UQ1JYWlcAAL/ZU/bctBkuNTT1yqV+y0buoNVImsRehVYhJwffSWeSHaBR5/GJjlCSQ=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.56.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-1vXe1vcMOssb/hOF8iv52A7feWW2xnu+c8BV4t1F//m9QVLTfNVpEdja5ia762j/UEJe2Z1jAmEqZAK42tVW3g=="], - "@reactflow/node-resizer": ["@reactflow/node-resizer@2.2.14", "", { "dependencies": { "@reactflow/core": "11.11.4", "classcat": "^5.0.4", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-fwqnks83jUlYr6OHcdFEedumWKChTHRGw/kbCxj0oqBd+ekfs+SIp4ddyNU0pdx96JIm5iNFS0oNrmEiJbbSaA=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.56.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-bof7fbIlvqsyv/DtaXSck4VYQ9lPtoWNFCB/JY4snlFuJREXfZnm+Ej6yaCHfQvofJDXLDMTVxWscVSuQvVWUQ=="], - "@reactflow/node-toolbar": ["@reactflow/node-toolbar@1.3.14", "", { "dependencies": { "@reactflow/core": "11.11.4", "classcat": "^5.0.3", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-rbynXQnH/xFNu4P9H+hVqlEUafDCkEoCy0Dg9mG22Sg+rY/0ck6KkrAQrYrTgXusd+cEJOMK0uOOFCK2/5rSGQ=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.56.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KNa6lYHloW+7lTEkYGa37fpvPq+NKG/EHKM8+G/g9WDU7ls4sMqbVRV78J6LdNuVaeeK5WB9/9VAFbKxcbXKYg=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.55.1", "", { "os": "android", "cpu": "arm" }, "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.56.0", "", { "os": "linux", "cpu": "arm" }, "sha512-E8jKK87uOvLrrLN28jnAAAChNq5LeCd2mGgZF+fGF5D507WlG/Noct3lP/QzQ6MrqJ5BCKNwI9ipADB6jyiq2A=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.55.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.56.0", "", { "os": "linux", "cpu": "arm" }, "sha512-jQosa5FMYF5Z6prEpTCCmzCXz6eKr/tCBssSmQGEeozA9tkRUty/5Vx06ibaOP9RCrW1Pvb8yp3gvZhHwTDsJw=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.55.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.56.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-uQVoKkrC1KGEV6udrdVahASIsaF8h7iLG0U0W+Xn14ucFwi6uS539PsAr24IEF9/FoDtzMeeJXJIBo5RkbNWvQ=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.55.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.56.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vLZ1yJKLxhQLFKTs42RwTwa6zkGln+bnXc8ueFGMYmBTLfNu58sl5/eXyxRa2RarTkJbXl8TKPgfS6V5ijNqEA=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.55.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.56.0", "", { "os": "linux", "cpu": "none" }, "sha512-FWfHOCub564kSE3xJQLLIC/hbKqHSVxy8vY75/YHHzWvbJL7aYJkdgwD/xGfUlL5UV2SB7otapLrcCj2xnF1dg=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.55.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw=="], + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.56.0", "", { "os": "linux", "cpu": "none" }, "sha512-z1EkujxIh7nbrKL1lmIpqFTc/sr0u8Uk0zK/qIEFldbt6EDKWFk/pxFq3gYj4Bjn3aa9eEhYRlL3H8ZbPT1xvA=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.56.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-iNFTluqgdoQC7AIE8Q34R3AuPrJGJirj5wMUErxj22deOcY7XwZRaqYmB6ZKFHoVGqRcRd0mqO+845jAibKCkw=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg=="], + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.56.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-MtMeFVlD2LIKjp2sE2xM2slq3Zxf9zwVuw0jemsxvh1QOpHSsSzfNOTH9uYW9i1MXFxUSMmLpeVeUzoNOKBaWg=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.56.0", "", { "os": "linux", "cpu": "none" }, "sha512-in+v6wiHdzzVhYKXIk5U74dEZHdKN9KH0Q4ANHOTvyXPG41bajYRsy7a8TPKbYPl34hU7PP7hMVHRvv/5aCSew=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.56.0", "", { "os": "linux", "cpu": "none" }, "sha512-yni2raKHB8m9NQpI9fPVwN754mn6dHQSbDTwxdr9SE0ks38DTjLMMBjrwvB5+mXrX+C0npX0CVeCUcvvvD8CNQ=="], - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.56.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-zhLLJx9nQPu7wezbxt2ut+CI4YlXi68ndEve16tPc/iwoylWS9B3FxpLS2PkmfYgDQtosah07Mj9E0khc3Y+vQ=="], - "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.56.0", "", { "os": "linux", "cpu": "x64" }, "sha512-MVC6UDp16ZSH7x4rtuJPAEoE1RwS8N4oK9DLHy3FTEdFoUTCFVzMfJl/BVJ330C+hx8FfprA5Wqx4FhZXkj2Kw=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.56.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ZhGH1eA4Qv0lxaV00azCIS1ChedK0V32952Md3FtnxSqZTBTd6tgil4nZT5cU8B+SIw3PFYkvyR4FKo2oyZIHA=="], - "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw=="], + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.56.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-O16XcmyDeFI9879pEcmtWvD/2nyxR9mF7Gs44lf1vGGx8Vg2DRNx11aVXBEqOQhWb92WN4z7fW/q4+2NYzCbBA=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.56.0", "", { "os": "none", "cpu": "arm64" }, "sha512-LhN/Reh+7F3RCgQIRbgw8ZMwUwyqJM+8pXNT6IIJAqm2IdKkzpCh/V9EdgOMBKuebIrzswqy4ATlrDgiOwbRcQ=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.56.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-kbFsOObXp3LBULg1d3JIUQMa9Kv4UitDmpS+k0tinPBz3watcUiV2/LUDMMucA6pZO3WGE27P7DsfaN54l9ing=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.55.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.56.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-vSSgny54D6P4vf2izbtFm/TcWYedw7f8eBrOiGGecyHyQB9q4Kqentjaj8hToe+995nob/Wv48pDqL5a62EWtg=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.56.0", "", { "os": "win32", "cpu": "x64" }, "sha512-FeCnkPCTHQJFbiGG49KjV5YGW/8b9rrXAM2Mz2kiIoktq2qsJxRD5giEMEOD2lPdgs72upzefaUvS+nc8E3UzQ=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w=="], - - "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.55.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg=="], - - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.55.1", "", { "os": "none", "cpu": "arm64" }, "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw=="], - - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.55.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g=="], - - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.55.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA=="], - - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg=="], - - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.56.0", "", { "os": "win32", "cpu": "x64" }, "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g=="], "@rsbuild/core": ["@rsbuild/core@1.7.2", "", { "dependencies": { "@rspack/core": "~1.7.1", "@rspack/lite-tapable": "~1.1.0", "@swc/helpers": "^0.5.18", "core-js": "~3.47.0", "jiti": "^2.6.1" }, "bin": { "rsbuild": "bin/rsbuild.js" } }, "sha512-VAFO6cM+cyg2ntxNW6g3tB2Jc5J5mpLjLluvm7VtW2uceNzyUlVv41o66Yp1t1ikxd3ljtqegViXem62JqzveA=="], "@rsbuild/plugin-react": ["@rsbuild/plugin-react@1.4.3", "", { "dependencies": { "@rspack/plugin-react-refresh": "^1.5.3", "react-refresh": "^0.18.0" }, "peerDependencies": { "@rsbuild/core": "^1.0.0 || ^2.0.0-0" } }, "sha512-Uf9FkKk2TqYDbsypXHgjdivPmEoYFvBTHJT5fPmjCf0Sc3lR2BHtlc0WMdZTCKUJ5jTxREygMs9LbnehX98L8g=="], - "@rspack/binding": ["@rspack/binding@1.7.2", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.2", "@rspack/binding-darwin-x64": "1.7.2", "@rspack/binding-linux-arm64-gnu": "1.7.2", "@rspack/binding-linux-arm64-musl": "1.7.2", "@rspack/binding-linux-x64-gnu": "1.7.2", "@rspack/binding-linux-x64-musl": "1.7.2", "@rspack/binding-wasm32-wasi": "1.7.2", "@rspack/binding-win32-arm64-msvc": "1.7.2", "@rspack/binding-win32-ia32-msvc": "1.7.2", "@rspack/binding-win32-x64-msvc": "1.7.2" } }, "sha512-bVssRQ39TgGA2RxKEbhUBKYRHln9sbBi0motHmqSU53aMnIkiLXjcj7tZC5dK7Okl2SrHM5KCYK9eG4UodDfdA=="], + "@rspack/binding": ["@rspack/binding@1.7.3", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.3", "@rspack/binding-darwin-x64": "1.7.3", "@rspack/binding-linux-arm64-gnu": "1.7.3", "@rspack/binding-linux-arm64-musl": "1.7.3", "@rspack/binding-linux-x64-gnu": "1.7.3", "@rspack/binding-linux-x64-musl": "1.7.3", "@rspack/binding-wasm32-wasi": "1.7.3", "@rspack/binding-win32-arm64-msvc": "1.7.3", "@rspack/binding-win32-ia32-msvc": "1.7.3", "@rspack/binding-win32-x64-msvc": "1.7.3" } }, "sha512-N943pbPktJPymiYZWZMZMVX/PeSU42cWGpBly82N+ibNCX/Oo4yKWE0v+TyIJm5JaUFhtF2NpvzRbrjg/6skqw=="], - "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EsmfzNZnuEhVPMX5jWATCHT2UCCBh6iqq448xUMmASDiKVbIOhUTN1ONTV+aMERYl7BgMNJn0iTis6ot2GWKIg=="], + "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-sXha3xG2KDkXLVjrmnw5kGhBriH2gFd9KAyD2ZBq0sH/gNIvqEaWhAFoO1YtrKU6rCgiSBrs0frfGc6DEqWfTA=="], - "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-lQLq0eNzFDzR31XD0H5oTG0y8cBoNF9hJ2gt1GgqMlYvaY+pMEeh7s4rTX1/M0c4gHpLudp86SsDuDJ53BwnaQ=="], + "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-AUWMBgaPo7NgpW7arlw9laj9ZQxg7EjC5pnSCRH4BVPV+8egdoPCn5DZk05M25m73crKnGl8c7CrwTRNZeaPrw=="], - "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-rtrsygVbDYw55ukdIk3NEwNQWkUemfRgeNOUvZ0k/6p7eP16020VPDvIqvcmyPtBhwFmz5vfo57GnBLisjM/kw=="], + "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-SodEX3+1/GLz0LobX9cY1QdjJ1NftSEh4C2vGpr71iA3MS9HyXuw4giqSeRQ4DpCybqpdS/3RLjVqFQEfGpcnw=="], - "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-zhh6ycumTHI7V/VOOT6DolvBe5RFG+Np/e5hhlhjEFtskraO9rkWg8knE9Ssu6a6Qdj4nGscqOj9ENNpc6gb+A=="], + "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-ydD2fNdEy+G7EYJ/a3FfdFZPfrLj/UnZocCNlZTTSHEhu+jURdQk0hwV11CvL+sjnKU5e/8IVMGUzhu3Gu8Ghg=="], - "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.2", "", { "os": "linux", "cpu": "x64" }, "sha512-ON9hy6OTpBOmmFp/51RPa0r9bDbZ3wTTubT54V+yhHuB+eSrlXQIOQScUGCGoGgqp6sLTwKjv2yy7YLyzd1gCA=="], + "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.3", "", { "os": "linux", "cpu": "x64" }, "sha512-adnDbUqafSAI6/N6vZ+iONSo1W3yUpnNtJqP3rVp7+YdABhUpbOhtaY37qpIJ3uFajXctYFyISPrb4MWl1M9Yg=="], - "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.2", "", { "os": "linux", "cpu": "x64" }, "sha512-+2nnjwaSOStgLKtY5O7I3yfkwTkhiJLQ35CwQqWKRw+g1E4OFIKpXBfl34JDtrF/2DeS7sVVyLeuC25+43n9/A=="], + "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.3", "", { "os": "linux", "cpu": "x64" }, "sha512-5jnjdODk5HCUFPN6rTaFukynDU4Fn9eCL+4TSp6mqo6YAnfnJEuzDjfetA8t3aQFcAs7WriQfNwvdcA4HvYtbA=="], - "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.2", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-TU/aLBpm9CTR/RTLF27WlvBKGyju6gpiNTRd3XRbX2JfY3UBNUQN/Ev+gQMVeOj55y9Fruzou42/w9ncTKA0Dw=="], + "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.3", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-WLQK0ksUzMkVeGoHAMIxenmeEU5tMvFDK36Aip7VRj7T6vZTcAwvbMwc38QrIAvlG7dqWoxgPQi35ba1igNNDw=="], - "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-RReQN3AUu46XUZnOy5L/vSj5J+tcl/bzSnGQ2KetZ7dUOjGCC6c0Ki3EiklVM5OC1Agytz0Rz7cJqHJ+HaQbsA=="], + "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-RAetPeY45g2NW6fID46VTV7mwY4Lqyw/flLbvCG28yrVOSkekw1KMCr1k335O3VNeqD+5dZDi1n+mwiAx/KMmA=="], - "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-EytrfT2sfUCnRMtXfSNv7AR65DWuY3dX/Bsn1TTin7CC6+RFEAP9nzHtCMISvFPp+c5bveok0/eY8j/f4LZ/Gg=="], + "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-X3c1B609DxzW++FdWf7kkoXWwsC/DUEJ1N1qots4T0P2G2V+pDQfjdTRSC0YQ75toAvwZqpwGzToQJ9IwQ4Ayw=="], - "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.2", "", { "os": "win32", "cpu": "x64" }, "sha512-zLFt6cr55fjbIy6HT1xS2yLVmtvRjyZ0TbcRum7Ipp+s23gyGHVYNRuDMj34AHnhbCcX/XrxDTzCc4ba6xtYTw=="], + "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.3", "", { "os": "win32", "cpu": "x64" }, "sha512-f6AvZbJGIg+7NggHXv0+lyMzvIUfeCxcB5DNbo3H5AalIgwkoFpcBXLBqgMVIbqA0yNyP06eiK98rpzc9ulQQg=="], - "@rspack/cli": ["@rspack/cli@1.7.2", "", { "dependencies": { "@discoveryjs/json-ext": "^0.5.7", "@rspack/dev-server": "~1.1.5", "exit-hook": "^4.0.0", "webpack-bundle-analyzer": "4.10.2" }, "peerDependencies": { "@rspack/core": "^1.0.0-alpha || ^1.x" }, "bin": { "rspack": "bin/rspack.js" } }, "sha512-X0Z67n0qu2sDodpJticfV1PHRS6T4Pszwp6KwgVv75sMeaHP0hc3A79B/W2SN2mT7DRVp57Cd99MoNmM3OOgLQ=="], + "@rspack/cli": ["@rspack/cli@1.7.3", "", { "dependencies": { "@discoveryjs/json-ext": "^0.5.7", "@rspack/dev-server": "~1.1.5", "exit-hook": "^4.0.0", "webpack-bundle-analyzer": "4.10.2" }, "peerDependencies": { "@rspack/core": "^1.0.0-alpha || ^1.x" }, "bin": { "rspack": "bin/rspack.js" } }, "sha512-6fb+cd1RjCK3ByN8oq7dIXZWFkbI7+y7VGlIvt/Nl2roGnL3IzXhEbyQzmXv9X+/fZ/pEKHWEyH05Rnqs3+VUQ=="], - "@rspack/core": ["@rspack/core@1.7.2", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.2", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-Pm06phSQqbthbzl92KdnbXmwcnYRv3Ef86uE6hoADqVjsmt2WvJwNjpqgs0S6n+s9UL6QzxqaaAaKg5qeBT+3g=="], + "@rspack/core": ["@rspack/core@1.7.3", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.3", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-GUiTRTz6+gbfM2g3ixXqrvPSeHmyAFu/qHEZZjbYFeDtZhpy1gVaVAHiZfaaIIm+vRlNi7JmULWFZQFKwpQB9Q=="], "@rspack/dev-server": ["@rspack/dev-server@1.1.5", "", { "dependencies": { "chokidar": "^3.6.0", "http-proxy-middleware": "^2.0.9", "p-retry": "^6.2.0", "webpack-dev-server": "5.2.2", "ws": "^8.18.0" }, "peerDependencies": { "@rspack/core": "*" } }, "sha512-cwz0qc6iqqoJhyWqxP7ZqE2wyYNHkBMQUXxoQ0tNoZ4YNRkDyQ4HVJ/3oPSmMKbvJk/iJ16u7xZmwG6sK47q/A=="], @@ -715,55 +726,55 @@ "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", "tailwindcss": "4.1.18" } }, "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="], - "@tanstack/devtools": ["@tanstack/devtools@0.7.0", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/keyboard": "^1.3.3", "@solid-primitives/resize-observer": "^2.1.3", "@tanstack/devtools-client": "0.0.3", "@tanstack/devtools-event-bus": "0.3.3", "@tanstack/devtools-ui": "0.4.4", "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-AlAoCqJhWLg9GBEaoV1g/j+X/WA1aJSWOsekxeuZpYeS2hdVuKAjj04KQLUMJhtLfNl2s2E+TCj7ZRtWyY3U4w=="], + "@tanstack/devtools": ["@tanstack/devtools@0.10.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/keyboard": "^1.3.3", "@solid-primitives/resize-observer": "^2.1.3", "@tanstack/devtools-client": "0.0.5", "@tanstack/devtools-event-bus": "0.4.0", "@tanstack/devtools-ui": "0.4.4", "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-M2HnKtaNf3Z8JDTNDq+X7/1gwOqSwTnCyC0GR+TYiRZM9mkY9GpvTqp6p6bx3DT8onu2URJiVxgHD9WK2e3MNQ=="], - "@tanstack/devtools-client": ["@tanstack/devtools-client@0.0.3", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.3.3" } }, "sha512-kl0r6N5iIL3t9gGDRAv55VRM3UIyMKVH83esRGq7xBjYsRLe/BeCIN2HqrlJkObUXQMKhy7i8ejuGOn+bDqDBw=="], + "@tanstack/devtools-client": ["@tanstack/devtools-client@0.0.5", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.4.0" } }, "sha512-hsNDE3iu4frt9cC2ppn1mNRnLKo2uc1/1hXAyY9z4UYb+o40M2clFAhiFoo4HngjfGJDV3x18KVVIq7W4Un+zA=="], - "@tanstack/devtools-event-bus": ["@tanstack/devtools-event-bus@0.3.3", "", { "dependencies": { "ws": "^8.18.3" } }, "sha512-lWl88uLAz7ZhwNdLH6A3tBOSEuBCrvnY9Fzr5JPdzJRFdM5ZFdyNWz1Bf5l/F3GU57VodrN0KCFi9OA26H5Kpg=="], + "@tanstack/devtools-event-bus": ["@tanstack/devtools-event-bus@0.4.0", "", { "dependencies": { "ws": "^8.18.3" } }, "sha512-1t+/csFuDzi+miDxAOh6Xv7VDE80gJEItkTcAZLjV5MRulbO/W8ocjHLI2Do/p2r2/FBU0eKCRTpdqvXaYoHpQ=="], - "@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.3.5", "", {}, "sha512-RL1f5ZlfZMpghrCIdzl6mLOFLTuhqmPNblZgBaeKfdtk5rfbjykurv+VfYydOFXj0vxVIoA2d/zT7xfD7Ph8fw=="], + "@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.4.0", "", {}, "sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw=="], "@tanstack/devtools-ui": ["@tanstack/devtools-ui@0.4.4", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-5xHXFyX3nom0UaNfiOM92o6ziaHjGo3mcSGe2HD5Xs8dWRZNpdZ0Smd0B9ddEhy0oB+gXyMzZgUJb9DmrZV0Mg=="], - "@tanstack/history": ["@tanstack/history@1.151.1", "", {}, "sha512-Z/eymNBuUGHYIea7nNX3xR5feqx418ChlwWOKklVpCVzEQ5Q3kNTUw+WK4HYUKxF+1uXFN01Dbuhhl7SmW1LJA=="], + "@tanstack/history": ["@tanstack/history@1.154.14", "", {}, "sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA=="], - "@tanstack/query-core": ["@tanstack/query-core@5.90.19", "", {}, "sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA=="], + "@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="], "@tanstack/query-devtools": ["@tanstack/query-devtools@5.92.0", "", {}, "sha512-N8D27KH1vEpVacvZgJL27xC6yPFUy0Zkezn5gnB3L3gRCxlDeSuiya7fKge8Y91uMTnC8aSxBQhcK6ocY7alpQ=="], - "@tanstack/react-devtools": ["@tanstack/react-devtools@0.7.11", "", { "dependencies": { "@tanstack/devtools": "0.7.0" }, "peerDependencies": { "@types/react": ">=16.8", "@types/react-dom": ">=16.8", "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-a2Lmz8x+JoDrsU6f7uKRcyyY+k8mA/n5mb9h7XJ3Fz/y3+sPV9t7vAW1s5lyNkQyyDt6V1Oim99faLthoJSxMw=="], + "@tanstack/react-devtools": ["@tanstack/react-devtools@0.9.2", "", { "dependencies": { "@tanstack/devtools": "0.10.3" }, "peerDependencies": { "@types/react": ">=16.8", "@types/react-dom": ">=16.8", "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-JNXvBO3jgq16GzTVm7p65n5zHNfMhnqF6Bm7CawjoqZrjEakxbM6Yvy63aKSIpbrdf+Wun2Xn8P0qD+vp56e1g=="], - "@tanstack/react-query": ["@tanstack/react-query@5.90.19", "", { "dependencies": { "@tanstack/query-core": "5.90.19" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-qTZRZ4QyTzQc+M0IzrbKHxSeISUmRB3RPGmao5bT+sI6ayxSRhn0FXEnT5Hg3as8SBFcRosrXXRFB+yAcxVxJQ=="], + "@tanstack/react-query": ["@tanstack/react-query@5.90.20", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw=="], "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.91.2", "", { "dependencies": { "@tanstack/query-devtools": "5.92.0" }, "peerDependencies": { "@tanstack/react-query": "^5.90.14", "react": "^18 || ^19" } }, "sha512-ZJ1503ay5fFeEYFUdo7LMNFzZryi6B0Cacrgr2h1JRkvikK1khgIq6Nq2EcblqEdIlgB/r7XDW8f8DQ89RuUgg=="], - "@tanstack/react-router": ["@tanstack/react-router@1.151.1", "", { "dependencies": { "@tanstack/history": "1.151.1", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.151.1", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-343gO0W5HrYH4TEhZIvnjqbrLHHfIk0/OE0+fWgWh/Ke0dVTMOuEc1EAIgEpMqZgnsma+4gqIroqjivYd9rR2A=="], + "@tanstack/react-router": ["@tanstack/react-router@1.157.15", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.157.15", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-dVHX3Ann1rxLkXCrB9ctNKveGOrkmlKMo5fDIaaPCqqkDN/aC1gZ9O93i0OQVPUNekpkdXijmpHkxw12WqMTRQ=="], - "@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.151.1", "", { "dependencies": { "@tanstack/router-devtools-core": "1.151.1" }, "peerDependencies": { "@tanstack/react-router": "^1.151.1", "@tanstack/router-core": "^1.151.1", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-JoRtzzuUw9LaCq2Rv9QjPgCaMU54Go0638qmhCvZLYwWrBjOwvuGq9KhrOJEhJOi9vViqw8HiGFRPoEHEGe7pA=="], + "@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.157.15", "", { "dependencies": { "@tanstack/router-devtools-core": "1.157.15" }, "peerDependencies": { "@tanstack/react-router": "^1.157.15", "@tanstack/router-core": "^1.157.15", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-WNxsQaoVz1MDINKbWJ7xGYg0xyG9UAnRq7cYNFypDFyX6gqfiQUTxpFMVZfaw1sv+/fI/6E+hd7WChu1rrfBqQ=="], "@tanstack/react-store": ["@tanstack/react-store@0.8.0", "", { "dependencies": { "@tanstack/store": "0.8.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow=="], "@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="], - "@tanstack/router-core": ["@tanstack/router-core@1.151.1", "", { "dependencies": { "@tanstack/history": "1.151.1", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.1", "seroval-plugins": "^1.4.0", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-RNH/jkxqPhCCEMZ3LTGQXJGzQKMATAfHRT2oquFD9T4BqBW4IMeZoeptEPV4So8j3lK33tn0IDkyg6Jzyq0JcQ=="], + "@tanstack/router-core": ["@tanstack/router-core@1.157.15", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-KaYz6s+wYcg92kRQ7HXlTJLhBaBXOYiiqRBv5tsRbKRIqqhWNyeGz5+NfDwaYFHg5XLSDs3DvN0elMtxcj4dTg=="], - "@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.151.1", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.151.1", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-1tWGZ/0BFEDfJho7kQPysK4hkZVcf0bwu72ZytP9FH8l/yOCWifytxrEXbCGYEmNjluZrEnShN9nc9dWY09O+w=="], + "@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.157.15", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.157.15", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-udqDYuJUtVfPmk/4yhtOZl1dYlze/rMqaj3v/jQRS8TeGqWYal48Q18hM3A5Bd2YqORvaAkOQsI7JWKYnvxCiQ=="], - "@tanstack/router-generator": ["@tanstack/router-generator@1.151.1", "", { "dependencies": { "@tanstack/router-core": "1.151.1", "@tanstack/router-utils": "1.143.11", "@tanstack/virtual-file-routes": "1.145.4", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-MB+UCsG9bsQfHqA3eDcW0ZjfYp1fkgboU4cs4k4zieSs4qqxL4rW2Bq0U1G8nV8UL7I6+sWecWGpV+ThbpHlqw=="], + "@tanstack/router-generator": ["@tanstack/router-generator@1.157.15", "", { "dependencies": { "@tanstack/router-core": "1.157.15", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-zGac6tyRFz/X86fk9/CAmS6z8lyZf4p9lhAqLBCKVkFiFPmU4eAJp1ODvs81EtV0uJdRL1/rb+uvgHLGUsmQ0g=="], - "@tanstack/router-plugin": ["@tanstack/router-plugin@1.151.1", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.151.1", "@tanstack/router-generator": "1.151.1", "@tanstack/router-utils": "1.143.11", "@tanstack/virtual-file-routes": "1.145.4", "babel-dead-code-elimination": "^1.0.11", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.151.1", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-AkWk2L5pCouWrVBGEY1rvuSIRIwbTxi7myQXoIZOJ6enR8w03qhJQpWWj5JX4mhipDQs2nOljIrnR68nPlWIxg=="], + "@tanstack/router-plugin": ["@tanstack/router-plugin@1.157.15", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.157.15", "@tanstack/router-generator": "1.157.15", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "babel-dead-code-elimination": "^1.0.11", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.157.15", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-EpRYRb35//sVJ8GPBhthqfPt9HNhx1xAaejiQ8i4vkG37et6qaSGAO+Woq91WjnpmxMYs4+sNJpGioPuVLBBqQ=="], - "@tanstack/router-utils": ["@tanstack/router-utils@1.143.11", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-N24G4LpfyK8dOlnP8BvNdkuxg1xQljkyl6PcrdiPSA301pOjatRT1y8wuCCJZKVVD8gkd0MpCZ0VEjRMGILOtA=="], + "@tanstack/router-utils": ["@tanstack/router-utils@1.154.7", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-61bGx32tMKuEpVRseu2sh1KQe8CfB7793Mch/kyQt0EP3tD7X0sXmimCl3truRiDGUtI0CaSoQV1NPjAII1RBA=="], "@tanstack/store": ["@tanstack/store@0.8.0", "", {}, "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ=="], "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="], - "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.145.4", "", {}, "sha512-CI75JrfqSluhdGwLssgVeQBaCphgfkMQpi8MCY3UJX1hoGzXa8kHYJcUuIFMOLs1q7zqHy++EVVtMK03osR5wQ=="], + "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.154.7", "", {}, "sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg=="], "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], - "@testing-library/react": ["@testing-library/react@16.3.1", "", { "dependencies": { "@babel/runtime": "^7.12.5" }, "peerDependencies": { "@testing-library/dom": "^10.0.0", "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw=="], + "@testing-library/react": ["@testing-library/react@16.3.2", "", { "dependencies": { "@babel/runtime": "^7.12.5" }, "peerDependencies": { "@testing-library/dom": "^10.0.0", "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g=="], "@toon-format/toon": ["@toon-format/toon@0.9.0", "", {}, "sha512-BaMhGh1+/z8ceDrF2xL9Drd42hijbUJlivm/1goPR26RgCYsqlMkHbg48hx9a5UjZC7oZqxWPJ6ju5qvALi6Ag=="], @@ -775,74 +786,14 @@ "@types/bonjour": ["@types/bonjour@3.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ=="], + "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], "@types/connect-history-api-fallback": ["@types/connect-history-api-fallback@1.5.4", "", { "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw=="], - "@types/d3": ["@types/d3@7.4.3", "", { "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", "@types/d3-brush": "*", "@types/d3-chord": "*", "@types/d3-color": "*", "@types/d3-contour": "*", "@types/d3-delaunay": "*", "@types/d3-dispatch": "*", "@types/d3-drag": "*", "@types/d3-dsv": "*", "@types/d3-ease": "*", "@types/d3-fetch": "*", "@types/d3-force": "*", "@types/d3-format": "*", "@types/d3-geo": "*", "@types/d3-hierarchy": "*", "@types/d3-interpolate": "*", "@types/d3-path": "*", "@types/d3-polygon": "*", "@types/d3-quadtree": "*", "@types/d3-random": "*", "@types/d3-scale": "*", "@types/d3-scale-chromatic": "*", "@types/d3-selection": "*", "@types/d3-shape": "*", "@types/d3-time": "*", "@types/d3-time-format": "*", "@types/d3-timer": "*", "@types/d3-transition": "*", "@types/d3-zoom": "*" } }, "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww=="], - - "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], - - "@types/d3-axis": ["@types/d3-axis@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw=="], - - "@types/d3-brush": ["@types/d3-brush@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A=="], - - "@types/d3-chord": ["@types/d3-chord@3.0.6", "", {}, "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg=="], - - "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], - - "@types/d3-contour": ["@types/d3-contour@3.0.6", "", { "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" } }, "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg=="], - - "@types/d3-delaunay": ["@types/d3-delaunay@6.0.4", "", {}, "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw=="], - - "@types/d3-dispatch": ["@types/d3-dispatch@3.0.7", "", {}, "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA=="], - - "@types/d3-drag": ["@types/d3-drag@3.0.7", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ=="], - - "@types/d3-dsv": ["@types/d3-dsv@3.0.7", "", {}, "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g=="], - - "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], - - "@types/d3-fetch": ["@types/d3-fetch@3.0.7", "", { "dependencies": { "@types/d3-dsv": "*" } }, "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA=="], - - "@types/d3-force": ["@types/d3-force@3.0.10", "", {}, "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw=="], - - "@types/d3-format": ["@types/d3-format@3.0.4", "", {}, "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g=="], - - "@types/d3-geo": ["@types/d3-geo@3.1.0", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ=="], - - "@types/d3-hierarchy": ["@types/d3-hierarchy@3.1.7", "", {}, "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg=="], - - "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], - - "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], - - "@types/d3-polygon": ["@types/d3-polygon@3.0.2", "", {}, "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA=="], - - "@types/d3-quadtree": ["@types/d3-quadtree@3.0.6", "", {}, "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg=="], - - "@types/d3-random": ["@types/d3-random@3.0.3", "", {}, "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ=="], - - "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], - - "@types/d3-scale-chromatic": ["@types/d3-scale-chromatic@3.1.0", "", {}, "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ=="], - - "@types/d3-selection": ["@types/d3-selection@3.0.11", "", {}, "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="], - - "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="], - - "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], - - "@types/d3-time-format": ["@types/d3-time-format@4.0.3", "", {}, "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg=="], - - "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], - - "@types/d3-transition": ["@types/d3-transition@3.0.9", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg=="], - - "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="], - "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], @@ -855,8 +806,6 @@ "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.8", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA=="], - "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], - "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], "@types/http-proxy": ["@types/http-proxy@1.17.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw=="], @@ -865,7 +814,7 @@ "@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="], - "@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="], + "@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="], "@types/node-forge": ["@types/node-forge@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw=="], @@ -873,7 +822,7 @@ "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], - "@types/react": ["@types/react@19.2.8", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg=="], + "@types/react": ["@types/react@19.2.9", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="], "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], @@ -891,19 +840,19 @@ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - "@vitest/expect": ["@vitest/expect@4.0.17", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.17", "@vitest/utils": "4.0.17", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ=="], + "@vitest/expect": ["@vitest/expect@4.0.18", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ=="], - "@vitest/mocker": ["@vitest/mocker@4.0.17", "", { "dependencies": { "@vitest/spy": "4.0.17", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ=="], + "@vitest/mocker": ["@vitest/mocker@4.0.18", "", { "dependencies": { "@vitest/spy": "4.0.18", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ=="], - "@vitest/pretty-format": ["@vitest/pretty-format@4.0.17", "", { "dependencies": { "tinyrainbow": "^3.0.3" } }, "sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw=="], + "@vitest/pretty-format": ["@vitest/pretty-format@4.0.18", "", { "dependencies": { "tinyrainbow": "^3.0.3" } }, "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw=="], - "@vitest/runner": ["@vitest/runner@4.0.17", "", { "dependencies": { "@vitest/utils": "4.0.17", "pathe": "^2.0.3" } }, "sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ=="], + "@vitest/runner": ["@vitest/runner@4.0.18", "", { "dependencies": { "@vitest/utils": "4.0.18", "pathe": "^2.0.3" } }, "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw=="], - "@vitest/snapshot": ["@vitest/snapshot@4.0.17", "", { "dependencies": { "@vitest/pretty-format": "4.0.17", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ=="], + "@vitest/snapshot": ["@vitest/snapshot@4.0.18", "", { "dependencies": { "@vitest/pretty-format": "4.0.18", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA=="], - "@vitest/spy": ["@vitest/spy@4.0.17", "", {}, "sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew=="], + "@vitest/spy": ["@vitest/spy@4.0.18", "", {}, "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw=="], - "@vitest/utils": ["@vitest/utils@4.0.17", "", { "dependencies": { "@vitest/pretty-format": "4.0.17", "tinyrainbow": "^3.0.3" } }, "sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w=="], + "@vitest/utils": ["@vitest/utils@4.0.18", "", { "dependencies": { "@vitest/pretty-format": "4.0.18", "tinyrainbow": "^3.0.3" } }, "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA=="], "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="], @@ -987,17 +936,17 @@ "at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="], - "axios": ["axios@1.13.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="], + "axios": ["axios@1.13.3", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-ERT8kdX7DZjtUm7IitEyV7InTHAF42iJuMArIiDIV5YtPanJkgw4hw5Dyg9fh0mihdWNn1GKaeIWErfe56UQ1g=="], "axios-retry": ["axios-retry@4.5.0", "", { "dependencies": { "is-retry-allowed": "^2.2.0" }, "peerDependencies": { "axios": "0.x || 1.x" } }, "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ=="], "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.9.15", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.9.18", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-e23vBV1ZLfjb9apvfPk4rHVu2ry6RIr2Wfs+O324okSidrX7pTAnEJPCh/O5BtRlr7QtZI7ktOP3vsqr7Z5XoA=="], "batch": ["batch@0.6.1", "", {}, "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw=="], - "better-auth": ["better-auth@1.4.14", "", { "dependencies": { "@better-auth/core": "1.4.14", "@better-auth/telemetry": "1.4.14", "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21", "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "better-call": "1.1.8", "defu": "^6.1.4", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1", "zod": "^4.1.12" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start-server": "^1.0.0", "@tanstack/solid-start-server": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", "drizzle-orm": ">=0.41.0", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start-server", "@tanstack/solid-start-server", "better-sqlite3", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-gDpOmWOilhnLIBuv/7/6HoaXLtCDR7iUEjkvYCunJhUWZng53kZ2jivxtekhYC0j4+VSG6AZTihPIaoKrlztlA=="], + "better-auth": ["better-auth@1.4.17", "", { "dependencies": { "@better-auth/core": "1.4.17", "@better-auth/telemetry": "1.4.17", "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21", "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "better-call": "1.1.8", "defu": "^6.1.4", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1", "zod": "^4.3.5" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", "drizzle-orm": ">=0.41.0", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "better-sqlite3", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-VmHGQyKsEahkEs37qguROKg/6ypYpNF13D7v/lkbO7w7Aivz0Bv2h+VyUkH4NzrGY0QBKXi1577mGhDCVwp0ew=="], "better-call": ["better-call@1.1.8", "", { "dependencies": { "@better-auth/utils": "^0.3.0", "@better-fetch/fetch": "^1.1.4", "rou3": "^0.7.10", "set-cookie-parser": "^2.7.1" }, "peerDependencies": { "zod": "^4.0.0" }, "optionalPeers": ["zod"] }, "sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw=="], @@ -1019,24 +968,22 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], + "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], - "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - "caniuse-lite": ["caniuse-lite@1.0.30001764", "", {}, "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g=="], + "caniuse-lite": ["caniuse-lite@1.0.30001766", "", {}, "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA=="], - "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], "chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="], - "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], - "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], @@ -1047,8 +994,6 @@ "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], - "classcat": ["classcat@5.0.5", "", {}, "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w=="], - "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], @@ -1087,33 +1032,17 @@ "cron-parser": ["cron-parser@4.9.0", "", { "dependencies": { "luxon": "^3.2.1" } }, "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q=="], + "cross-fetch": ["cross-fetch@4.1.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw=="], + "css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="], "cssstyle": ["cssstyle@5.3.7", "", { "dependencies": { "@asamuzakjp/css-color": "^4.1.1", "@csstools/css-syntax-patches-for-csstree": "^1.0.21", "css-tree": "^3.1.0", "lru-cache": "^11.2.4" } }, "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], - - "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="], - - "d3-drag": ["d3-drag@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" } }, "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg=="], - - "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], - - "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], - - "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="], - - "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], - - "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="], - - "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="], - "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], - "data-urls": ["data-urls@6.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^15.0.0" } }, "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA=="], + "data-urls": ["data-urls@6.0.1", "", { "dependencies": { "whatwg-mimetype": "^5.0.0", "whatwg-url": "^15.1.0" } }, "sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ=="], "date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="], @@ -1123,8 +1052,6 @@ "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], - "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], - "deep-equal": ["deep-equal@1.0.1", "", {}, "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw=="], "default-browser": ["default-browser@5.4.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg=="], @@ -1169,9 +1096,9 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "effect": ["effect@3.19.14", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-3vwdq0zlvQOxXzXNKRIPKTqZNMyGCdaFUBfMPqpsyzZDre67kgC1EEHDV4EoQTovJ4w5fmJW756f86kkuz7WFA=="], + "effect": ["effect@3.19.15", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-vzMmgfZKLcojmUjBdlQx+uaKryO7yULlRxjpDnHdnvcp1NPHxJyoM6IOXBLlzz2I/uPtZpGKavt5hBv7IvGZkA=="], - "electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="], + "electron-to-chromium": ["electron-to-chromium@1.5.279", "", {}, "sha512-0bblUU5UNdOt5G7XqGiJtpZMONma6WAfq9vsFmtn9x1+joAObr6x1chfqyxFSDCAFwFhCQDrqeAr6MYdpwJ9Hg=="], "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], @@ -1193,7 +1120,7 @@ "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], - "esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + "esbuild": ["esbuild@0.25.12", "", { "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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], @@ -1319,7 +1246,7 @@ "homedir-polyfill": ["homedir-polyfill@1.0.3", "", { "dependencies": { "parse-passwd": "^1.0.0" } }, "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA=="], - "hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="], + "hono": ["hono@4.11.6", "", {}, "sha512-ofIiiHyl34SV6AuhE3YT2mhO5HRWokce+eUYE82TsP6z0/H3JeJcjVWEMSIAiw2QkjDOEpES/lYsg8eEbsLtdw=="], "host": ["host@workspace:host"], @@ -1389,7 +1316,7 @@ "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "isbot": ["isbot@5.1.32", "", {}, "sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ=="], + "isbot": ["isbot@5.1.34", "", {}, "sha512-aCMIBSKd/XPRYdiCQTLC8QHH4YT8B3JUADu+7COgYIZPvkeoMcUHMRjZLM9/7V8fCj+l7FSREc1lOPNjzogo/A=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -1425,7 +1352,7 @@ "koa-compose": ["koa-compose@4.1.0", "", {}, "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw=="], - "kysely": ["kysely@0.28.9", "", {}, "sha512-3BeXMoiOhpOwu62CiVpO6lxfq4eS6KMYfQdMsN/2kUCRNuF2YiEr7u0HLHaQU+O4Xu8YXE3bHVkwaQ85i72EuA=="], + "kysely": ["kysely@0.28.10", "", {}, "sha512-ksNxfzIW77OcZ+QWSAPC7yDqUSaIVwkTWnTPNiIy//vifNbwsSgQ57OkkncHxxpcBHM3LRfLAZVEh7kjq5twVA=="], "launch-editor": ["launch-editor@2.12.0", "", { "dependencies": { "picocolors": "^1.1.1", "shell-quote": "^1.8.3" } }, "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg=="], @@ -1463,11 +1390,9 @@ "long-timeout": ["long-timeout@0.1.1", "", {}, "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w=="], - "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], - - "lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], + "lru-cache": ["lru-cache@11.2.5", "", {}, "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw=="], - "lucide-react": ["lucide-react@0.544.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw=="], + "lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="], "luxon": ["luxon@3.7.2", "", {}, "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew=="], @@ -1481,7 +1406,7 @@ "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], - "memfs": ["memfs@4.53.0", "", { "dependencies": { "@jsonjoy.com/json-pack": "^1.11.0", "@jsonjoy.com/util": "^1.9.0", "glob-to-regex.js": "^1.0.1", "thingies": "^2.5.0", "tree-dump": "^1.0.3", "tslib": "^2.0.0" } }, "sha512-TKFRsKjJA30iAc9ZeGH/77v5nLcNUD0GBOL/tAj4O63RPIKNxGDZ54ZyuQM4KjEKEj7gfer/Ta1xAzB+HrEnrA=="], + "memfs": ["memfs@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.56.10", "@jsonjoy.com/fs-fsa": "4.56.10", "@jsonjoy.com/fs-node": "4.56.10", "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-to-fsa": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10", "@jsonjoy.com/fs-print": "4.56.10", "@jsonjoy.com/fs-snapshot": "4.56.10", "@jsonjoy.com/json-pack": "^1.11.0", "@jsonjoy.com/util": "^1.9.0", "glob-to-regex.js": "^1.0.1", "thingies": "^2.5.0", "tree-dump": "^1.0.3", "tslib": "^2.0.0" } }, "sha512-eLvzyrwqLHnLYalJP7YZ3wBe79MXktMdfQbvMrVD80K+NhrIukCVBvgP30zTJYEEDh9hZ/ep9z0KOdD7FSHo7w=="], "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], @@ -1513,7 +1438,7 @@ "nanostores": ["nanostores@1.1.0", "", {}, "sha512-yJBmDJr18xy47dbNVlHcgdPrulSn1nhSE6Ns9vTG+Nx9VPT6iV1MD6aQFp/t52zpf82FhLLTXAXr30NuCnxvwA=="], - "near-kit": ["near-kit@0.6.3", "", { "dependencies": { "@napi-rs/keyring": "^1.2.0", "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", "@scure/base": "^2.0.0", "@scure/bip32": "^2.0.1", "@scure/bip39": "^2.0.1", "@zorsh/zorsh": "^0.4.0", "tar": "^7.5.2", "zod": "^4.1.12" }, "peerDependencies": { "@hot-labs/near-connect": ">=0.6.0", "@near-wallet-selector/core": ">=8.0.0" }, "optionalPeers": ["@hot-labs/near-connect", "@near-wallet-selector/core"] }, "sha512-3OibK7+2iODvwb+E9Cualz9HsH+hKdh6Q6WwhhGSjrKKurOslkcCOA1Bz7EK5sU7p+SZItJ53rI+eyQ0wQteNg=="], + "near-kit": ["near-kit@0.10.0", "", { "dependencies": { "@napi-rs/keyring": "^1.2.0", "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", "@scure/base": "^2.0.0", "@scure/bip32": "^2.0.1", "@scure/bip39": "^2.0.1", "@zorsh/zorsh": "^0.4.0", "tar": "^7.5.6", "zod": "^4.3.6" }, "peerDependencies": { "@hot-labs/near-connect": ">=0.6.0", "@near-wallet-selector/core": ">=8.0.0" }, "optionalPeers": ["@hot-labs/near-connect", "@near-wallet-selector/core"] }, "sha512-P/UEXT8gSbdZgeEFc7lMIOmUvkCwczmypDS5vU/7gUdcFG8S77ZymBzn8dkyxxLeVA2wFkwVpAPmzJEEX9m4ug=="], "near-sign-verify": ["near-sign-verify@0.4.5", "", { "dependencies": { "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", "@scure/base": "^2.0.0", "@zorsh/zorsh": "^0.3.3" } }, "sha512-AOcPcKywejmKgCdQN4j77EyanK8AsIoZQzZnpKSk9wQMmxEi/97+GbDMb4p0TSAJEOuumfJRtJ5V5VYp+2qbKg=="], @@ -1575,15 +1500,13 @@ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], - "prettier": ["prettier@3.8.0", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA=="], + "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], "pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="], @@ -1615,9 +1538,9 @@ "raw-body": ["raw-body@2.5.3", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" } }, "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA=="], - "react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="], + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], - "react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="], + "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], "react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], @@ -1629,8 +1552,6 @@ "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], - "reactflow": ["reactflow@11.11.4", "", { "dependencies": { "@reactflow/background": "11.3.14", "@reactflow/controls": "11.2.14", "@reactflow/core": "11.11.4", "@reactflow/minimap": "11.7.14", "@reactflow/node-resizer": "2.2.14", "@reactflow/node-toolbar": "1.3.14" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-70FOtJkUWH3BAOsN+LU9lCrKoKbtOPnz2uq0CV2PLdNSwxTXOhCbsZr50GmZ+Rtw3jx8Uv7/vBFtCGixLfd4Og=="], - "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], @@ -1651,7 +1572,7 @@ "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], - "rollup": ["rollup@4.55.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.1", "@rollup/rollup-android-arm64": "4.55.1", "@rollup/rollup-darwin-arm64": "4.55.1", "@rollup/rollup-darwin-x64": "4.55.1", "@rollup/rollup-freebsd-arm64": "4.55.1", "@rollup/rollup-freebsd-x64": "4.55.1", "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", "@rollup/rollup-linux-arm-musleabihf": "4.55.1", "@rollup/rollup-linux-arm64-gnu": "4.55.1", "@rollup/rollup-linux-arm64-musl": "4.55.1", "@rollup/rollup-linux-loong64-gnu": "4.55.1", "@rollup/rollup-linux-loong64-musl": "4.55.1", "@rollup/rollup-linux-ppc64-gnu": "4.55.1", "@rollup/rollup-linux-ppc64-musl": "4.55.1", "@rollup/rollup-linux-riscv64-gnu": "4.55.1", "@rollup/rollup-linux-riscv64-musl": "4.55.1", "@rollup/rollup-linux-s390x-gnu": "4.55.1", "@rollup/rollup-linux-x64-gnu": "4.55.1", "@rollup/rollup-linux-x64-musl": "4.55.1", "@rollup/rollup-openbsd-x64": "4.55.1", "@rollup/rollup-openharmony-arm64": "4.55.1", "@rollup/rollup-win32-arm64-msvc": "4.55.1", "@rollup/rollup-win32-ia32-msvc": "4.55.1", "@rollup/rollup-win32-x64-gnu": "4.55.1", "@rollup/rollup-win32-x64-msvc": "4.55.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A=="], + "rollup": ["rollup@4.56.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.56.0", "@rollup/rollup-android-arm64": "4.56.0", "@rollup/rollup-darwin-arm64": "4.56.0", "@rollup/rollup-darwin-x64": "4.56.0", "@rollup/rollup-freebsd-arm64": "4.56.0", "@rollup/rollup-freebsd-x64": "4.56.0", "@rollup/rollup-linux-arm-gnueabihf": "4.56.0", "@rollup/rollup-linux-arm-musleabihf": "4.56.0", "@rollup/rollup-linux-arm64-gnu": "4.56.0", "@rollup/rollup-linux-arm64-musl": "4.56.0", "@rollup/rollup-linux-loong64-gnu": "4.56.0", "@rollup/rollup-linux-loong64-musl": "4.56.0", "@rollup/rollup-linux-ppc64-gnu": "4.56.0", "@rollup/rollup-linux-ppc64-musl": "4.56.0", "@rollup/rollup-linux-riscv64-gnu": "4.56.0", "@rollup/rollup-linux-riscv64-musl": "4.56.0", "@rollup/rollup-linux-s390x-gnu": "4.56.0", "@rollup/rollup-linux-x64-gnu": "4.56.0", "@rollup/rollup-linux-x64-musl": "4.56.0", "@rollup/rollup-openbsd-x64": "4.56.0", "@rollup/rollup-openharmony-arm64": "4.56.0", "@rollup/rollup-win32-arm64-msvc": "4.56.0", "@rollup/rollup-win32-ia32-msvc": "4.56.0", "@rollup/rollup-win32-x64-gnu": "4.56.0", "@rollup/rollup-win32-x64-msvc": "4.56.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-9FwVqlgUHzbXtDg9RCMgodF3Ua4Na6Gau+Sdt9vyCN4RhHfVKX2DCHy3BjMLTDd47ITDhYAnTwGulWTblJSDLg=="], "rou3": ["rou3@0.7.12", "", {}, "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg=="], @@ -1671,17 +1592,17 @@ "selfsigned": ["selfsigned@2.4.1", "", { "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" } }, "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q=="], - "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], "send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="], "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], - "seroval": ["seroval@1.4.2", "", {}, "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ=="], + "seroval": ["seroval@1.5.0", "", {}, "sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw=="], - "seroval-plugins": ["seroval-plugins@1.4.2", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA=="], + "seroval-plugins": ["seroval-plugins@1.5.0", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA=="], - "serve-index": ["serve-index@1.9.1", "", { "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", "debug": "2.6.9", "escape-html": "~1.0.3", "http-errors": "~1.6.2", "mime-types": "~2.1.17", "parseurl": "~1.3.2" } }, "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw=="], + "serve-index": ["serve-index@1.9.2", "", { "dependencies": { "accepts": "~1.3.8", "batch": "0.6.1", "debug": "2.6.9", "escape-html": "~1.0.3", "http-errors": "~1.8.0", "mime-types": "~2.1.35", "parseurl": "~1.3.3" } }, "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ=="], "serve-static": ["serve-static@1.16.3", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "~0.19.1" } }, "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA=="], @@ -1707,7 +1628,7 @@ "sockjs": ["sockjs@0.3.24", "", { "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" } }, "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ=="], - "solid-js": ["solid-js@1.9.10", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew=="], + "solid-js": ["solid-js@1.9.11", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q=="], "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="], @@ -1735,8 +1656,6 @@ "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], @@ -1751,7 +1670,7 @@ "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], - "tar": ["tar@7.5.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-ENg5JUHUm2rDD7IvKNFGzyElLXNjachNLp6RaGf4+JOgxXHkqA+gq81ZAMCUmtMtqBsoU62lcp6S27g1LCYGGQ=="], + "tar": ["tar@7.5.6", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA=="], "terser": ["terser@5.46.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg=="], @@ -1771,12 +1690,8 @@ "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], - "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], - "tinyrainbow": ["tinyrainbow@3.0.3", "", {}, "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q=="], - "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], - "tldts": ["tldts@7.0.19", "", { "dependencies": { "tldts-core": "^7.0.19" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA=="], "tldts-core": ["tldts-core@7.0.19", "", {}, "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A=="], @@ -1801,20 +1716,6 @@ "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], - "turbo": ["turbo@2.7.5", "", { "optionalDependencies": { "turbo-darwin-64": "2.7.5", "turbo-darwin-arm64": "2.7.5", "turbo-linux-64": "2.7.5", "turbo-linux-arm64": "2.7.5", "turbo-windows-64": "2.7.5", "turbo-windows-arm64": "2.7.5" }, "bin": { "turbo": "bin/turbo" } }, "sha512-7Imdmg37joOloTnj+DPrab9hIaQcDdJ5RwSzcauo/wMOSAgO+A/I/8b3hsGGs6PWQz70m/jkPgdqWsfNKtwwDQ=="], - - "turbo-darwin-64": ["turbo-darwin-64@2.7.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-nN3wfLLj4OES/7awYyyM7fkU8U8sAFxsXau2bYJwAWi6T09jd87DgHD8N31zXaJ7LcpyppHWPRI2Ov9MuZEwnQ=="], - - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.7.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wCoDHMiTf3FgLAbZHDDx/unNNonSGhsF5AbbYODbxnpYyoKDpEYacUEPjZD895vDhNvYCH0Nnk24YsP4n/cD6g=="], - - "turbo-linux-64": ["turbo-linux-64@2.7.5", "", { "os": "linux", "cpu": "x64" }, "sha512-KKPvhOmJMmzWj/yjeO4LywkQ85vOJyhru7AZk/+c4B6OUh/odQ++SiIJBSbTG2lm1CuV5gV5vXZnf/2AMlu3Zg=="], - - "turbo-linux-arm64": ["turbo-linux-arm64@2.7.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-8PIva4L6BQhiPikUTds9lSFSHXVDAsEvV6QUlgwPsXrtXVQMVi6Sv9p+IxtlWQFvGkdYJUgX9GnK2rC030Xcmw=="], - - "turbo-windows-64": ["turbo-windows-64@2.7.5", "", { "os": "win32", "cpu": "x64" }, "sha512-rupskv/mkIUgQXzX/wUiK00mKMorQcK8yzhGFha/D5lm05FEnLx8dsip6rWzMcVpvh+4GUMA56PgtnOgpel2AA=="], - - "turbo-windows-arm64": ["turbo-windows-arm64@2.7.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-G377Gxn6P42RnCzfMyDvsqQV7j69kVHKlhz9J4RhtJOB5+DyY4yYh/w0oTIxZQ4JRMmhjwLu3w9zncMoQ6nNDw=="], - "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], "type-fest": ["type-fest@5.4.1", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-xygQcmneDyzsEuKZrFbRMne5HDqMs++aFzefrJTgEIKjQ3rekM+RPfFCVq2Gp1VIDqddoYeppCj4Pcb+RZW0GQ=="], @@ -1853,11 +1754,9 @@ "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "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" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], - "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], + "vite-tsconfig-paths": ["vite-tsconfig-paths@6.0.5", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-f/WvY6ekHykUF1rWJUAbCU7iS/5QYDIugwpqJA+ttwKbxSbzNlqlE8vZSrsnxNQciUW+z6lvhlXMaEyZn9MSig=="], - "vite-tsconfig-paths": ["vite-tsconfig-paths@6.0.4", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3", "vite": "*" } }, "sha512-iIsEJ+ek5KqRTK17pmxtgIxXtqr3qDdE6OxrP9mVeGhVDNXRJTKN/l9oMbujTQNzMLe6XZ8qmpztfbkPu2TiFQ=="], - - "vitest": ["vitest@4.0.17", "", { "dependencies": { "@vitest/expect": "4.0.17", "@vitest/mocker": "4.0.17", "@vitest/pretty-format": "4.0.17", "@vitest/runner": "4.0.17", "@vitest/snapshot": "4.0.17", "@vitest/spy": "4.0.17", "@vitest/utils": "4.0.17", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.17", "@vitest/browser-preview": "4.0.17", "@vitest/browser-webdriverio": "4.0.17", "@vitest/ui": "4.0.17", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg=="], + "vitest": ["vitest@4.0.18", "", { "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", "@vitest/pretty-format": "4.0.18", "@vitest/runner": "4.0.18", "@vitest/snapshot": "4.0.18", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.18", "@vitest/browser-preview": "4.0.18", "@vitest/browser-webdriverio": "4.0.18", "@vitest/ui": "4.0.18", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ=="], "w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="], @@ -1909,75 +1808,57 @@ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "zephyr-agent": ["zephyr-agent@0.1.4", "", { "dependencies": { "@toon-format/toon": "^0.9.0", "axios": "^1.12.0", "axios-retry": "^4.5.0", "debug": "^4.3.4", "eventsource": "^4.0.0", "git-url-parse": "^15.0.0", "is-ci": "^4.1.0", "jose": "^5.10.0", "node-persist": "^4.0.1", "open": "^10.1.0", "proper-lockfile": "^4.1.2", "tslib": "^2.8.1", "zephyr-edge-contract": "0.1.4" } }, "sha512-/etHBEPr0BiGMKA8uSwsrzE5ofOgkl4QcYNOKIT0Bv7KTK8nevMcK52PdR/c5PAEMxfw5ewuZA7/TxGPecj4+g=="], + "zephyr-agent": ["zephyr-agent@0.1.8", "", { "dependencies": { "@toon-format/toon": "^0.9.0", "axios": "^1.12.0", "axios-retry": "^4.5.0", "debug": "^4.3.4", "eventsource": "^4.0.0", "git-url-parse": "^15.0.0", "is-ci": "^4.1.0", "jose": "^5.10.0", "node-persist": "^4.0.1", "open": "^10.1.0", "proper-lockfile": "^4.1.2", "tslib": "^2.8.1", "zephyr-edge-contract": "0.1.8" }, "peerDependencies": { "https-proxy-agent": "^7.0.6" } }, "sha512-rEuzsN/wEKYTReBjIjqXWpo7DxzVcvprMSEGyiLyWXewWA7ECmYoK8/6pJjpIidgcuGrl9kFE0Y9aYe6lV1jWQ=="], - "zephyr-edge-contract": ["zephyr-edge-contract@0.1.4", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-g/4oz95ajrqAap1Sfc6Av6Vy+FVez4AMxEk5X5rJGShSRvGyCXc8W7uKjYFxMlx9nf3iZ94h+NcXv2qyOUewXA=="], + "zephyr-edge-contract": ["zephyr-edge-contract@0.1.8", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-raJQmMdJvlrxnlL2L5/6Mlrru3sw0WCcsHcNWukBoLHN6KbR73G3qyTiyCDOJHnP3pWHcKZrtUXtk9sFmKj/UQ=="], - "zephyr-rsbuild-plugin": ["zephyr-rsbuild-plugin@0.1.4", "", { "dependencies": { "zephyr-rspack-plugin": "0.1.4" }, "peerDependencies": { "@rsbuild/core": "^1.0.0" } }, "sha512-/YRkBIPw71Y21C+FpSCEKtD175ruGBFF9+BMvzNUePefqvVAonPESeqt3M4IdMuV+Q26dSKsShY5qAOXUHt8Wg=="], + "zephyr-rsbuild-plugin": ["zephyr-rsbuild-plugin@0.1.8", "", { "dependencies": { "zephyr-rspack-plugin": "0.1.8" }, "peerDependencies": { "@rsbuild/core": "^1.0.0" } }, "sha512-Orn7tcyT6GNYQ5Y+GidflJg/L7jHXeYTOfT403AkV1Qf3aQW0rZ28wHbxX4w1MAzY3SimobUWSCx9NQbyiZUjQ=="], - "zephyr-rspack-plugin": ["zephyr-rspack-plugin@0.1.4", "", { "dependencies": { "tslib": "^2.8.1", "zephyr-agent": "0.1.4", "zephyr-xpack-internal": "0.1.4" }, "peerDependencies": { "@rspack/core": "^1.0.0" } }, "sha512-rozsBpVIO7Tnd4J8TAcTk3k7h5SzOOeRX9rVVEelDzhwbJ22bTtFfLDxgzQ6vclAbpxdmW28jYrmgCKXoF/s0Q=="], + "zephyr-rspack-plugin": ["zephyr-rspack-plugin@0.1.8", "", { "dependencies": { "tslib": "^2.8.1", "zephyr-agent": "0.1.8", "zephyr-xpack-internal": "0.1.8" }, "peerDependencies": { "@rspack/core": "^1.0.0" } }, "sha512-DMO1Lo7VX449ZCURE6wTypIuLNaCUJNWOHE/Ny7at0L3hph17fazwRSn6M5DW9rcLqG8nsAPqYzJJCBg4K7wpA=="], - "zephyr-xpack-internal": ["zephyr-xpack-internal@0.1.4", "", { "dependencies": { "@module-federation/automatic-vendor-federation": "^1.2.1", "tslib": "^2.8.1", "zephyr-agent": "0.1.4", "zephyr-edge-contract": "0.1.4" } }, "sha512-qN6WtSey/hQM2vt9OPU2hK3VwgMBS2g2ykVCl+dvcz9rnbCg3HHRkHxERnE7u58C96nUBj4TnN3Fd05iirJItA=="], + "zephyr-xpack-internal": ["zephyr-xpack-internal@0.1.8", "", { "dependencies": { "@module-federation/automatic-vendor-federation": "^1.2.1", "tslib": "^2.8.1", "zephyr-agent": "0.1.8", "zephyr-edge-contract": "0.1.8" } }, "sha512-xdSsZr5rDebKkINsOp99WeIe1YhhU4VkAWkLxHk1onNnjMxDuBPzo37lmPUBYLLrImdlD91sNWFZxop1jnHDdg=="], - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], "zustand": ["zustand@5.0.10", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "@better-auth/core/zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@better-auth/core/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], - "@libsql/hrana-client/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@17.65.0", "", { "dependencies": { "@jsonjoy.com/base64": "17.65.0", "@jsonjoy.com/buffers": "17.65.0", "@jsonjoy.com/codegen": "17.65.0", "@jsonjoy.com/json-pointer": "17.65.0", "@jsonjoy.com/util": "17.65.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-e0SG/6qUCnVhHa0rjDJHgnXnbsacooHVqQHxspjvlYQSkHm+66wkHw6Gql+3u/WxI/b1VsOdUi0M+fOtkgKGdQ=="], + + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/util": ["@jsonjoy.com/util@17.65.0", "", { "dependencies": { "@jsonjoy.com/buffers": "17.65.0", "@jsonjoy.com/codegen": "17.65.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-cWiEHZccQORf96q2y6zU3wDeIVPeidmGqd9cNKJRYoVHTV0S1eHPy5JTbHpMnGfDvtvujQwQozOqgO9ABu6h0w=="], - "@module-federation/bridge-react-webpack-plugin/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], + "@jsonjoy.com/json-pack/@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@1.2.1", "", { "peerDependencies": { "tslib": "2" } }, "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA=="], - "@module-federation/bridge-react-webpack-plugin/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], + "@jsonjoy.com/util/@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@1.2.1", "", { "peerDependencies": { "tslib": "2" } }, "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA=="], - "@module-federation/cli/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], + "@libsql/hrana-client/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], "@module-federation/cli/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "@module-federation/cli/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], - "@module-federation/data-prefetch/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], - "@module-federation/data-prefetch/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], - "@module-federation/dts-plugin/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], - "@module-federation/dts-plugin/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], "@module-federation/dts-plugin/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], - "@module-federation/enhanced/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.21.6", "", { "dependencies": { "@module-federation/runtime": "0.21.6", "@module-federation/webpack-bundler-runtime": "0.21.6" } }, "sha512-fnP+ZOZTFeBGiTAnxve+axGmiYn2D60h86nUISXjXClK3LUY1krUfPgf6MaD4YDJ4i51OGXZWPekeMe16pkd8Q=="], - - "@module-federation/enhanced/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], + "@module-federation/enhanced/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.23.0", "", { "dependencies": { "@module-federation/runtime": "0.23.0", "@module-federation/webpack-bundler-runtime": "0.23.0" } }, "sha512-TzUaU/X+mVHHilz8WApivSLjMZaBhydQrrMtrWCK4yUNfIjC/SmnGrdhmZE3qFxXezk4iit60KKS+xxZ+2udPg=="], - "@module-federation/inject-external-runtime-core-plugin/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.21.6", "", { "dependencies": { "@module-federation/runtime": "0.21.6", "@module-federation/webpack-bundler-runtime": "0.21.6" } }, "sha512-fnP+ZOZTFeBGiTAnxve+axGmiYn2D60h86nUISXjXClK3LUY1krUfPgf6MaD4YDJ4i51OGXZWPekeMe16pkd8Q=="], - - "@module-federation/managers/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], + "@module-federation/inject-external-runtime-core-plugin/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.23.0", "", { "dependencies": { "@module-federation/runtime": "0.23.0", "@module-federation/webpack-bundler-runtime": "0.23.0" } }, "sha512-TzUaU/X+mVHHilz8WApivSLjMZaBhydQrrMtrWCK4yUNfIjC/SmnGrdhmZE3qFxXezk4iit60KKS+xxZ+2udPg=="], "@module-federation/managers/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], - "@module-federation/manifest/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], - - "@module-federation/node/@module-federation/enhanced": ["@module-federation/enhanced@0.22.1", "", { "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.22.1", "@module-federation/cli": "0.22.1", "@module-federation/data-prefetch": "0.22.1", "@module-federation/dts-plugin": "0.22.1", "@module-federation/error-codes": "0.22.1", "@module-federation/inject-external-runtime-core-plugin": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/manifest": "0.22.1", "@module-federation/rspack": "0.22.1", "@module-federation/runtime-tools": "0.22.1", "@module-federation/sdk": "0.22.1", "btoa": "^1.2.1", "schema-utils": "^4.3.0", "upath": "2.0.1" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24", "webpack": "^5.0.0" }, "optionalPeers": ["typescript", "vue-tsc", "webpack"], "bin": { "mf": "bin/mf.js" } }, "sha512-0xUEmo1omhtSqFFtSec9tuUAwZ8rYUmqGngarBK8yaQXBa/g7NO7IZUN5rlRFzAvUh3Jl+Xyaq2qApTWEcpFwg=="], - - "@module-federation/node/@module-federation/runtime": ["@module-federation/runtime@0.22.1", "", { "dependencies": { "@module-federation/error-codes": "0.22.1", "@module-federation/runtime-core": "0.22.1", "@module-federation/sdk": "0.22.1" } }, "sha512-oFC5hHFSYDKquEO5+BA2pnEpFn6+Ky7eJyJlbo2KHBq7kVHbi+1i2b74H1mKjmF8Q66Q/PZQxF5GhcB2ehxVjg=="], - - "@module-federation/rsbuild-plugin/@module-federation/node": ["@module-federation/node@2.7.25", "", { "dependencies": { "@module-federation/enhanced": "0.21.6", "@module-federation/runtime": "0.21.6", "@module-federation/sdk": "0.21.6", "btoa": "1.2.1", "encoding": "^0.1.13", "node-fetch": "2.7.0" }, "peerDependencies": { "react": "^16||^17||^18||^19", "react-dom": "^16||^17||^18||^19", "webpack": "^5.40.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-/u4f+GYRZfHpSvdt5n40lMCS9Cmve7N3JlDreaFXz8xrWDNOp2wvMgiVGpndo5J4iQdtLjpavWStahGQ05B2cQ=="], - - "@module-federation/rsbuild-plugin/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], - - "@module-federation/rspack/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.21.6", "", { "dependencies": { "@module-federation/runtime": "0.21.6", "@module-federation/webpack-bundler-runtime": "0.21.6" } }, "sha512-fnP+ZOZTFeBGiTAnxve+axGmiYn2D60h86nUISXjXClK3LUY1krUfPgf6MaD4YDJ4i51OGXZWPekeMe16pkd8Q=="], - - "@module-federation/rspack/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], - - "@module-federation/runtime/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], - - "@module-federation/runtime-core/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], + "@module-federation/rspack/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.23.0", "", { "dependencies": { "@module-federation/runtime": "0.23.0", "@module-federation/webpack-bundler-runtime": "0.23.0" } }, "sha512-TzUaU/X+mVHHilz8WApivSLjMZaBhydQrrMtrWCK4yUNfIjC/SmnGrdhmZE3qFxXezk4iit60KKS+xxZ+2udPg=="], "@module-federation/runtime-tools/@module-federation/runtime": ["@module-federation/runtime@0.22.0", "", { "dependencies": { "@module-federation/error-codes": "0.22.0", "@module-federation/runtime-core": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA=="], @@ -2053,18 +1934,6 @@ "@radix-ui/react-visually-hidden/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - "@reactflow/background/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], - - "@reactflow/controls/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], - - "@reactflow/core/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], - - "@reactflow/minimap/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], - - "@reactflow/node-resizer/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], - - "@reactflow/node-toolbar/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], @@ -2077,23 +1946,19 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], + "@tanstack/router-generator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@tanstack/router-plugin/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "api/vite-tsconfig-paths": ["vite-tsconfig-paths@5.1.4", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" }, "optionalPeers": ["vite"] }, "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w=="], - - "api/vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@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", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "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": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="], - - "better-auth/zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], - - "better-call/zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], + "better-auth/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "better-near-auth/near-kit": ["near-kit@0.7.0", "", { "dependencies": { "@napi-rs/keyring": "^1.2.0", "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", "@scure/base": "^2.0.0", "@scure/bip32": "^2.0.1", "@scure/bip39": "^2.0.1", "@zorsh/zorsh": "^0.4.0", "tar": "^7.5.2", "zod": "^4.1.12" }, "peerDependencies": { "@hot-labs/near-connect": ">=0.6.0", "@near-wallet-selector/core": ">=8.0.0" }, "optionalPeers": ["@hot-labs/near-connect", "@near-wallet-selector/core"] }, "sha512-mqE9i8QRq0DV/mky8RY+tO1kdx+yuQm3X5nuWiJAXqrfVe17SvDoMjyZpDWENSUqempiU22kBQX4OjGod4B96g=="], - "better-near-auth/zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], + "better-near-auth/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -2107,7 +1972,7 @@ "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "drizzle-kit/esbuild": ["esbuild@0.25.12", "", { "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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + "data-urls/whatwg-mimetype": ["whatwg-mimetype@5.0.0", "", {}, "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw=="], "esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], @@ -2115,7 +1980,7 @@ "every-plugin/@module-federation/runtime-core": ["@module-federation/runtime-core@0.22.1", "", { "dependencies": { "@module-federation/error-codes": "0.22.1", "@module-federation/sdk": "0.22.1" } }, "sha512-bQNECpm3MMHWlCOt1I6b+kgA9vJPKbT4Zz2IvlVgx73Nig6jsXMzkVBybFQIDVLFmjb18Bx9wvOZkQn9iB9GGA=="], - "every-plugin/zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], + "every-plugin/effect": ["effect@3.19.14", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-3vwdq0zlvQOxXzXNKRIPKTqZNMyGCdaFUBfMPqpsyzZDre67kgC1EEHDV4EoQTovJ4w5fmJW756f86kkuz7WFA=="], "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], @@ -2125,8 +1990,6 @@ "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "host/@types/node": ["@types/node@22.19.7", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw=="], - "hpack.js/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "http-assert/http-errors": ["http-errors@1.8.1", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.1" } }, "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g=="], @@ -2139,7 +2002,7 @@ "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "near-kit/zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], + "near-kit/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "near-sign-verify/@zorsh/zorsh": ["@zorsh/zorsh@0.3.3", "", {}, "sha512-Fu+iihpwuWPki/I93Bnocj4wmsDaOIfplzvbWGY1zvkGkvPq7y+npE2/Sub0bJJ0EB2C6fH/JvHkbH9B+9OIDQ=="], @@ -2161,25 +2024,19 @@ "serve-index/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "serve-index/http-errors": ["http-errors@1.6.3", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", "statuses": ">= 1.4.0 < 2" } }, "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A=="], - - "solid-js/seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="], - - "solid-js/seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="], + "serve-index/http-errors": ["http-errors@1.8.1", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.1" } }, "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g=="], "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "streamroller/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], - "strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], - "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "type-is/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + "tsx/esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], - "ui/@types/node": ["@types/node@22.19.7", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw=="], + "type-is/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], - "ui/vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@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", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "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": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="], + "vite/esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], "webpack/es-module-lexer": ["es-module-lexer@2.0.0", "", {}, "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw=="], @@ -2237,35 +2094,19 @@ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], - "@module-federation/enhanced/@module-federation/runtime-tools/@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.21.6", "", { "dependencies": { "@module-federation/runtime": "0.21.6", "@module-federation/sdk": "0.21.6" } }, "sha512-7zIp3LrcWbhGuFDTUMLJ2FJvcwjlddqhWGxi/MW3ur1a+HaO8v5tF2nl+vElKmbG1DFLU/52l3PElVcWf/YcsQ=="], - - "@module-federation/inject-external-runtime-core-plugin/@module-federation/runtime-tools/@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.21.6", "", { "dependencies": { "@module-federation/runtime": "0.21.6", "@module-federation/sdk": "0.21.6" } }, "sha512-7zIp3LrcWbhGuFDTUMLJ2FJvcwjlddqhWGxi/MW3ur1a+HaO8v5tF2nl+vElKmbG1DFLU/52l3PElVcWf/YcsQ=="], + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack/@jsonjoy.com/base64": ["@jsonjoy.com/base64@17.65.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-Xrh7Fm/M0QAYpekSgmskdZYnFdSGnsxJ/tHaolA4bNwWdG9i65S8m83Meh7FOxyJyQAdo4d4J97NOomBLEfkDQ=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/bridge-react-webpack-plugin": ["@module-federation/bridge-react-webpack-plugin@0.22.1", "", { "dependencies": { "@module-federation/sdk": "0.22.1", "@types/semver": "7.5.8", "semver": "7.6.3" } }, "sha512-jKxU4GC5P/gVTJW1pOheHz+hk7yZiEmsyapNslxpD+ZVv2eN/OI6Om5mKJVtSa5tvrQMw/lVMAaX6UNkd34k0g=="], + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack/@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@17.65.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-7MXcRYe7n3BG+fo3jicvjB0+6ypl2Y/bQp79Sp7KeSiiCgLqw4Oled6chVv07/xLVTdo3qa1CD0VCCnPaw+RGA=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/cli": ["@module-federation/cli@0.22.1", "", { "dependencies": { "@module-federation/dts-plugin": "0.22.1", "@module-federation/sdk": "0.22.1", "chalk": "3.0.0", "commander": "11.1.0", "jiti": "2.4.2" }, "bin": { "mf": "bin/mf.js" } }, "sha512-/kw1yb/kWuYxmLhvz1mpKTdSAR/O18A/DJLa39Rmayq++DMbQHEwFrYr3BsVRdDcAaX2/R+CyHATvVFNn5EPSg=="], + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack/@jsonjoy.com/json-pointer": ["@jsonjoy.com/json-pointer@17.65.0", "", { "dependencies": { "@jsonjoy.com/util": "17.65.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-uhTe+XhlIZpWOxgPcnO+iSCDgKKBpwkDVTyYiXX9VayGV8HSFVJM67M6pUE71zdnXF1W0Da21AvnhlmdwYPpow=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/data-prefetch": ["@module-federation/data-prefetch@0.22.1", "", { "dependencies": { "@module-federation/runtime": "0.22.1", "@module-federation/sdk": "0.22.1", "fs-extra": "9.1.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-6jcZSFuUpU06IWPIaQeoB+HI2NI2BUmiV65oEYsjnwXtLMT8aFTGqN1XCZc0R2V7b5hBa1rSrk/FGCAXnwiFNQ=="], + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/util/@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@17.65.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-7MXcRYe7n3BG+fo3jicvjB0+6ypl2Y/bQp79Sp7KeSiiCgLqw4Oled6chVv07/xLVTdo3qa1CD0VCCnPaw+RGA=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/dts-plugin": ["@module-federation/dts-plugin@0.22.1", "", { "dependencies": { "@module-federation/error-codes": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/sdk": "0.22.1", "@module-federation/third-party-dts-extractor": "0.22.1", "adm-zip": "^0.5.10", "ansi-colors": "^4.1.3", "axios": "^1.12.0", "chalk": "3.0.0", "fs-extra": "9.1.0", "isomorphic-ws": "5.0.0", "koa": "3.0.3", "lodash.clonedeepwith": "4.5.0", "log4js": "6.9.1", "node-schedule": "2.1.1", "rambda": "^9.1.0", "ws": "8.18.0" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["vue-tsc"] }, "sha512-+zdQco9j1wbIhTAlLG5mZ7lSem9X9YnUzZNVSKqKF69Wg/rm220acMPSXJc7W+Nw6DuSp0m9elMA3I31DW7etg=="], + "@module-federation/enhanced/@module-federation/runtime-tools/@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.23.0", "", { "dependencies": { "@module-federation/runtime": "0.23.0", "@module-federation/sdk": "0.23.0" } }, "sha512-HnYVRiCg5nKpJ5LnUxT4iNzvay7fd/ZdubO/AWp4AqW7Y/cVaRFNNhg8cytuIZAha3R73BLYqia/a518K5dSwg=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/error-codes": ["@module-federation/error-codes@0.22.1", "", {}, "sha512-J3Gt4E2U9cSUoAUUrUSp7n1W8v3OT8B6UcVdt+p+fTKKkQ1yhDVWE7SOTgDCA7hiEaO9D6Gahwnn5IbxlH0pTQ=="], + "@module-federation/inject-external-runtime-core-plugin/@module-federation/runtime-tools/@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.23.0", "", { "dependencies": { "@module-federation/runtime": "0.23.0", "@module-federation/sdk": "0.23.0" } }, "sha512-HnYVRiCg5nKpJ5LnUxT4iNzvay7fd/ZdubO/AWp4AqW7Y/cVaRFNNhg8cytuIZAha3R73BLYqia/a518K5dSwg=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/inject-external-runtime-core-plugin": ["@module-federation/inject-external-runtime-core-plugin@0.22.1", "", { "peerDependencies": { "@module-federation/runtime-tools": "0.22.1" } }, "sha512-1+bkU/qbV87sR4QvsCQXtple/DIV1w1nuBKukBWI9UCz8M42ihpDljmdq794n/BC4D9kUk6z0nbA7hjgPcC2hg=="], - - "@module-federation/node/@module-federation/enhanced/@module-federation/managers": ["@module-federation/managers@0.22.1", "", { "dependencies": { "@module-federation/sdk": "0.22.1", "find-pkg": "2.0.0", "fs-extra": "9.1.0" } }, "sha512-9x557xoKjZrNwIp12wYGnizSdDfwEVgorlODVLyUcRe1pT0mx3cKtSxvuvkUle+CylgYLz6b4AFRNEZjYD4oFQ=="], - - "@module-federation/node/@module-federation/enhanced/@module-federation/manifest": ["@module-federation/manifest@0.22.1", "", { "dependencies": { "@module-federation/dts-plugin": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/sdk": "0.22.1", "chalk": "3.0.0", "find-pkg": "2.0.0" } }, "sha512-DQiV24e8xb63tEJQMdRvFx4BwsKtLmGkU+NtR6GrnT2OT0pj6AEva+zr8AkQLH9vDWtzGAr7FFxjJyZbKj2RZQ=="], - - "@module-federation/node/@module-federation/enhanced/@module-federation/rspack": ["@module-federation/rspack@0.22.1", "", { "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.22.1", "@module-federation/dts-plugin": "0.22.1", "@module-federation/inject-external-runtime-core-plugin": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/manifest": "0.22.1", "@module-federation/runtime-tools": "0.22.1", "@module-federation/sdk": "0.22.1", "btoa": "1.2.1" }, "peerDependencies": { "@rspack/core": ">=0.7", "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["typescript", "vue-tsc"] }, "sha512-dBOUpvtcls+VBCFwWBct6Z6xbxL/XCdeoADzX5CwbVt5ZB9H3qq2Qcj9shwO5M+4KJsfQDBSzkL7gqK7vNFlKA=="], - - "@module-federation/node/@module-federation/enhanced/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.22.1", "", { "dependencies": { "@module-federation/runtime": "0.22.1", "@module-federation/webpack-bundler-runtime": "0.22.1" } }, "sha512-GzqNytPPnQVejl78XFFvtLyj3XNgPu6rSac2EbQkCxV3uzAD3kFQ7SW0VuwXWbQeRTUgt/4Nl/o+BrJXy14lsw=="], - - "@module-federation/node/@module-federation/runtime/@module-federation/error-codes": ["@module-federation/error-codes@0.22.1", "", {}, "sha512-J3Gt4E2U9cSUoAUUrUSp7n1W8v3OT8B6UcVdt+p+fTKKkQ1yhDVWE7SOTgDCA7hiEaO9D6Gahwnn5IbxlH0pTQ=="], - - "@module-federation/node/@module-federation/runtime/@module-federation/runtime-core": ["@module-federation/runtime-core@0.22.1", "", { "dependencies": { "@module-federation/error-codes": "0.22.1", "@module-federation/sdk": "0.22.1" } }, "sha512-bQNECpm3MMHWlCOt1I6b+kgA9vJPKbT4Zz2IvlVgx73Nig6jsXMzkVBybFQIDVLFmjb18Bx9wvOZkQn9iB9GGA=="], - - "@module-federation/rspack/@module-federation/runtime-tools/@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.21.6", "", { "dependencies": { "@module-federation/runtime": "0.21.6", "@module-federation/sdk": "0.21.6" } }, "sha512-7zIp3LrcWbhGuFDTUMLJ2FJvcwjlddqhWGxi/MW3ur1a+HaO8v5tF2nl+vElKmbG1DFLU/52l3PElVcWf/YcsQ=="], + "@module-federation/rspack/@module-federation/runtime-tools/@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.23.0", "", { "dependencies": { "@module-federation/runtime": "0.23.0", "@module-federation/sdk": "0.23.0" } }, "sha512-HnYVRiCg5nKpJ5LnUxT4iNzvay7fd/ZdubO/AWp4AqW7Y/cVaRFNNhg8cytuIZAha3R73BLYqia/a518K5dSwg=="], "@module-federation/runtime-tools/@module-federation/runtime/@module-federation/error-codes": ["@module-federation/error-codes@0.22.0", "", {}, "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug=="], @@ -2303,187 +2144,177 @@ "@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], - "api/vitest/@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], - - "api/vitest/@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="], - - "api/vitest/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], - - "api/vitest/@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="], - - "api/vitest/@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="], - - "api/vitest/@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], + "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "api/vitest/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], + "body-parser/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], - "api/vitest/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "api/vitest/tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], + "every-plugin/@module-federation/enhanced/@module-federation/bridge-react-webpack-plugin": ["@module-federation/bridge-react-webpack-plugin@0.22.1", "", { "dependencies": { "@module-federation/sdk": "0.22.1", "@types/semver": "7.5.8", "semver": "7.6.3" } }, "sha512-jKxU4GC5P/gVTJW1pOheHz+hk7yZiEmsyapNslxpD+ZVv2eN/OI6Om5mKJVtSa5tvrQMw/lVMAaX6UNkd34k0g=="], - "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "every-plugin/@module-federation/enhanced/@module-federation/cli": ["@module-federation/cli@0.22.1", "", { "dependencies": { "@module-federation/dts-plugin": "0.22.1", "@module-federation/sdk": "0.22.1", "chalk": "3.0.0", "commander": "11.1.0", "jiti": "2.4.2" }, "bin": { "mf": "bin/mf.js" } }, "sha512-/kw1yb/kWuYxmLhvz1mpKTdSAR/O18A/DJLa39Rmayq++DMbQHEwFrYr3BsVRdDcAaX2/R+CyHATvVFNn5EPSg=="], - "body-parser/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + "every-plugin/@module-federation/enhanced/@module-federation/data-prefetch": ["@module-federation/data-prefetch@0.22.1", "", { "dependencies": { "@module-federation/runtime": "0.22.1", "@module-federation/sdk": "0.22.1", "fs-extra": "9.1.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-6jcZSFuUpU06IWPIaQeoB+HI2NI2BUmiV65oEYsjnwXtLMT8aFTGqN1XCZc0R2V7b5hBa1rSrk/FGCAXnwiFNQ=="], - "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "every-plugin/@module-federation/enhanced/@module-federation/dts-plugin": ["@module-federation/dts-plugin@0.22.1", "", { "dependencies": { "@module-federation/error-codes": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/sdk": "0.22.1", "@module-federation/third-party-dts-extractor": "0.22.1", "adm-zip": "^0.5.10", "ansi-colors": "^4.1.3", "axios": "^1.12.0", "chalk": "3.0.0", "fs-extra": "9.1.0", "isomorphic-ws": "5.0.0", "koa": "3.0.3", "lodash.clonedeepwith": "4.5.0", "log4js": "6.9.1", "node-schedule": "2.1.1", "rambda": "^9.1.0", "ws": "8.18.0" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["vue-tsc"] }, "sha512-+zdQco9j1wbIhTAlLG5mZ7lSem9X9YnUzZNVSKqKF69Wg/rm220acMPSXJc7W+Nw6DuSp0m9elMA3I31DW7etg=="], - "drizzle-kit/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + "every-plugin/@module-federation/enhanced/@module-federation/error-codes": ["@module-federation/error-codes@0.22.1", "", {}, "sha512-J3Gt4E2U9cSUoAUUrUSp7n1W8v3OT8B6UcVdt+p+fTKKkQ1yhDVWE7SOTgDCA7hiEaO9D6Gahwnn5IbxlH0pTQ=="], - "drizzle-kit/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + "every-plugin/@module-federation/enhanced/@module-federation/inject-external-runtime-core-plugin": ["@module-federation/inject-external-runtime-core-plugin@0.22.1", "", { "peerDependencies": { "@module-federation/runtime-tools": "0.22.1" } }, "sha512-1+bkU/qbV87sR4QvsCQXtple/DIV1w1nuBKukBWI9UCz8M42ihpDljmdq794n/BC4D9kUk6z0nbA7hjgPcC2hg=="], - "drizzle-kit/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + "every-plugin/@module-federation/enhanced/@module-federation/managers": ["@module-federation/managers@0.22.1", "", { "dependencies": { "@module-federation/sdk": "0.22.1", "find-pkg": "2.0.0", "fs-extra": "9.1.0" } }, "sha512-9x557xoKjZrNwIp12wYGnizSdDfwEVgorlODVLyUcRe1pT0mx3cKtSxvuvkUle+CylgYLz6b4AFRNEZjYD4oFQ=="], - "drizzle-kit/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + "every-plugin/@module-federation/enhanced/@module-federation/manifest": ["@module-federation/manifest@0.22.1", "", { "dependencies": { "@module-federation/dts-plugin": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/sdk": "0.22.1", "chalk": "3.0.0", "find-pkg": "2.0.0" } }, "sha512-DQiV24e8xb63tEJQMdRvFx4BwsKtLmGkU+NtR6GrnT2OT0pj6AEva+zr8AkQLH9vDWtzGAr7FFxjJyZbKj2RZQ=="], - "drizzle-kit/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + "every-plugin/@module-federation/enhanced/@module-federation/rspack": ["@module-federation/rspack@0.22.1", "", { "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.22.1", "@module-federation/dts-plugin": "0.22.1", "@module-federation/inject-external-runtime-core-plugin": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/manifest": "0.22.1", "@module-federation/runtime-tools": "0.22.1", "@module-federation/sdk": "0.22.1", "btoa": "1.2.1" }, "peerDependencies": { "@rspack/core": ">=0.7", "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["typescript", "vue-tsc"] }, "sha512-dBOUpvtcls+VBCFwWBct6Z6xbxL/XCdeoADzX5CwbVt5ZB9H3qq2Qcj9shwO5M+4KJsfQDBSzkL7gqK7vNFlKA=="], - "drizzle-kit/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + "every-plugin/@module-federation/enhanced/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.22.1", "", { "dependencies": { "@module-federation/runtime": "0.22.1", "@module-federation/webpack-bundler-runtime": "0.22.1" } }, "sha512-GzqNytPPnQVejl78XFFvtLyj3XNgPu6rSac2EbQkCxV3uzAD3kFQ7SW0VuwXWbQeRTUgt/4Nl/o+BrJXy14lsw=="], - "drizzle-kit/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + "every-plugin/@module-federation/enhanced/@module-federation/sdk": ["@module-federation/sdk@0.22.1", "", {}, "sha512-e+xcroeeZwb1lXK0tM6E7YmGr8lYHm3QzplWVM/q0Hs8SlvQMcM9Lv+JF6y9UQmhVSaMKW40PyPyqL0Y1rIeVw=="], - "drizzle-kit/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + "every-plugin/@module-federation/runtime-core/@module-federation/error-codes": ["@module-federation/error-codes@0.22.1", "", {}, "sha512-J3Gt4E2U9cSUoAUUrUSp7n1W8v3OT8B6UcVdt+p+fTKKkQ1yhDVWE7SOTgDCA7hiEaO9D6Gahwnn5IbxlH0pTQ=="], - "drizzle-kit/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + "every-plugin/@module-federation/runtime-core/@module-federation/sdk": ["@module-federation/sdk@0.22.1", "", {}, "sha512-e+xcroeeZwb1lXK0tM6E7YmGr8lYHm3QzplWVM/q0Hs8SlvQMcM9Lv+JF6y9UQmhVSaMKW40PyPyqL0Y1rIeVw=="], - "drizzle-kit/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "drizzle-kit/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + "express/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], - "drizzle-kit/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "drizzle-kit/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + "hpack.js/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - "drizzle-kit/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + "hpack.js/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], - "drizzle-kit/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + "http-assert/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], - "drizzle-kit/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + "http-assert/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], - "drizzle-kit/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + "koa/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "drizzle-kit/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + "node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - "drizzle-kit/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + "node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], - "drizzle-kit/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "drizzle-kit/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + "serve-index/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "drizzle-kit/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + "serve-index/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], - "drizzle-kit/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + "serve-index/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], - "drizzle-kit/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + "streamroller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], - "drizzle-kit/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + "streamroller/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - "drizzle-kit/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], - "every-plugin/@module-federation/enhanced/@module-federation/bridge-react-webpack-plugin": ["@module-federation/bridge-react-webpack-plugin@0.22.1", "", { "dependencies": { "@module-federation/sdk": "0.22.1", "@types/semver": "7.5.8", "semver": "7.6.3" } }, "sha512-jKxU4GC5P/gVTJW1pOheHz+hk7yZiEmsyapNslxpD+ZVv2eN/OI6Om5mKJVtSa5tvrQMw/lVMAaX6UNkd34k0g=="], + "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], - "every-plugin/@module-federation/enhanced/@module-federation/cli": ["@module-federation/cli@0.22.1", "", { "dependencies": { "@module-federation/dts-plugin": "0.22.1", "@module-federation/sdk": "0.22.1", "chalk": "3.0.0", "commander": "11.1.0", "jiti": "2.4.2" }, "bin": { "mf": "bin/mf.js" } }, "sha512-/kw1yb/kWuYxmLhvz1mpKTdSAR/O18A/DJLa39Rmayq++DMbQHEwFrYr3BsVRdDcAaX2/R+CyHATvVFNn5EPSg=="], + "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], - "every-plugin/@module-federation/enhanced/@module-federation/data-prefetch": ["@module-federation/data-prefetch@0.22.1", "", { "dependencies": { "@module-federation/runtime": "0.22.1", "@module-federation/sdk": "0.22.1", "fs-extra": "9.1.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-6jcZSFuUpU06IWPIaQeoB+HI2NI2BUmiV65oEYsjnwXtLMT8aFTGqN1XCZc0R2V7b5hBa1rSrk/FGCAXnwiFNQ=="], + "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], - "every-plugin/@module-federation/enhanced/@module-federation/dts-plugin": ["@module-federation/dts-plugin@0.22.1", "", { "dependencies": { "@module-federation/error-codes": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/sdk": "0.22.1", "@module-federation/third-party-dts-extractor": "0.22.1", "adm-zip": "^0.5.10", "ansi-colors": "^4.1.3", "axios": "^1.12.0", "chalk": "3.0.0", "fs-extra": "9.1.0", "isomorphic-ws": "5.0.0", "koa": "3.0.3", "lodash.clonedeepwith": "4.5.0", "log4js": "6.9.1", "node-schedule": "2.1.1", "rambda": "^9.1.0", "ws": "8.18.0" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["vue-tsc"] }, "sha512-+zdQco9j1wbIhTAlLG5mZ7lSem9X9YnUzZNVSKqKF69Wg/rm220acMPSXJc7W+Nw6DuSp0m9elMA3I31DW7etg=="], + "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], - "every-plugin/@module-federation/enhanced/@module-federation/error-codes": ["@module-federation/error-codes@0.22.1", "", {}, "sha512-J3Gt4E2U9cSUoAUUrUSp7n1W8v3OT8B6UcVdt+p+fTKKkQ1yhDVWE7SOTgDCA7hiEaO9D6Gahwnn5IbxlH0pTQ=="], + "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], - "every-plugin/@module-federation/enhanced/@module-federation/inject-external-runtime-core-plugin": ["@module-federation/inject-external-runtime-core-plugin@0.22.1", "", { "peerDependencies": { "@module-federation/runtime-tools": "0.22.1" } }, "sha512-1+bkU/qbV87sR4QvsCQXtple/DIV1w1nuBKukBWI9UCz8M42ihpDljmdq794n/BC4D9kUk6z0nbA7hjgPcC2hg=="], + "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], - "every-plugin/@module-federation/enhanced/@module-federation/managers": ["@module-federation/managers@0.22.1", "", { "dependencies": { "@module-federation/sdk": "0.22.1", "find-pkg": "2.0.0", "fs-extra": "9.1.0" } }, "sha512-9x557xoKjZrNwIp12wYGnizSdDfwEVgorlODVLyUcRe1pT0mx3cKtSxvuvkUle+CylgYLz6b4AFRNEZjYD4oFQ=="], + "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], - "every-plugin/@module-federation/enhanced/@module-federation/manifest": ["@module-federation/manifest@0.22.1", "", { "dependencies": { "@module-federation/dts-plugin": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/sdk": "0.22.1", "chalk": "3.0.0", "find-pkg": "2.0.0" } }, "sha512-DQiV24e8xb63tEJQMdRvFx4BwsKtLmGkU+NtR6GrnT2OT0pj6AEva+zr8AkQLH9vDWtzGAr7FFxjJyZbKj2RZQ=="], + "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], - "every-plugin/@module-federation/enhanced/@module-federation/rspack": ["@module-federation/rspack@0.22.1", "", { "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.22.1", "@module-federation/dts-plugin": "0.22.1", "@module-federation/inject-external-runtime-core-plugin": "0.22.1", "@module-federation/managers": "0.22.1", "@module-federation/manifest": "0.22.1", "@module-federation/runtime-tools": "0.22.1", "@module-federation/sdk": "0.22.1", "btoa": "1.2.1" }, "peerDependencies": { "@rspack/core": ">=0.7", "typescript": "^4.9.0 || ^5.0.0", "vue-tsc": ">=1.0.24" }, "optionalPeers": ["typescript", "vue-tsc"] }, "sha512-dBOUpvtcls+VBCFwWBct6Z6xbxL/XCdeoADzX5CwbVt5ZB9H3qq2Qcj9shwO5M+4KJsfQDBSzkL7gqK7vNFlKA=="], + "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], - "every-plugin/@module-federation/enhanced/@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.22.1", "", { "dependencies": { "@module-federation/runtime": "0.22.1", "@module-federation/webpack-bundler-runtime": "0.22.1" } }, "sha512-GzqNytPPnQVejl78XFFvtLyj3XNgPu6rSac2EbQkCxV3uzAD3kFQ7SW0VuwXWbQeRTUgt/4Nl/o+BrJXy14lsw=="], + "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], - "every-plugin/@module-federation/runtime-core/@module-federation/error-codes": ["@module-federation/error-codes@0.22.1", "", {}, "sha512-J3Gt4E2U9cSUoAUUrUSp7n1W8v3OT8B6UcVdt+p+fTKKkQ1yhDVWE7SOTgDCA7hiEaO9D6Gahwnn5IbxlH0pTQ=="], + "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], - "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], - "express/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], - "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], - "host/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], - "hpack.js/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], - "hpack.js/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "tsx/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], - "http-assert/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], + "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], - "http-assert/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], + "tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], - "koa/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], - "node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "tsx/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], - "node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], - "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], - "serve-index/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], - "serve-index/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], + "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], - "serve-index/http-errors/inherits": ["inherits@2.0.3", "", {}, "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="], + "type-is/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "serve-index/http-errors/setprototypeof": ["setprototypeof@1.1.0", "", {}, "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="], + "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], - "serve-index/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], + "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], - "streamroller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], - "streamroller/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], - "type-is/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], - "ui/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], - "ui/vitest/@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], + "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], - "ui/vitest/@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="], + "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], - "ui/vitest/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], + "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], - "ui/vitest/@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="], + "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], - "ui/vitest/@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="], + "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], - "ui/vitest/@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], + "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], - "ui/vitest/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], + "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], - "ui/vitest/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], - "ui/vitest/tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], + "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], - "webpack-dev-middleware/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], - "@module-federation/inject-external-runtime-core-plugin/@module-federation/runtime-tools/@module-federation/webpack-bundler-runtime/@module-federation/sdk": ["@module-federation/sdk@0.21.6", "", {}, "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw=="], + "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/bridge-react-webpack-plugin/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], + "vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/cli/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/cli/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], + "vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/data-prefetch/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/dts-plugin/@module-federation/third-party-dts-extractor": ["@module-federation/third-party-dts-extractor@0.22.1", "", { "dependencies": { "find-pkg": "2.0.0", "fs-extra": "9.1.0", "resolve": "1.22.8" } }, "sha512-RhRNIZ9q1ifYW5IW8VAfvf1OnF0ME/uItJ2YWwEB0nsELX34eogvJTx0Y5l+aOhKpdIaCSP4RUUCK4zKzPQ4Yg=="], + "vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/dts-plugin/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/dts-plugin/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/managers/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], - "@module-federation/node/@module-federation/enhanced/@module-federation/runtime-tools/@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.22.1", "", { "dependencies": { "@module-federation/runtime": "0.22.1", "@module-federation/sdk": "0.22.1" } }, "sha512-+rJ91eJPCIlyDylIwekBxsO33S2AtuiUWdToA6tYFpOTAkTtBk1OW/PpQaLrOpw1Eny9EH8fOXqQMCvGvUbMXA=="], + "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], - "every-plugin/@module-federation/enhanced/@module-federation/bridge-react-webpack-plugin/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], + "webpack-dev-middleware/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], "every-plugin/@module-federation/enhanced/@module-federation/cli/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], diff --git a/host/README.md b/host/README.md index f9b2985..547cacc 100644 --- a/host/README.md +++ b/host/README.md @@ -1,127 +1,200 @@ # host -Server host for the application with authentication and Module Federation. +Server host with authentication and Module Federation. Orchestrates UI and API federation. ## Architecture -The host orchestrates two federation systems: +The host orchestrates both UI and API federation: -``` +```bash ┌─────────────────────────────────────────────────────────┐ │ host │ │ │ │ ┌────────────────────────────────────────────────┐ │ -│ │ server.ts │ │ +│ │ src/program.ts │ │ │ │ Hono.js + oRPC handlers │ │ │ └────────────────────────────────────────────────┘ │ │ ↑ ↑ │ +│ │ bos.config.json │ │ +│ │ (single source) │ │ │ ┌────────┴────────┐ ┌────────┴────────┐ │ -│ │ bos.config.json │ │ bos.config.json │ │ │ │ UI Federation │ │ API Plugins │ │ +│ │ (remoteEntry) │ │ (every-plugin) │ │ │ └────────┬────────┘ └────────┬────────┘ │ │ ↓ ↓ │ │ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ Module Fed │ │ every-plugin │ │ -│ │ runtime │ │ runtime │ │ -│ └─────────────────┘ └─────────────────┘ │ -│ ↓ ↓ │ -│ ┌─────────────────┐ ┌─────────────────┐ │ │ │ React app │ │ oRPC router │ │ │ │ (SSR/CSR) │ │ (merged) │ │ │ └─────────────────┘ └─────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` +## Directory Structure + +``` +host/ +├── server.ts # Entry point +├── bootstrap.ts # Remote host loader +├── src/ +│ ├── program.ts # Main server program +│ ├── ui.tsx # UI rendering +│ ├── types.ts # Type definitions +│ ├── db/ +│ │ └── schema/ +│ │ └── auth.ts # Auth schema +│ ├── layers/ +│ │ └── index.ts # Effect layers composition +│ ├── lib/ +│ │ └── schemas.ts # Shared schemas +│ ├── services/ +│ │ ├── auth.ts # Better-Auth setup +│ │ ├── config.ts # Runtime config loader +│ │ ├── context.ts # Request context +│ │ ├── database.ts # Database connection +│ │ ├── errors.ts # Error types +│ │ ├── federation.server.ts # UI module loading +│ │ ├── plugins.ts # API plugin loading +│ │ └── router.ts # Router creation +│ └── utils/ +│ └── logger.ts # Logging utility +├── migrations/ # Drizzle migrations +├── drizzle.config.ts # Drizzle config +└── package.json +``` + ## Configuration -All runtime configuration is in `bos.config.json` at the project root: +All configuration from `bos.config.json`: ```json { - "account": "agency.near", + "account": "example.near", "app": { "host": { - "title": "agent", - "development": "http://localhost:3001", - "production": "https://" + "title": "App Title", + "description": "App description", + "development": "http://localhost:3000", + "production": "https://example.com", + "secrets": ["HOST_DATABASE_URL", "HOST_DATABASE_AUTH_TOKEN", "BETTER_AUTH_SECRET", "BETTER_AUTH_URL"] }, "ui": { "name": "ui", "development": "http://localhost:3002", - "production": "https://", - "exposes": { - "App": "./App", - "components": "./components", - "providers": "./providers", - "types": "./types" - } + "production": "https://cdn.example.com/ui", + "ssr": "https://cdn.example.com/ui-ssr" }, "api": { "name": "api", "development": "http://localhost:3014", - "production": "https://", - "variables": { - "NEAR_AI_MODEL": "deepseek-ai/DeepSeek-V3.1" - }, - "secrets": [ - "API_DATABASE_URL", - "API_DATABASE_AUTH_TOKEN", - "NEAR_AI_API_KEY", - "NEAR_AI_BASE_URL" - ] + "production": "https://cdn.example.com/api", + "secrets": ["API_DATABASE_URL", "API_DATABASE_AUTH_TOKEN", "NEAR_AI_API_KEY"] } } } ``` -**Router Composition** (`routers/index.ts`): +**Environment Variables:** -```typescript -return { - ...baseRouter, // /health, /status - ...plugins.api.router, // plugin routes -} +| Variable | Description | Default | +|----------|-------------|---------| +| `UI_SOURCE` | `local` or `remote` | Based on NODE_ENV | +| `API_SOURCE` | `local` or `remote` | Based on NODE_ENV | +| `API_PROXY` | Proxy API requests to another host URL | - | +| `HOST_DATABASE_URL` | SQLite database URL for auth | `file:./database.db` | +| `HOST_DATABASE_AUTH_TOKEN` | Auth token for remote database | - | +| `BETTER_AUTH_SECRET` | Secret for session encryption | - | +| `BETTER_AUTH_URL` | Base URL for auth endpoints | - | +| `CORS_ORIGIN` | Comma-separated allowed origins | Host + UI URLs | + +### Proxy Mode + +Set `API_PROXY=true` or `API_PROXY=` to proxy all `/api/*` requests to another host instead of loading the API plugin locally. Useful for: + +- Development against production API +- Staging environments +- Testing without running the API server + +```bash +API_PROXY=https://production.example.com bun dev ``` ## Tech Stack - **Server**: Hono.js + @hono/node-server - **API**: oRPC (RPC + OpenAPI) -- **Auth**: Better-Auth + better-near-auth +- **Auth**: Better-Auth + better-near-auth (SIWN) - **Database**: SQLite (libsql) + Drizzle ORM - **Build**: Rsbuild + Module Federation - **Plugins**: every-plugin runtime +- **Effects**: Effect-TS for service composition ## Available Scripts -- `bun dev` - Start dev server (Host: 3001, UI: 3002, API: 3014) -- `bun build` - Build for production -- `bun preview` - Run production server +- `bun dev` - Start dev server (port 3000) +- `bun build` - Build MF bundle for production (outputs `remoteEntry.js`) +- `bun bootstrap` - Run host from remote MF URL (requires `HOST_REMOTE_URL`) +- `bun preview` - Run production server locally +- `bun test` - Run tests +- `bun typecheck` - Type checking - `bun db:migrate` - Run migrations +- `bun db:push` - Push schema changes +- `bun db:generate` - Generate migrations - `bun db:studio` - Open Drizzle Studio -## API Routes +## Remote Host Mode -- `/api/auth/*` - Authentication endpoints (Better-Auth) -- `/api/rpc/*` - RPC endpoint (batching supported) -- `/api/*` - REST API (OpenAPI spec) -- `/health` - Health check +The host can be deployed as a Module Federation remote and loaded dynamically at runtime: -## Adding New Plugins +### Building & Deploying -1. Add plugin to `bos.config.json`: -```json -{ - "app": { - "new-plugin": { - "name": "new-plugin", - "development": "http://localhost:3015", - "production": "https://cdn.example.com/plugin/remoteEntry.js", - "variables": {}, - "secrets": [] - } - } -} +```bash +# Build the MF bundle (deploys to Zephyr, updates bos.config.json) +cd host +bun build +``` + +This produces `dist/remoteEntry.js` and deploys to Zephyr. The Zephyr URL is saved to `bos.config.json → app.host.remote`. + +### Production Deployment (Railway/Docker) + +Use the bootstrap script to run the host from a remote URL: + +```bash +# Set the remote URL +export HOST_REMOTE_URL=https://your-zephyr-url.zephyrcloud.app + +# Run +bun bootstrap +``` + +**Dockerfile example:** +```dockerfile +FROM oven/bun:latest +WORKDIR /app +COPY package.json bun.lockb ./ +RUN bun install +COPY bootstrap.ts ./ +CMD ["bun", "bootstrap"] ``` -2. Plugin router is automatically merged in `routers/index.ts` +**Required Environment Variables:** +- `HOST_REMOTE_URL` - Zephyr URL of the deployed host bundle +- `HOST_DATABASE_URL` - Database connection string +- `BETTER_AUTH_SECRET` - Auth encryption secret +- `BETTER_AUTH_URL` - Base URL for auth endpoints + +### Benefits + +1. **No local host code needed** - Just reference the remote URL +2. **Instant updates** - Deploy new bundle, containers pick it up on restart +3. **Version flexibility** - Pin to specific Zephyr URLs for stability +4. **Same binary everywhere** - Bootstrap script is tiny, all logic lives in the bundle + +## API Routes + +| Route | Description | +|-------|-------------| +| `/health` | Health check | +| `/api/auth/*` | Authentication endpoints (Better-Auth) | +| `/api/rpc/*` | RPC endpoint (batching supported) | +| `/api/*` | REST API (OpenAPI spec at `/api`) | diff --git a/host/bootstrap.ts b/host/bootstrap.ts new file mode 100644 index 0000000..ec35bab --- /dev/null +++ b/host/bootstrap.ts @@ -0,0 +1,81 @@ +#!/usr/bin/env bun +import "dotenv/config"; +import { createInstance, getInstance } from "@module-federation/enhanced/runtime"; +import { setGlobalFederationInstance } from "@module-federation/runtime-core"; + +interface ServerHandle { + ready: Promise; + shutdown: () => Promise; +} + +function getRemoteUrl(): string { + const url = process.env.HOST_REMOTE_URL; + if (!url) { + console.error("❌ HOST_REMOTE_URL environment variable is required"); + console.error(" Set it to the Zephyr URL of your deployed host bundle"); + process.exit(1); + } + return url; +} + +async function bootstrap() { + const remoteUrl = getRemoteUrl(); + + console.log("🚀 Bootstrapping host from remote..."); + console.log(` Remote URL: ${remoteUrl}`); + + let serverHandle: ServerHandle | null = null; + + const shutdown = async () => { + console.log("\n[Bootstrap] Shutting down..."); + if (serverHandle) { + await serverHandle.shutdown(); + } + process.exit(0); + }; + + process.on("SIGINT", () => void shutdown()); + process.on("SIGTERM", () => void shutdown()); + + try { + let mf = getInstance(); + if (!mf) { + mf = createInstance({ + name: "bootstrap-host", + remotes: [], + }); + setGlobalFederationInstance(mf); + } + + const remoteEntryUrl = remoteUrl.endsWith("/remoteEntry.js") + ? remoteUrl + : `${remoteUrl}/remoteEntry.js`; + + console.log(` Loading: ${remoteEntryUrl}`); + + mf.registerRemotes([{ + name: "host", + entry: remoteEntryUrl, + }]); + + console.log(" Loading host/Server module..."); + const hostModule = await mf.loadRemote<{ runServer: () => ServerHandle }>("host/Server"); + + if (!hostModule?.runServer) { + throw new Error("Host module does not export runServer function"); + } + + console.log(" Starting server..."); + serverHandle = hostModule.runServer(); + + await serverHandle.ready; + console.log("✅ Server ready"); + + await new Promise(() => {}); + } catch (error) { + console.error("❌ Failed to bootstrap host:", error); + process.exit(1); + } +} + +bootstrap(); diff --git a/host/index.html b/host/index.html deleted file mode 100644 index 06ead7a..0000000 --- a/host/index.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - -
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- - diff --git a/host/package.json b/host/package.json index e4eaa45..ad13398 100644 --- a/host/package.json +++ b/host/package.json @@ -1,52 +1,58 @@ { "name": "host", + "version": "1.0.0", "private": true, "type": "module", "scripts": { "dev": "BOS_CONFIG_PATH=../bos.config.json tsx server.ts", - "build": "rsbuild build", + "build": "NODE_ENV=production rsbuild build", + "bootstrap": "tsx bootstrap.ts", "preview": "NODE_ENV=production BOS_CONFIG_PATH=../bos.config.json tsx server.ts", + "test": "NODE_ENV=production BOS_CONFIG_PATH=../bos.config.json vitest run", + "test:watch": "NODE_ENV=production BOS_CONFIG_PATH=../bos.config.json vitest", "typecheck": "tsc --noEmit", "db:push": "drizzle-kit push", "db:studio": "drizzle-kit studio", "db:generate": "drizzle-kit generate", - "db:migrate": "drizzle-kit migrate", - "promote-admin": "tsx src/scripts/promote-admin.ts" + "db:migrate": "drizzle-kit migrate" }, "dependencies": { + "effect": "catalog:", "@hono/node-server": "^1.19.9", "@hot-labs/near-connect": "^0.8.2", - "@libsql/client": "^0.15.15", - "@module-federation/enhanced": "^0.21.6", - "@module-federation/node": "^2.7.27", - "@module-federation/rsbuild-plugin": "^0.21.6", - "@module-federation/runtime": "^0.21.6", - "@module-federation/runtime-core": "^0.21.6", + "@libsql/client": "^0.17.0", + "@module-federation/enhanced": "^0.23.0", + "@module-federation/node": "^2.7.28", + "@module-federation/runtime-core": "^0.23.0", "@orpc/openapi": "^1.13.4", "@orpc/server": "^1.13.4", "@orpc/zod": "^1.13.4", "@t3-oss/env-core": "^0.13.10", - "@tanstack/react-query": "^5.90.19", - "@tanstack/react-router": "^1.151.1", - "better-auth": "^1.4.14", - "better-near-auth": "^0.3.4", + "@tanstack/react-query": "catalog:", + "@tanstack/react-router": "catalog:", + "better-auth": "catalog:", + "better-near-auth": "catalog:", "dotenv": "^17.2.3", "drizzle-kit": "^0.31.8", "drizzle-orm": "^0.45.1", - "every-plugin": "^0.8.8", - "hono": "^4.11.4", - "near-kit": "^0.6.3", - "react": "^19.2.3", - "react-dom": "^19.2.3" + "every-plugin": "catalog:", + "hono": "^4.11.6", + "near-kit": "catalog:", + "react": "^19.2.4", + "react-dom": "^19.2.4" }, "devDependencies": { + "@module-federation/rsbuild-plugin": "^0.23.0", "@rsbuild/core": "^1.7.2", "@rsbuild/plugin-react": "^1.4.3", - "@types/node": "^22.19.7", - "@types/react": "^19.2.8", + "@types/node": "^25.0.10", + "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "tsx": "^4.21.0", - "typescript": "^5.9.3", - "zephyr-rsbuild-plugin": "^0.1.4" + "typescript": "catalog:", + "vite-tsconfig-paths": "^6.0.5", + "vitest": "^4.0.18", + "web-vitals": "^5.1.0", + "zephyr-rsbuild-plugin": "^0.1.8" } } diff --git a/host/rsbuild.config.ts b/host/rsbuild.config.ts index 90e08d1..f7952fd 100644 --- a/host/rsbuild.config.ts +++ b/host/rsbuild.config.ts @@ -1,43 +1,22 @@ import fs from "node:fs"; import path from "node:path"; -import { pluginModuleFederation } from "@module-federation/rsbuild-plugin"; +import { ModuleFederationPlugin } from "@module-federation/enhanced/rspack"; import { defineConfig } from "@rsbuild/core"; import { pluginReact } from "@rsbuild/plugin-react"; import { withZephyr } from "zephyr-rsbuild-plugin"; -import pkg from "./package.json"; const __dirname = import.meta.dirname; const isProduction = process.env.NODE_ENV === "production"; -const useRemoteUi = process.env.USE_REMOTE_UI === "true"; const configPath = process.env.BOS_CONFIG_PATH ?? path.resolve(__dirname, "../bos.config.json"); -const bosConfig = JSON.parse(fs.readFileSync(configPath, "utf8")); -const env = isProduction ? "production" : "development"; -const uiUrl = useRemoteUi ? bosConfig.app.ui.production : bosConfig.app.ui[env]; - -function getClientRuntimeConfig() { - return { - env, - title: bosConfig.app.host.title, - hostUrl: bosConfig.app.host[env], - ui: { - name: bosConfig.app.ui.name, - url: uiUrl, - exposes: bosConfig.app.ui.exposes, - }, - apiBase: "/api", - rpcBase: "/api/rpc", - }; -} - -function updateBosConfig(hostUrl: string) { +function updateBosConfig(field: "production" | "remote", url: string) { try { const config = JSON.parse(fs.readFileSync(configPath, "utf8")); - config.app.host.production = hostUrl; - fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n"); - console.log(" ✅ Updated bos.config.json"); + config.app.host[field] = url; + fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`); + console.log(` ✅ Updated bos.config.json: app.host.${field}`); } catch (err) { console.error( " ❌ Failed to update bos.config.json:", @@ -46,46 +25,7 @@ function updateBosConfig(hostUrl: string) { } } -const plugins = [ - pluginReact(), - pluginModuleFederation({ - name: "host", - remotes: {}, - dts: false, - shared: { - react: { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies.react, - }, - "react-dom": { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies["react-dom"], - }, - "@tanstack/react-query": { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies["@tanstack/react-query"], - }, - "@tanstack/react-router": { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies["@tanstack/react-router"], - }, - "@hot-labs/near-connect": { - singleton: true, - eager: false, - requiredVersion: pkg.dependencies["@hot-labs/near-connect"], - }, - "near-kit": { - singleton: true, - eager: false, - requiredVersion: pkg.dependencies["near-kit"], - }, - }, - }), -]; +const plugins = [pluginReact()]; if (isProduction) { plugins.push( @@ -93,7 +33,7 @@ if (isProduction) { hooks: { onDeployComplete: (info: { url: string }) => { console.log("🚀 Host Deployed:", info.url); - updateBosConfig(info.url); + updateBosConfig("remote", info.url); }, }, }) @@ -103,82 +43,59 @@ if (isProduction) { export default defineConfig({ plugins, source: { - define: { - "process.env.NODE_ENV": JSON.stringify( - process.env.NODE_ENV || "development" - ), - "process.env.USE_REMOTE_API": JSON.stringify( - process.env.USE_REMOTE_API || "false" - ), - "process.env.USE_REMOTE_UI": JSON.stringify( - process.env.USE_REMOTE_UI || "false" - ), - "process.env.PUBLIC_ACCOUNT_ID": JSON.stringify(bosConfig.account), - "process.env.BETTER_AUTH_URL": JSON.stringify( - process.env.BETTER_AUTH_URL || - bosConfig.app.host[process.env.NODE_ENV || "development"] - ), - }, entry: { - index: "./src/index.client.tsx", + index: "./src/program.ts", }, }, - html: { - template: "./index.html", - title: bosConfig.app.host.title, - templateParameters: { - title: bosConfig.app.host.title, - description: bosConfig.app.host.description, + resolve: { + alias: { + "@": "./src", }, - inject: "body", - scriptLoading: "defer", - tags: [ - { - tag: "script", - attrs: {}, - children: `window.__RUNTIME_CONFIG__=${JSON.stringify( - getClientRuntimeConfig() - )};`, - head: true, - append: false, - }, - { - tag: "link", - attrs: { - rel: "preload", - href: `${uiUrl}/remoteEntry.js`, - as: "script", - }, - head: true, - append: true, - }, - ], }, dev: { progressBar: false, - client: { - overlay: false, - }, - }, - server: { - port: 3001, - proxy: { - "/api": "http://localhost:3000", - }, - historyApiFallback: true, }, tools: { rspack: { + target: "async-node", + optimization: { + nodeEnv: false, + }, + output: { + uniqueName: "host", + library: { type: "commonjs-module" }, + }, + externals: [ + /^node:/, + /^bun:/, + "@libsql/client", + ], infrastructureLogging: { level: "error", }, stats: "errors-warnings", + plugins: [ + new ModuleFederationPlugin({ + name: "host", + filename: "remoteEntry.js", + dts: false, + runtimePlugins: [require.resolve("@module-federation/node/runtimePlugin")], + library: { type: "commonjs-module" }, + exposes: { + "./Server": "./src/program.ts", + }, + }), + ], }, }, output: { + minify: false, distPath: { root: "dist", }, assetPrefix: "/", + filename: { + js: "[name].js", + }, }, }); diff --git a/host/server.ts b/host/server.ts index 2bf8561..1b204f8 100644 --- a/host/server.ts +++ b/host/server.ts @@ -1,313 +1,4 @@ -import { serve } from '@hono/node-server'; -import { serveStatic } from '@hono/node-server/serve-static'; -import { OpenAPIHandler } from '@orpc/openapi/fetch'; -import { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'; -import { onError } from '@orpc/server'; -import { RPCHandler } from '@orpc/server/fetch'; -import { BatchHandlerPlugin } from '@orpc/server/plugins'; -import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'; -import { createRsbuild, logger } from '@rsbuild/core'; -import 'dotenv/config'; -import { eq } from 'drizzle-orm'; -import { formatORPCError } from 'every-plugin/errors'; -import { Hono } from 'hono'; -import { cors } from 'hono/cors'; -import { randomBytes } from 'node:crypto'; -import { readFile } from 'node:fs/promises'; -import { resolve } from 'node:path'; -import { z } from 'every-plugin/zod'; -import config from './rsbuild.config'; -import { loadBosConfig, type RuntimeConfig } from './src/config'; -import { db } from './src/db'; -import * as schema from './src/db/schema/auth'; -import { initializeServerFederation } from './src/federation.server'; -import { initializeServerApiClient } from './src/lib/api-client.server'; -import { auth } from './src/lib/auth'; -import { createRouter } from './src/routers'; -import { initializePlugins } from './src/runtime'; -import { renderToStream, createSSRHtml } from './src/ssr'; -import { rateLimitChat, rateLimitKV, rateLimitAuth } from './src/middleware/rate-limit'; +import "dotenv/config"; +import { runServer } from "./src/program"; -const envSchema = z.object({ - BETTER_AUTH_SECRET: z.string().min(32, "BETTER_AUTH_SECRET must be at least 32 characters"), - BETTER_AUTH_URL: z.string().url("BETTER_AUTH_URL must be a valid URL"), - HOST_DATABASE_URL: z.string().min(1, "HOST_DATABASE_URL is required"), - CORS_ORIGIN: z.string().optional(), -}); - -function ensureDevSecrets() { - const isDev = process.env.NODE_ENV !== 'production'; - - if (!process.env.BETTER_AUTH_SECRET && isDev) { - const generated = randomBytes(32).toString('hex'); - process.env.BETTER_AUTH_SECRET = generated; - logger.warn('[Auth] ⚠️ Generated temporary BETTER_AUTH_SECRET for development'); - logger.warn(` For persistence, add to host/.env:`); - logger.warn(` BETTER_AUTH_SECRET=${generated}`); - } -} - -function validateEnv() { - const result = envSchema.safeParse(process.env); - if (!result.success) { - logger.error("❌ Invalid environment variables:"); - result.error.issues.forEach((issue) => { - logger.error(` ${issue.path.join(".")}: ${issue.message}`); - }); - logger.error("\nCheck your .env file against .env.example"); - process.exit(1); - } - logger.info("✅ Environment variables validated"); -} - -function injectRuntimeConfig(html: string, config: RuntimeConfig): string { - const clientConfig = { - env: config.env, - title: config.title, - hostUrl: config.hostUrl, - ui: config.ui, - apiBase: '/api', - rpcBase: '/api/rpc', - }; - const configScript = ``; - const preloadLink = ``; - - return html - .replace('', configScript) - .replace('', preloadLink); -} - -async function createContext(req: Request) { - const session = await auth.api.getSession({ headers: req.headers }); - - // Get NEAR account ID from linked accounts - let nearAccountId: string | null = null; - if (session?.user?.id) { - const nearAccount = await db.query.nearAccount.findFirst({ - where: eq(schema.nearAccount.userId, session.user.id), - }); - nearAccountId = nearAccount?.accountId ?? null; - } - - // Extract role from user - const role = (session?.user as { role?: string })?.role ?? null; - - return { - session, - user: session?.user, - nearAccountId, - role, - }; -} - -async function startServer() { - ensureDevSecrets(); - validateEnv(); - - const port = Number(process.env.PORT) || 3001; - const apiPort = Number(process.env.API_PORT) || 3000; - const isDev = process.env.NODE_ENV !== 'production'; - - const bosConfig = await loadBosConfig(); - const plugins = await initializePlugins(); - const router = createRouter(plugins); - - initializeServerApiClient(router); - - // Setup graceful shutdown handlers - const shutdown = async () => { - console.log('[Plugins] Shutting down plugin runtime...'); - if (plugins.runtime) { - await plugins.runtime.shutdown(); - } - process.exit(0); - }; - - process.on('SIGINT', shutdown); - process.on('SIGTERM', shutdown); - - const rpcHandler = new RPCHandler(router, { - plugins: [new BatchHandlerPlugin()], - interceptors: [onError((error) => formatORPCError(error))], - }); - - const apiHandler = new OpenAPIHandler(router, { - plugins: [ - new OpenAPIReferencePlugin({ - schemaConverters: [new ZodToJsonSchemaConverter()], - specGenerateOptions: { - info: { - title: bosConfig.title, - version: '1.0.0', - }, - servers: [{ url: `${bosConfig.hostUrl}/api` }], - }, - }), - ], - interceptors: [onError((error) => formatORPCError(error))], - }); - - const apiApp = new Hono(); - - // Configure CORS origins - const corsOrigins = process.env.CORS_ORIGIN?.split(',').map((o) => o.trim()) - ?? [bosConfig.hostUrl, bosConfig.ui.url]; - - if (!process.env.CORS_ORIGIN && isDev === false) { - logger.warn('[CORS] ⚠️ CORS_ORIGIN not set. Using bos.config.json defaults. Set explicitly for production.'); - } - - apiApp.use( - '/*', - cors({ - origin: corsOrigins, - credentials: true, - }) - ); - - apiApp.get('/health', (c) => c.text('OK')); - - apiApp.get('/health/ready', async (c) => { - const checks: Record = { - database: false, - ai: false, - }; - - // Check database connectivity - try { - await db.query.user.findFirst(); - checks.database = true; - } catch (error) { - console.error('[Health] Database check failed:', error); - checks.database = false; - } - - // Check AI service availability (optional dependency) - checks.ai = plugins?.status?.available ?? false; - - // Ready if database is connected (AI is optional) - const ready = checks.database; - - return c.json( - { - status: ready ? 'ready' : 'degraded', - checks, - timestamp: new Date().toISOString(), - }, - ready ? 200 : 503 - ); - }); - - apiApp.on(['POST', 'GET'], '/api/auth/*', rateLimitAuth, (c) => auth.handler(c.req.raw)); - - // Apply rate limiting to chat endpoints - apiApp.use('/api/chat', rateLimitChat); - apiApp.use('/api/chat/*', rateLimitChat); - - // Apply rate limiting to KV endpoints - apiApp.use('/api/kv', rateLimitKV); - apiApp.use('/api/kv/*', rateLimitKV); - - apiApp.all('/api/rpc/*', async (c) => { - const req = c.req.raw; - const context = await createContext(req); - - const result = await rpcHandler.handle(req, { - prefix: '/api/rpc', - context, - }); - - return result.response - ? c.newResponse(result.response.body, result.response) - : c.text('Not Found', 404); - }); - - apiApp.all('/api/*', async (c) => { - const req = c.req.raw; - const context = await createContext(req); - - const result = await apiHandler.handle(req, { - prefix: '/api', - context, - }); - - return result.response - ? c.newResponse(result.response.body, result.response) - : c.text('Not Found', 404); - }); - - if (isDev) { - serve({ fetch: apiApp.fetch, port: apiPort }, (info) => { - logger.info(`API server running at http://localhost:${info.port}`); - logger.info( - ` http://localhost:${info.port}/api → REST API (OpenAPI docs)` - ); - logger.info(` http://localhost:${info.port}/api/rpc → RPC endpoint`); - }); - - const rsbuild = await createRsbuild({ - cwd: import.meta.dirname, - rsbuildConfig: config, - }); - - await rsbuild.startDevServer(); - } else { - const ssrEnabled = process.env.DISABLE_SSR !== 'true'; - const indexHtml = await readFile(resolve(import.meta.dirname, './dist/index.html'), 'utf-8'); - const injectedHtml = injectRuntimeConfig(indexHtml, bosConfig); - - if (ssrEnabled) { - initializeServerFederation(bosConfig); - } - - apiApp.use('/*', serveStatic({ root: './dist' })); - - apiApp.get('*', async (c) => { - if (ssrEnabled) { - try { - const url = new URL(c.req.url).pathname + new URL(c.req.url).search; - const { stream, dehydratedState, headData } = await renderToStream({ - url, - config: bosConfig, - }); - - const decoder = new TextDecoder(); - let bodyContent = ''; - const reader = stream.getReader(); - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - bodyContent += decoder.decode(value, { stream: true }); - } - bodyContent += decoder.decode(); - - const html = createSSRHtml(bodyContent, dehydratedState, bosConfig, headData); - return c.html(html); - } catch (error) { - logger.error('[SSR] Render failed, falling back to CSR:', error); - return c.html(injectedHtml); - } - } - - return c.html(injectedHtml); - }); - - serve({ fetch: apiApp.fetch, port }, (info) => { - logger.info( - `Host production server running at http://localhost:${info.port}` - ); - logger.info( - ` http://localhost:${info.port}/api → REST API (OpenAPI docs)` - ); - logger.info(` http://localhost:${info.port}/api/rpc → RPC endpoint`); - logger.info(` SSR: ${ssrEnabled ? 'Enabled' : 'Disabled'}`); - }); - } -} - -startServer().catch((err) => { - logger.error('Failed to start server'); - logger.error(err); - process.exit(1); -}); +runServer(); diff --git a/host/src/components.tsx b/host/src/components.tsx deleted file mode 100644 index 72024c8..0000000 --- a/host/src/components.tsx +++ /dev/null @@ -1,365 +0,0 @@ -import { loadRemote } from "@module-federation/runtime"; -import { - Suspense, - lazy, - useEffect, - useMemo, - useState, - type CSSProperties, - type ComponentType, - type FC, -} from "react"; -import { getRuntimeConfig } from "./federation"; -import { ErrorBoundary, Loading } from "./ui"; - -interface RegistryItem { - name: string; - type: string; - title: string; - description: string; - registryDependencies?: string[]; - files: { path: string; type: string }[]; - meta?: { - defaultProps?: Record; - }; -} - -interface Registry { - $schema: string; - name: string; - homepage: string; - items: RegistryItem[]; -} - -const Providers = lazy(async () => { - const config = getRuntimeConfig(); - const module = await loadRemote<{ - default: FC<{ children: React.ReactNode }>; - }>(`${config.ui.name}/providers`); - if (!module) throw new Error(`Failed to load ${config.ui.name}/providers`); - return module; -}); - -const cardContainerStyle: CSSProperties = { - background: "#fff", - borderRadius: "12px", - border: "1px solid #e5e7eb", - overflow: "hidden", - display: "flex", - flexDirection: "column", -}; - -const cardHeaderStyle: CSSProperties = { - padding: "12px 16px", - borderBottom: "1px solid #e5e7eb", - background: "#fafafa", - display: "flex", - alignItems: "center", - justifyContent: "space-between", -}; - -const cardTitleStyle: CSSProperties = { - fontSize: "13px", - fontWeight: 600, - color: "#374151", - fontFamily: - "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace", -}; - -const previewContainerStyle: CSSProperties = { - padding: "24px", - display: "flex", - alignItems: "center", - justifyContent: "center", - minHeight: "120px", - background: "linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%)", -}; - -const propsToggleStyle: CSSProperties = { - fontSize: "11px", - color: "#6b7280", - cursor: "pointer", - display: "flex", - alignItems: "center", - gap: "4px", - padding: "4px 8px", - borderRadius: "4px", - border: "none", - background: "transparent", -}; - -const propsContainerStyle: CSSProperties = { - borderTop: "1px solid #e5e7eb", - background: "#f9fafb", - padding: "12px 16px", - fontSize: "11px", - fontFamily: - "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace", - color: "#6b7280", - overflow: "auto", - maxHeight: "120px", -}; - -const inlineLoaderStyle: CSSProperties = { - display: "flex", - alignItems: "center", - gap: "8px", - color: "#9ca3af", - fontSize: "12px", -}; - -const errorBadgeStyle: CSSProperties = { - fontSize: "11px", - color: "#dc2626", - background: "#fef2f2", - padding: "4px 8px", - borderRadius: "4px", -}; - -interface ComponentCardProps { - name: string; - title: string; - description: string; - Component: ComponentType>; - props: Record; - index: number; -} - -const ComponentCard: FC = ({ title, Component, props }) => { - const [showProps, setShowProps] = useState(false); - const hasProps = Object.keys(props).length > 0; - - return ( -
-
- {`<${title} />`} - {hasProps && ( - - )} -
-
- Failed to load} - > - - Loading... -
- } - > - - - -
- {hasProps && showProps && ( -
-
-            {JSON.stringify(props, null, 2)}
-          
-
- )} - - ); -}; - -const pageContainerStyle: CSSProperties = { - display: "flex", - flexDirection: "column", - height: "100vh", - width: "100vw", - overflow: "hidden", - background: "#f3f4f6", -}; - -const scrollContainerStyle: CSSProperties = { - flex: 1, - overflow: "auto", - padding: "clamp(16px, 4vw, 32px)", -}; - -const contentWrapperStyle: CSSProperties = { - maxWidth: "1200px", - margin: "0 auto", -}; - -const headerStyle: CSSProperties = { - marginBottom: "clamp(24px, 4vw, 40px)", -}; - -const titleStyle: CSSProperties = { - fontSize: "clamp(20px, 4vw, 28px)", - fontWeight: 600, - color: "#111827", - margin: 0, -}; - -const subtitleStyle: CSSProperties = { - fontSize: "clamp(13px, 2vw, 15px)", - color: "#6b7280", - marginTop: "8px", -}; - -const codeStyle: CSSProperties = { - background: "#e5e7eb", - padding: "2px 6px", - borderRadius: "4px", - fontFamily: - "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace", - fontSize: "0.9em", -}; - -const gridStyle: CSSProperties = { - display: "grid", - gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))", - gap: "clamp(16px, 3vw, 24px)", -}; - -const createLazyComponent = (componentName: string) => { - return lazy(async () => { - const config = getRuntimeConfig(); - const module = await loadRemote< - Record>> - >(`${config.ui.name}/components`); - if (!module || !module[componentName]) { - throw new Error( - `Component ${componentName} not found in ${config.ui.name}/components` - ); - } - return { default: module[componentName] }; - }); -}; - -export const Components: FC = () => { - const [ready, setReady] = useState(false); - const [registry, setRegistry] = useState(null); - const [registryError, setRegistryError] = useState(null); - const [config, setConfig] = useState | null>(null); - - useEffect(() => { - const timer = setTimeout(() => setReady(true), 50); - return () => clearTimeout(timer); - }, []); - - useEffect(() => { - setConfig(getRuntimeConfig()); - }, []); - - useEffect(() => { - const fetchRegistry = async () => { - if (!config) return; - - try { - const remoteUrl = config.ui.url; - const baseUrl = remoteUrl.replace(/\/remoteEntry\.js$/, ""); - const registryUrl = `${baseUrl}/r/registry.json`; - - const response = await fetch(registryUrl); - if (!response.ok) - throw new Error(`Failed to fetch registry: ${response.status}`); - const data = await response.json(); - setRegistry(data); - } catch (err) { - console.error("Failed to load registry:", err); - setRegistryError(err instanceof Error ? err.message : "Unknown error"); - } - }; - - fetchRegistry(); - }, [config]); - - const componentEntries = useMemo(() => { - if (!registry) return []; - return registry.items.map((item) => ({ - name: item.name, - title: item.title, - description: item.description, - Component: createLazyComponent(item.title), - defaultProps: item.meta?.defaultProps || {}, - })); - }, [registry]); - - const wrapperAnimation: CSSProperties = { - opacity: ready ? 1 : 0, - transition: "opacity 300ms ease-out", - }; - - return ( -
- - - }> - -
-
-
-

Component Gallery

-

- Remote components from{" "} - - {config?.ui.name || "Loading..."} - -

-
- - {registryError && ( -
- Failed to load registry: {registryError} -
- )} - - {!registry && !registryError && ( -
- Loading component registry... -
- )} - -
- {componentEntries.map((entry, index) => ( - - ))} -
-
-
-
-
-
-
- ); -}; - -export default Components; diff --git a/host/src/config.ts b/host/src/config.ts deleted file mode 100644 index 979c4ad..0000000 --- a/host/src/config.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { readFile } from 'node:fs/promises'; -import { resolve } from 'node:path'; - -interface BosConfig { - account: string; - app: { - host: { - title: string; - development: string; - production: string; - }; - ui: { - name: string; - development: string; - production: string; - exposes: Record; - }; - api: { - name: string; - development: string; - production: string; - variables?: RuntimeVariables; - secrets?: string[]; - }; - }; -} - -type RuntimeVariables = Record; - -export interface RuntimeConfig { - env: 'development' | 'production'; - account: string; - title: string; - hostUrl: string; - ui: { - name: string; - url: string; - exposes: Record; - }; - api: { - name: string; - url: string; - variables?: RuntimeVariables; - secrets?: string[]; - }; -} - -export async function loadBosConfig(): Promise { - const env = (process.env.NODE_ENV as 'development' | 'production') || 'development'; - - const path = process.env.BOS_CONFIG_PATH ?? resolve(process.cwd(), 'bos.config.json'); - - const raw = await readFile(path, 'utf8'); - const config = JSON.parse(raw) as BosConfig; - - const useRemoteApi = process.env.USE_REMOTE_API === 'true'; - const useRemoteUi = process.env.USE_REMOTE_UI === 'true'; - - const api: RuntimeConfig['api'] = { - name: config.app.api.name, - url: useRemoteApi ? config.app.api.production : config.app.api[env], - variables: config.app.api.variables, - secrets: config.app.api.secrets, - }; - - return { - env, - account: config.account, - title: config.app.host.title, - hostUrl: config.app.host[env], - ui: { - name: config.app.ui.name, - url: useRemoteUi ? config.app.ui.production : config.app.ui[env], - exposes: config.app.ui.exposes, - }, - api, - }; -} diff --git a/host/src/db/index.ts b/host/src/db/index.ts deleted file mode 100644 index b20169e..0000000 --- a/host/src/db/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { drizzle } from 'drizzle-orm/libsql'; -import { createClient } from '@libsql/client'; -import * as authSchema from './schema/auth'; - -const client = createClient({ - url: process.env.HOST_DATABASE_URL || 'file:./database.db', - authToken: process.env.HOST_DATABASE_AUTH_TOKEN, -}); - -export const db = drizzle(client, { - schema: { - ...authSchema, - }, -}); diff --git a/host/src/federation.server.ts b/host/src/federation.server.ts deleted file mode 100644 index 27770d3..0000000 --- a/host/src/federation.server.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { createInstance } from '@module-federation/enhanced/runtime'; -import type { RuntimeConfig } from './config'; - -let mfInstance: ReturnType | null = null; - -export function getServerFederationInstance() { - return mfInstance; -} - -export function initializeServerFederation(config: RuntimeConfig) { - if (mfInstance) { - console.log('[Federation Server] Using existing instance'); - return mfInstance; - } - - mfInstance = createInstance({ - name: 'host_ssr', - remotes: [ - { - name: config.ui.name, - entry: `${config.ui.url}/remoteEntry.js`, - alias: config.ui.name, - }, - ], - }); - - console.log('[Federation Server] Created new instance with remote:', config.ui.name); - return mfInstance; -} - -export async function loadRemoteModule(remoteName: string, exposedModule: string): Promise { - if (!mfInstance) { - throw new Error('Server federation not initialized. Call initializeServerFederation first.'); - } - - const modulePath = `${remoteName}/${exposedModule}`; - const module = await mfInstance.loadRemote(modulePath); - - if (!module) { - throw new Error(`Failed to load remote module: ${modulePath}`); - } - - return module; -} diff --git a/host/src/federation.ts b/host/src/federation.ts deleted file mode 100644 index df690f7..0000000 --- a/host/src/federation.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { registerRemotes } from '@module-federation/enhanced/runtime'; - -interface RuntimeConfig { - env: 'development' | 'production'; - title: string; - hostUrl: string; - ui: { - name: string; - url: string; - exposes: Record; - }; - apiBase: string; - rpcBase: string; -} - -declare global { - interface Window { - __RUNTIME_CONFIG__?: RuntimeConfig; - } -} - -let runtimeConfig: RuntimeConfig | null = null; - -export function getRuntimeConfig(): RuntimeConfig { - if (!runtimeConfig) { - throw new Error('Runtime config not initialized. Ensure window.__RUNTIME_CONFIG__ is set.'); - } - return runtimeConfig; -} - -export async function initializeFederation() { - if (!window.__RUNTIME_CONFIG__) { - throw new Error('Runtime config not found. SSR should always inline __RUNTIME_CONFIG__.'); - } - - runtimeConfig = window.__RUNTIME_CONFIG__; - - console.log('[Federation] Registering dynamic remote:', { - name: runtimeConfig.ui.name, - entry: `${runtimeConfig.ui.url}/remoteEntry.js`, - alias: runtimeConfig.ui.name, - }); - - registerRemotes([ - { - name: runtimeConfig.ui.name, - entry: `${runtimeConfig.ui.url}/remoteEntry.js`, - alias: runtimeConfig.ui.name, - }, - ]); - - return runtimeConfig; -} diff --git a/host/src/index.client.tsx b/host/src/index.client.tsx deleted file mode 100644 index 49571cc..0000000 --- a/host/src/index.client.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { StrictMode } from 'react'; -import { createRoot } from 'react-dom/client'; -import { initializeFederation } from './federation'; - -const rootElement = document.getElementById('root'); - -if (!rootElement) { - throw new Error('Root element not found'); -} - -const pathname = window.location.pathname; - -// Initialize federation before rendering -initializeFederation().then(async () => { - const ComponentModule = pathname === '/components' - ? await import('./components') - : await import('./main'); - - const RootComponent = ComponentModule.default; - - createRoot(rootElement!).render( - - - - ); -}).catch((error) => { - console.error('Failed to initialize federation:', error); - document.body.innerHTML = '
Failed to initialize application. Check console for details.
'; -}); diff --git a/host/src/layers/index.ts b/host/src/layers/index.ts new file mode 100644 index 0000000..d63565a --- /dev/null +++ b/host/src/layers/index.ts @@ -0,0 +1,20 @@ +import { Layer } from "every-plugin/effect"; +import { AuthService } from "../services/auth"; +import { ConfigService } from "../services/config"; +import { DatabaseService } from "../services/database"; +import { FederationServerService } from "../services/federation.server"; +import { PluginsService } from "../services/plugins"; + +export const ConfigLive = ConfigService.Default; + +export const DatabaseLive = DatabaseService.Default; + +export const AuthLive = AuthService.Default; + +export const PluginsLive = PluginsService.Live; + +export const FederationServerLive = FederationServerService.Live; + +export const CoreLive = Layer.mergeAll(ConfigLive, DatabaseLive, AuthLive); + +export const FullServerLive = Layer.mergeAll(CoreLive, PluginsLive); diff --git a/host/src/lib/api-client.server.ts b/host/src/lib/api-client.server.ts deleted file mode 100644 index 881774e..0000000 --- a/host/src/lib/api-client.server.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { createRouterClient, type RouterClient } from 'every-plugin/orpc'; -import type { AppRouter } from '../routers'; - -declare global { - var $apiClient: RouterClient | undefined; -} - -export function initializeServerApiClient(router: AppRouter) { - globalThis.$apiClient = createRouterClient(router, { - context: async () => ({ - session: null, - user: null, - nearAccountId: null, - }), - }); -} - -export function getServerApiClient() { - if (!globalThis.$apiClient) { - throw new Error('Server API client not initialized. Call initializeServerApiClient first.'); - } - return globalThis.$apiClient; -} - -export function hasServerApiClient(): boolean { - return !!globalThis.$apiClient; -} diff --git a/host/src/lib/auth.ts b/host/src/lib/auth.ts deleted file mode 100644 index 6e34d88..0000000 --- a/host/src/lib/auth.ts +++ /dev/null @@ -1,57 +0,0 @@ - -import fs from "node:fs"; -import path from "node:path"; -import { betterAuth } from "better-auth"; -import { drizzleAdapter } from "better-auth/adapters/drizzle"; -import { admin } from "better-auth/plugins"; -import { siwn } from "better-near-auth"; -import { db } from "../db"; -import * as schema from "../db/schema/auth"; - -const configPath = process.env.BOS_CONFIG_PATH ?? path.resolve(process.cwd(), 'bos.config.json'); -const bosConfig = JSON.parse(fs.readFileSync(configPath, 'utf8')); -const env = process.env.NODE_ENV === "production" ? "production" : "development"; -const defaultOrigins = [ - bosConfig?.app?.host?.[env], - bosConfig?.app?.ui?.[env], -].filter(Boolean); - -export const auth = betterAuth({ - database: drizzleAdapter(db, { - provider: "sqlite", - schema: schema, - }), - trustedOrigins: process.env.CORS_ORIGIN?.split(",") || defaultOrigins, - secret: process.env.BETTER_AUTH_SECRET, - baseURL: process.env.BETTER_AUTH_URL, - plugins: [ - siwn({ - recipient: bosConfig.account - }), - admin({ - defaultRole: "user", - adminRoles: ["admin"], - }), - ], - account: { - accountLinking: { - enabled: true, - trustedProviders: ["siwn"], - allowDifferentEmails: true, - updateUserInfoOnLink: true - } - }, - session: { - cookieCache: { - enabled: true, - maxAge: 5 * 60 // 5 minutes cache - reduces DB hits - } - }, - advanced: { - defaultCookieAttributes: { - sameSite: "lax", - secure: process.env.NODE_ENV === "production", - httpOnly: true - } - } -}); diff --git a/host/src/lib/rate-limit.ts b/host/src/lib/rate-limit.ts deleted file mode 100644 index b90a25c..0000000 --- a/host/src/lib/rate-limit.ts +++ /dev/null @@ -1,85 +0,0 @@ -/** - * In-Memory Rate Limiter - * - * Provides simple rate limiting for API endpoints. - * For production multi-instance deployments, replace with Redis-backed implementation. - */ - -type RateLimitEntry = { - count: number; - resetAt: number; -}; - -type RateLimitConfig = { - windowMs: number; - maxRequests: number; -}; - -class RateLimiter { - private store = new Map(); - private cleanupInterval: NodeJS.Timeout; - - constructor() { - // Clean up expired entries every minute - this.cleanupInterval = setInterval(() => this.cleanup(), 60_000); - } - - check( - key: string, - config: RateLimitConfig - ): { allowed: boolean; remaining: number; resetAt: number } { - const now = Date.now(); - const entry = this.store.get(key); - - // No entry or expired - create new window - if (!entry || now >= entry.resetAt) { - const resetAt = now + config.windowMs; - this.store.set(key, { count: 1, resetAt }); - return { allowed: true, remaining: config.maxRequests - 1, resetAt }; - } - - // Rate limit exceeded - if (entry.count >= config.maxRequests) { - return { allowed: false, remaining: 0, resetAt: entry.resetAt }; - } - - // Increment counter - entry.count++; - return { - allowed: true, - remaining: config.maxRequests - entry.count, - resetAt: entry.resetAt, - }; - } - - private cleanup() { - const now = Date.now(); - for (const [key, entry] of this.store) { - if (now >= entry.resetAt) { - this.store.delete(key); - } - } - } - - destroy() { - clearInterval(this.cleanupInterval); - this.store.clear(); - } -} - -export const rateLimiter = new RateLimiter(); - -/** - * Rate limit configurations by endpoint type - * - * Production note: Adjust these based on your expected traffic patterns - * and NEAR AI Cloud API limits. - */ -export const RATE_LIMITS = { - chat: { windowMs: 60_000, maxRequests: 20 }, // 20 chat requests per minute - kv: { windowMs: 60_000, maxRequests: 100 }, // 100 KV operations per minute - auth: { windowMs: 60_000, maxRequests: 100 }, // 100 auth attempts per minute - global: { windowMs: 60_000, maxRequests: 1000 }, // 1000 total requests per minute -} as const; - -export type RateLimitType = keyof typeof RATE_LIMITS; diff --git a/host/src/main.tsx b/host/src/main.tsx deleted file mode 100644 index 3ec22d0..0000000 --- a/host/src/main.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { - Suspense, - lazy, - type FC, - useState, - type CSSProperties, - useCallback, -} from 'react'; -import { loadRemote } from '@module-federation/enhanced/runtime'; -import { ErrorBoundary, Loading } from './ui'; -import { getRuntimeConfig } from './federation'; - -const RemoteApp = lazy(async () => { - const config = getRuntimeConfig(); - const module = await loadRemote<{ default: FC }>(`${config.ui.name}/App`); - if (!module) throw new Error(`Failed to load ${config.ui.name}/App`); - return module; -}); - -export const Main: FC = () => { - const [retryKey, setRetryKey] = useState(0); - - const handleRetry = useCallback(() => { - console.log('[Host] Retrying remote app load...'); - setRetryKey((prev) => prev + 1); - }, []); - - const containerStyle: CSSProperties = { - display: 'flex', - flexDirection: 'column', - height: '100vh', - width: '100vw', - overflow: 'hidden', - }; - - const contentStyle: CSSProperties = { - flex: 1, - display: 'flex', - flexDirection: 'column', - overflow: 'auto', - }; - - return ( -
-
- { - console.error('[Host] Failed to load remote app:', error.message); - }} - onRetry={handleRetry} - > - }> - - - -
-
- ); -}; - -export default Main; diff --git a/host/src/middleware/rate-limit.ts b/host/src/middleware/rate-limit.ts deleted file mode 100644 index 681deb5..0000000 --- a/host/src/middleware/rate-limit.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Rate Limiting Middleware - * - * Provides configurable rate limiting for Hono routes. - * Keys are based on authenticated user ID (preferred) or IP address (fallback). - */ - -import type { Context, Next } from "hono"; -import { rateLimiter, RATE_LIMITS, type RateLimitType } from "../lib/rate-limit"; - -export function rateLimit(type: RateLimitType, keyFn?: (c: Context) => string) { - const config = RATE_LIMITS[type]; - - return async (c: Context, next: Next) => { - let key: string; - - if (keyFn) { - // Custom key function provided - key = keyFn(c); - } else { - // Default: use authenticated user ID or fall back to IP - const session = c.get("session"); - const userId = session?.user?.id; - const ip = c.req.header("x-forwarded-for")?.split(",")[0] || - c.req.header("x-real-ip") || - "unknown"; - key = userId || `ip:${ip}`; - } - - const fullKey = `${type}:${key}`; - const result = rateLimiter.check(fullKey, config); - - // Add rate limit headers to response - c.header("X-RateLimit-Limit", String(config.maxRequests)); - c.header("X-RateLimit-Remaining", String(result.remaining)); - c.header("X-RateLimit-Reset", String(Math.ceil(result.resetAt / 1000))); - - if (!result.allowed) { - c.header("Retry-After", String(Math.ceil((result.resetAt - Date.now()) / 1000))); - return c.json( - { - error: "RATE_LIMITED", - message: "Too many requests. Please slow down.", - retryAfter: Math.ceil((result.resetAt - Date.now()) / 1000), - }, - 429 - ); - } - - // Global rate limit check (protects against total system overload) - const globalResult = rateLimiter.check("global:all", RATE_LIMITS.global); - if (!globalResult.allowed) { - return c.json( - { - error: "RATE_LIMITED", - message: "Service is experiencing high load. Please try again shortly.", - retryAfter: Math.ceil((globalResult.resetAt - Date.now()) / 1000), - }, - 429 - ); - } - - await next(); - }; -} - -// Pre-configured middleware for common endpoints -export const rateLimitChat = rateLimit("chat"); -export const rateLimitKV = rateLimit("kv"); -export const rateLimitAuth = rateLimit("auth", (c) => { - // For auth, always key by IP (user isn't authenticated yet) - const ip = c.req.header("x-forwarded-for")?.split(",")[0] || - c.req.header("x-real-ip") || - "unknown"; - return `ip:${ip}`; -}); diff --git a/host/src/program.ts b/host/src/program.ts new file mode 100644 index 0000000..7470784 --- /dev/null +++ b/host/src/program.ts @@ -0,0 +1,372 @@ +import { createServer, type IncomingHttpHeaders } from "node:http"; +import { serve } from "@hono/node-server"; +import { serveStatic } from "@hono/node-server/serve-static"; +import { OpenAPIHandler } from "@orpc/openapi/fetch"; +import { OpenAPIReferencePlugin } from "@orpc/openapi/plugins"; +import { RPCHandler } from "@orpc/server/fetch"; +import { BatchHandlerPlugin } from "@orpc/server/plugins"; +import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4"; +import { Effect, ManagedRuntime } from "every-plugin/effect"; +import { formatORPCError } from "every-plugin/errors"; +import { onError } from "every-plugin/orpc"; +import { type Context, Hono } from "hono"; +import { compress } from "hono/compress"; +import { cors } from "hono/cors"; +import { FullServerLive } from "./layers"; +import { type Auth, AuthService } from "./services/auth"; +import { type BootstrapConfig, ConfigService, type RuntimeConfig, setBootstrapConfig } from "./services/config"; +import { createRequestContext } from "./services/context"; +import type { Database } from "./services/database"; +import { closeDatabase, DatabaseService } from "./services/database"; +import { loadRouterModule, type RouterModule } from "./services/federation.server"; +import { type PluginResult, PluginsService } from "./services/plugins"; +import { createRouter } from "./services/router"; +import { logger } from "./utils/logger"; + +function nodeHeadersToHeaders(nodeHeaders: IncomingHttpHeaders): Headers { + const headers = new Headers(); + for (const [key, value] of Object.entries(nodeHeaders)) { + if (value) { + if (Array.isArray(value)) { + for (const v of value) { + headers.append(key, v); + } + } else { + headers.set(key, value); + } + } + } + return headers; +} + +async function proxyRequest(req: Request, targetBase: string): Promise { + const url = new URL(req.url); + const targetUrl = `${targetBase}${url.pathname}${url.search}`; + + const headers = new Headers(req.headers); + headers.delete("host"); + + const proxyReq = new Request(targetUrl, { + method: req.method, + headers, + body: req.body, + duplex: "half", + } as RequestInit); + + return fetch(proxyReq); +} + +function setupApiRoutes( + app: Hono, + config: RuntimeConfig, + plugins: PluginResult, + auth: Auth, + db: Database +) { + const isProxyMode = !!config.api.proxy; + + if (isProxyMode) { + const proxyTarget = config.api.proxy!; + logger.info(`[API] Proxy mode enabled → ${proxyTarget}`); + + app.all("/api/*", async (c: Context) => { + const response = await proxyRequest(c.req.raw, proxyTarget); + return response; + }); + + return; + } + + const router = createRouter(plugins); + + const rpcHandler = new RPCHandler(router, { + plugins: [new BatchHandlerPlugin()], + interceptors: [onError((error: unknown) => formatORPCError(error))], + }); + + const apiHandler = new OpenAPIHandler(router, { + plugins: [ + new OpenAPIReferencePlugin({ + schemaConverters: [new ZodToJsonSchemaConverter()], + specGenerateOptions: { + info: { + title: config.title, + version: "1.0.0", + }, + servers: [{ url: `${config.hostUrl}/api` }], + }, + }), + ], + interceptors: [onError((error: unknown) => formatORPCError(error))], + }); + + app.on(["POST", "GET"], "/api/auth/*", (c: Context) => auth.handler(c.req.raw)); + + app.all("/api/rpc/*", async (c: Context) => { + const req = c.req.raw; + const context = await createRequestContext(req, auth, db); + + const result = await rpcHandler.handle(req, { + prefix: "/api/rpc", + context, + }); + + return result.response ? c.newResponse(result.response.body, result.response) : c.text("Not Found", 404); + }); + + app.all("/api/*", async (c: Context) => { + const req = c.req.raw; + const context = await createRequestContext(req, auth, db); + + const result = await apiHandler.handle(req, { + prefix: "/api", + context, + }); + + return result.response ? c.newResponse(result.response.body, result.response) : c.text("Not Found", 404); + }); +} + +export const createStartServer = (onReady?: () => void) => Effect.gen(function* () { + const port = Number(process.env.PORT) || 3000; + const isDev = process.env.NODE_ENV !== "production"; + + const config = yield* ConfigService; + const db = yield* DatabaseService; + const auth = yield* AuthService; + const plugins = yield* PluginsService; + + const app = new Hono(); + + app.use( + "/*", + cors({ + origin: process.env.CORS_ORIGIN?.split(",").map((o) => o.trim()) ?? [ + config.hostUrl, + config.ui.url, + ], + credentials: true, + }) + ); + + if (!isDev) { + app.use("/*", async (c, next) => { + const accept = c.req.header("accept") || ""; + if (accept.includes("text/html")) { + return next(); + } + return compress()(c, next); + }); + } + + app.get("/health", (c: Context) => c.text("OK")); + + setupApiRoutes(app, config, plugins, auth, db); + + logger.info(`[Config] UI source: ${config.ui.source} → ${config.ui.url}`); + logger.info(`[Config] API source: ${config.api.source} → ${config.api.url}`); + if (config.api.proxy) { + logger.info(`[Config] API proxy: ${config.api.proxy}`); + } + + let ssrRouterModule: RouterModule | null = null; + + app.get("*", async (c: Context) => { + if (!ssrRouterModule) { + return c.html(` + + + + + Loading... + + + + +

⏳ SSR Loading...

+

The UI module is still loading. This page will refresh automatically.

+ + + `, 503); + } + + try { + const { env, account, title, hostUrl } = config; + const assetsUrl = config.ui.url; + const result = await ssrRouterModule.renderToStream(c.req.raw, { + assetsUrl, + runtimeConfig: { env, account, title, hostUrl, assetsUrl, apiBase: "/api", rpcBase: "/api/rpc" }, + }); + return new Response(result.stream, { + status: result.statusCode, + headers: result.headers, + }); + } catch (error) { + logger.error("[SSR] Streaming error:", error); + return c.html(` + + + + + Server Error + + + +

Server Error

+

An error occurred during server-side rendering.

+
${error instanceof Error ? error.stack : String(error)}
+ + + `, 500); + } + }); + + if (!isDev) { + app.use("/static/*", serveStatic({ root: "./dist" })); + app.use("/favicon.ico", serveStatic({ root: "./dist" })); + app.use("/icon.svg", serveStatic({ root: "./dist" })); + app.use("/manifest.json", serveStatic({ root: "./dist" })); + app.use("/robots.txt", serveStatic({ root: "./dist" })); + } + + const startHttpServer = () => { + if (isDev) { + const server = createServer(async (req, res) => { + const url = req.url || "/"; + const fetchReq = new Request(`http://localhost:${port}${url}`, { + method: req.method, + headers: nodeHeadersToHeaders(req.headers), + body: req.method !== "GET" && req.method !== "HEAD" ? req : undefined, + duplex: "half", + } as RequestInit); + + try { + const response = await app.fetch(fetchReq); + res.statusCode = response.status; + response.headers.forEach((value: string, key: string) => { + res.setHeader(key, value); + }); + + if (response.body) { + const reader = response.body.getReader(); + const pump = async () => { + const { done, value } = await reader.read(); + if (done) { + res.end(); + return; + } + res.write(value); + await pump(); + }; + await pump(); + } else { + const body = await response.arrayBuffer(); + res.end(Buffer.from(body)); + } + } catch (err) { + logger.error("[Server] Error handling request:", err); + res.statusCode = 500; + res.end("Internal Server Error"); + } + }); + + server.listen(port, () => { + logger.info(`Host dev server running at http://localhost:${port}`); + logger.info(` http://localhost:${port}/api → REST API (OpenAPI docs)`); + logger.info(` http://localhost:${port}/api/rpc → RPC endpoint`); + onReady?.(); + }); + } else { + const hostname = process.env.HOST || "0.0.0.0"; + serve({ fetch: app.fetch, port, hostname }, (info: { port: number }) => { + logger.info(`Host production server running at http://${hostname}:${info.port}`); + logger.info(` http://${hostname}:${info.port}/api → REST API (OpenAPI docs)`); + logger.info(` http://${hostname}:${info.port}/api/rpc → RPC endpoint`); + onReady?.(); + }); + } + }; + + startHttpServer(); + + yield* Effect.fork( + Effect.gen(function* () { + const ssrUrl = config.ui.ssrUrl ?? config.ui.url; + logger.info(`[SSR] Loading Router module from ${ssrUrl}...`); + + const routerModuleResult = yield* loadRouterModule(config).pipe(Effect.either); + + if (routerModuleResult._tag === "Left") { + logger.error("[SSR] Failed to load Router module:", routerModuleResult.left); + logger.warn("[SSR] Server running in API-only mode, SSR disabled"); + return; + } + + ssrRouterModule = routerModuleResult.right; + logger.info("[SSR] Router module loaded successfully, SSR routes active"); + }) + ); + + yield* Effect.never; +}); + +export const startServer = createStartServer(); + +export const ServerLive = FullServerLive; + +export interface ServerHandle { + ready: Promise; + shutdown: () => Promise; +} + +export const runServer = (bootstrap?: BootstrapConfig): ServerHandle => { + if (bootstrap) { + setBootstrapConfig(bootstrap); + } + + let resolveReady: () => void; + let rejectReady: (err: unknown) => void; + + const ready = new Promise((resolve, reject) => { + resolveReady = resolve; + rejectReady = reject; + }); + + const runtime = ManagedRuntime.make(ServerLive); + + const shutdown = async () => { + console.log("[Server] Shutting down..."); + closeDatabase(); + await runtime.dispose(); + console.log("[Server] Shutdown complete"); + }; + + const serverEffect = createStartServer(() => resolveReady()); + + runtime.runPromise(serverEffect).catch((err) => { + console.error("Failed to start server:", err); + rejectReady(err); + }); + + return { ready, shutdown }; +}; + +export const runServerBlocking = async () => { + const handle = runServer(); + + process.on("SIGINT", () => void handle.shutdown().then(() => process.exit(0))); + process.on("SIGTERM", () => void handle.shutdown().then(() => process.exit(0))); + + try { + await handle.ready; + await new Promise(() => { }); + } catch (err) { + console.error("Failed to start server:", err); + process.exit(1); + } +}; diff --git a/ui/src/reportWebVitals.ts b/host/src/reportWebVitals.ts similarity index 100% rename from ui/src/reportWebVitals.ts rename to host/src/reportWebVitals.ts diff --git a/host/src/routers/index.ts b/host/src/routers/index.ts deleted file mode 100644 index 1a770d5..0000000 --- a/host/src/routers/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { RouterClient } from 'every-plugin/orpc'; -import { os } from 'every-plugin/orpc'; -import type { Plugins } from '../runtime'; - -export function createRouter(plugins: Plugins) { - const baseRouter = { - health: os.route({ method: 'GET', path: '/health' }).handler(() => 'OK'), - } as const; - - if (!plugins.status.available || !plugins.api?.router) { - console.warn( - '[Router] Plugin router not available, using base router only' - ); - return baseRouter; - } - - return { - ...baseRouter, - ...plugins.api.router, - } as const; -} - -export type AppRouter = ReturnType; -export type AppRouterClient = RouterClient; diff --git a/host/src/runtime.ts b/host/src/runtime.ts deleted file mode 100644 index 8965522..0000000 --- a/host/src/runtime.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { createPluginRuntime } from 'every-plugin'; -import { loadBosConfig } from './config'; - -export interface PluginStatus { - available: boolean; - pluginName: string | null; - error: string | null; - errorDetails: string | null; -} - -function secretsFromEnv(keys: string[]): Record { - const out: Record = {}; - for (const k of keys) { - const v = process.env[k]; - if (typeof v === "string" && v.length > 0) out[k] = v; - } - return out; -} - -export interface PluginResult { - runtime: ReturnType | null; - api: any | null; // Plugin types loaded dynamically - status: PluginStatus; -} - -export async function initializePlugins(): Promise { - let pluginName: string | null = null; - let pluginUrl: string | null = null; - - try { - const config = await loadBosConfig(); - const pluginConfig = config.api; - pluginName = pluginConfig.name; - pluginUrl = pluginConfig.url; - - console.log(`[Plugins] Registering remote: ${pluginName} from ${pluginUrl}`); - - const runtime = createPluginRuntime({ - registry: { - [pluginName]: { - remote: pluginUrl, - }, - }, - secrets: {}, - }); - - const secrets = pluginConfig.secrets - ? secretsFromEnv(pluginConfig.secrets) - : {}; - const variables = pluginConfig.variables ?? {}; - - const api = await runtime.usePlugin(pluginName, { - // @ts-expect-error no plugin types loaded - variables, - // @ts-expect-error no plugin types loaded - secrets, - }); - - return { - runtime, - api, - status: { - available: true, - pluginName, - error: null, - errorDetails: null, - }, - }; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - const errorStack = error instanceof Error ? error.stack : undefined; - - console.error('[Plugins] ❌ Failed to initialize plugin'); - - if (errorMessage.includes('register-remote') || errorStack?.includes('register-remote')) { - console.error(`[Plugins] Failed to register remote plugin: ${pluginName}`); - console.error(`[Plugins] Remote URL: ${pluginUrl}`); - console.error('[Plugins] Possible causes:'); - console.error(' • API server is not running at the configured URL'); - console.error(' • Wrong URL in bos.config.json'); - console.error(' • Network connectivity issue'); - console.error(' • CORS configuration problem'); - console.error(`[Plugins] Error: ${errorMessage}`); - } else if (errorMessage.includes('validation') || errorMessage.includes('ZodError')) { - console.error('[Plugins] Configuration validation failed'); - console.error('[Plugins] Check that all required secrets are set in your environment variables'); - console.error(`[Plugins] Error: ${errorMessage}`); - } else if (errorMessage.includes('ENOTDIR') || errorMessage.includes('ENOENT')) { - console.error('[Plugins] Plugin file not found - ensure API is running and built'); - console.error(`[Plugins] Attempted URL: ${pluginUrl}`); - console.error(`[Plugins] Error: ${errorMessage}`); - } else if (errorMessage.includes('fetch') || errorMessage.includes('network')) { - console.error('[Plugins] Network error - ensure API server is running at the configured URL'); - console.error(`[Plugins] URL: ${pluginUrl}`); - console.error(`[Plugins] Error: ${errorMessage}`); - } else { - console.error(`[Plugins] Plugin: ${pluginName}`); - console.error(`[Plugins] URL: ${pluginUrl}`); - console.error(`[Plugins] Error: ${errorMessage}`); - } - - console.warn('[Plugins] Server will continue without plugin functionality'); - - return { - runtime: null, - api: null, - status: { - available: false, - pluginName, - error: errorMessage, - errorDetails: errorStack ?? null, - }, - }; - } -} - -export type Plugins = Awaited>; diff --git a/host/src/scripts/promote-admin.ts b/host/src/scripts/promote-admin.ts deleted file mode 100644 index 83e448a..0000000 --- a/host/src/scripts/promote-admin.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Promote User to Admin - * - * Usage: bun run promote-admin - * Example: bun run promote-admin alice.near - */ - -import { db } from '../db'; -import { user, nearAccount } from '../db/schema/auth'; -import { eq } from 'drizzle-orm'; - -async function promoteToAdmin(nearAccountId: string) { - // Find user by NEAR account ID - const account = await db.query.nearAccount.findFirst({ - where: eq(nearAccount.accountId, nearAccountId), - }); - - if (!account) { - console.error(`❌ No user found with NEAR account: ${nearAccountId}`); - process.exit(1); - } - - // Update user role - const result = await db - .update(user) - .set({ role: 'admin' }) - .where(eq(user.id, account.userId)) - .returning(); - - if (result.length > 0) { - console.log(`✅ Promoted ${nearAccountId} to admin`); - console.log(` User ID: ${result[0].id}`); - console.log(` Email: ${result[0].email}`); - } else { - console.error(`❌ Failed to promote user`); - process.exit(1); - } -} - -const nearAccountId = process.argv[2]; -if (!nearAccountId) { - console.error('Usage: bun run promote-admin '); - process.exit(1); -} - -promoteToAdmin(nearAccountId) - .then(() => process.exit(0)) - .catch((err) => { - console.error('Error:', err); - process.exit(1); - }); diff --git a/host/src/services/auth.ts b/host/src/services/auth.ts new file mode 100644 index 0000000..a527244 --- /dev/null +++ b/host/src/services/auth.ts @@ -0,0 +1,62 @@ +import { betterAuth } from "better-auth"; +import { drizzleAdapter } from "better-auth/adapters/drizzle"; +import { admin } from "better-auth/plugins"; +import { siwn } from "better-near-auth"; +import { Context, Effect, Layer } from "every-plugin/effect"; +import * as schema from "../db/schema/auth"; +import { ConfigService } from "./config"; +import { DatabaseService } from "./database"; + +export type Auth = ReturnType; + +export const createAuth = Effect.gen(function* () { + const config = yield* ConfigService; + const db = yield* DatabaseService; + + return betterAuth({ + database: drizzleAdapter(db, { + provider: "sqlite", + schema: schema, + }), + trustedOrigins: process.env.CORS_ORIGIN?.split(",") || ["*"], + secret: process.env.BETTER_AUTH_SECRET || "default-secret-change-in-production", + baseURL: process.env.BETTER_AUTH_URL, + plugins: [ + siwn({ + recipient: config.account, + }), + admin({ + defaultRole: "user", + adminRoles: ["admin"], + }), + ], + account: { + accountLinking: { + enabled: true, + trustedProviders: ["siwn"], + allowDifferentEmails: true, + updateUserInfoOnLink: true, + }, + }, + session: { + cookieCache: { + enabled: process.env.NODE_ENV === "production", + maxAge: 5 * 60 // 5 minutes cache - reduces DB hits + } + }, + advanced: { + defaultCookieAttributes: { + sameSite: "lax", + secure: process.env.NODE_ENV === "production", + httpOnly: true + } + }, + }); +}); + +export class AuthService extends Context.Tag("host/AuthService")() { + static Default = Layer.effect(AuthService, createAuth).pipe( + Layer.provide(ConfigService.Default), + Layer.provide(DatabaseService.Default) + ); +} diff --git a/host/src/services/config.ts b/host/src/services/config.ts new file mode 100644 index 0000000..d24980f --- /dev/null +++ b/host/src/services/config.ts @@ -0,0 +1,194 @@ +import { readFile } from "node:fs/promises"; +import { resolve } from "node:path"; +import { Effect } from "every-plugin/effect"; +import { ConfigError } from "./errors"; + +export interface BootstrapConfig { + configPath?: string; + secrets?: Record; + host?: { url?: string }; + ui?: { source?: SourceMode }; + api?: { source?: SourceMode; proxy?: string }; + database?: { url?: string }; + gatewayConfig?: BosConfig; + gatewaySecrets?: Record; +} + +let globalBootstrap: BootstrapConfig | undefined; + +export function setBootstrapConfig(config: BootstrapConfig): void { + globalBootstrap = config; +} + +export interface BosConfig { + account: string; + gateway?: string; + app: { + host: { + title: string; + description?: string; + development: string; + production: string; + secrets?: string[]; + }; + ui: { + name: string; + development: string; + production: string; + ssr?: string; + exposes: Record; + }; + api: { + name: string; + development: string; + production: string; + variables?: Record; + secrets?: string[]; + }; + }; +} + +export type SourceMode = "local" | "remote"; + +export interface RuntimeConfig { + env: "development" | "production"; + account: string; + title: string; + hostUrl: string; + ui: { + name: string; + url: string; + ssrUrl?: string; + source: SourceMode; + exposes: Record; + }; + api: { + name: string; + url: string; + source: SourceMode; + proxy?: string; + variables?: Record; + secrets?: string[]; + }; +} + +export type ClientRuntimeConfig = Pick & { + assetsUrl: string; + apiBase: string; + rpcBase: string; +}; + +export type WindowRuntimeConfig = Pick & { + ui: Pick; + apiBase: string; + rpcBase: string; +}; + +function resolveSource( + bootstrapSource: SourceMode | undefined, + envVar: string | undefined, + env: string +): SourceMode { + if (bootstrapSource) return bootstrapSource; + if (envVar === "local" || envVar === "remote") return envVar; + return env === "production" ? "remote" : "local"; +} + +function loadConfigFromGateway( + gatewayConfig: BosConfig, + gatewaySecrets: Record | undefined, + env: "development" | "production" +): RuntimeConfig { + if (gatewaySecrets) { + for (const [key, value] of Object.entries(gatewaySecrets)) { + process.env[key] = value; + } + } + + return { + env, + account: gatewayConfig.account, + title: gatewayConfig.app.host.title, + hostUrl: gatewayConfig.app.host.production, + ui: { + name: gatewayConfig.app.ui.name, + url: gatewayConfig.app.ui.production, + ssrUrl: gatewayConfig.app.ui.ssr || undefined, + source: "remote", + exposes: gatewayConfig.app.ui.exposes, + }, + api: { + name: gatewayConfig.app.api.name, + url: gatewayConfig.app.api.production, + source: "remote", + proxy: undefined, + variables: gatewayConfig.app.api.variables, + secrets: gatewayConfig.app.api.secrets, + }, + }; +} + +export const loadConfig = Effect.gen(function* () { + const bootstrap = globalBootstrap; + const env = (process.env.NODE_ENV as "development" | "production") || "development"; + + if (bootstrap?.gatewayConfig) { + return loadConfigFromGateway(bootstrap.gatewayConfig, bootstrap.gatewaySecrets, env); + } + + const path = bootstrap?.configPath ?? process.env.BOS_CONFIG_PATH ?? resolve(process.cwd(), "bos.config.json"); + + if (bootstrap?.secrets) { + for (const [key, value] of Object.entries(bootstrap.secrets)) { + process.env[key] = value; + } + } + + const raw = yield* Effect.tryPromise({ + try: () => readFile(path, "utf8"), + catch: (e) => new ConfigError({ path, cause: e }), + }); + + const config = yield* Effect.try({ + try: () => JSON.parse(raw) as BosConfig, + catch: (e) => new ConfigError({ path, cause: e }), + }); + + const uiSource = resolveSource(bootstrap?.ui?.source, process.env.UI_SOURCE, env); + const apiSource = resolveSource(bootstrap?.api?.source, process.env.API_SOURCE, env); + + const apiProxyEnv = bootstrap?.api?.proxy ?? process.env.API_PROXY; + const apiProxy = apiProxyEnv === "true" ? config.app.host.production : apiProxyEnv || undefined; + + const uiUrl = uiSource === "remote" ? config.app.ui.production : config.app.ui.development; + const apiUrl = apiSource === "remote" ? config.app.api.production : config.app.api.development; + const ssrUrl = config.app.ui.ssr || undefined; + + return { + env, + account: config.account, + title: config.app.host.title, + hostUrl: bootstrap?.host?.url ?? config.app.host[env], + ui: { + name: config.app.ui.name, + url: uiUrl, + ssrUrl, + source: uiSource, + exposes: config.app.ui.exposes, + }, + api: { + name: config.app.api.name, + url: apiUrl, + source: apiSource, + proxy: apiProxy, + variables: config.app.api.variables, + secrets: config.app.api.secrets, + }, + } satisfies RuntimeConfig; +}); + +export class ConfigService extends Effect.Service()("host/ConfigService", { + effect: loadConfig, +}) { } + +export const loadBosConfig = (): Promise => Effect.runPromise(loadConfig); diff --git a/host/src/services/context.ts b/host/src/services/context.ts new file mode 100644 index 0000000..f1ec007 --- /dev/null +++ b/host/src/services/context.ts @@ -0,0 +1,35 @@ +import { eq } from "drizzle-orm"; +import * as schema from "../db/schema/auth"; +import type { Auth } from "./auth"; +import type { Database } from "./database"; + +type SessionResult = Awaited>; +type User = NonNullable["user"]; + +export interface RequestContext { + session: SessionResult; + user: User | null; + nearAccountId: string | null; +} + +export async function createRequestContext( + req: Request, + auth: Auth, + db: Database +): Promise { + const session = await auth.api.getSession({ headers: req.headers }); + + let nearAccountId: string | null = null; + if (session?.user?.id) { + const nearAccount = await db.query.nearAccount.findFirst({ + where: eq(schema.nearAccount.userId, session.user.id), + }); + nearAccountId = nearAccount?.accountId ?? null; + } + + return { + session, + user: session?.user ?? null, + nearAccountId, + }; +} diff --git a/host/src/services/database.ts b/host/src/services/database.ts new file mode 100644 index 0000000..b944eff --- /dev/null +++ b/host/src/services/database.ts @@ -0,0 +1,53 @@ +import { type Client, createClient } from "@libsql/client"; +import { drizzle, type LibSQLDatabase } from "drizzle-orm/libsql"; +import { Effect } from "every-plugin/effect"; +import * as authSchema from "../db/schema/auth"; +import { DatabaseError } from "./errors"; + +type Schema = typeof authSchema; + +export interface DatabaseClient { + db: LibSQLDatabase; + client: Client; +} + +let activeClient: Client | null = null; + +const acquireDatabase = Effect.try({ + try: (): LibSQLDatabase => { + const client = createClient({ + url: process.env.HOST_DATABASE_URL || "file:./database.db", + authToken: process.env.HOST_DATABASE_AUTH_TOKEN, + }); + + activeClient = client; + + const db = drizzle(client, { + schema: { + ...authSchema, + }, + }); + + return db; + }, + catch: (e) => new DatabaseError({ cause: e }), +}); + +export const closeDatabase = (): void => { + if (activeClient) { + try { + activeClient.close(); + console.log("[Database] Connection closed"); + } catch { + } + activeClient = null; + } +}; + +export const createDatabase = acquireDatabase; + +export type Database = LibSQLDatabase; + +export class DatabaseService extends Effect.Service()("host/DatabaseService", { + effect: createDatabase, +}) {} diff --git a/host/src/services/errors.ts b/host/src/services/errors.ts new file mode 100644 index 0000000..4195544 --- /dev/null +++ b/host/src/services/errors.ts @@ -0,0 +1,26 @@ +import { Data } from "every-plugin/effect"; + +export class ConfigError extends Data.TaggedError("ConfigError")<{ + readonly path?: string; + readonly cause?: unknown; +}> {} + +export class DatabaseError extends Data.TaggedError("DatabaseError")<{ + readonly cause?: unknown; +}> {} + +export class FederationError extends Data.TaggedError("FederationError")<{ + readonly remoteName: string; + readonly remoteUrl?: string; + readonly cause?: unknown; +}> {} + +export class PluginError extends Data.TaggedError("PluginError")<{ + readonly pluginName?: string; + readonly pluginUrl?: string; + readonly cause?: unknown; +}> {} + +export class ServerError extends Data.TaggedError("ServerError")<{ + readonly cause?: unknown; +}> {} diff --git a/host/src/services/federation.server.ts b/host/src/services/federation.server.ts new file mode 100644 index 0000000..94aa9e9 --- /dev/null +++ b/host/src/services/federation.server.ts @@ -0,0 +1,99 @@ +import { createInstance, getInstance } from "@module-federation/enhanced/runtime"; +import { setGlobalFederationInstance } from "@module-federation/runtime-core"; +import { Context, Effect, Layer, Schedule } from "every-plugin/effect"; +import type { RouterModule } from "../types"; +import type { RuntimeConfig } from "./config"; +import { ConfigService } from "./config"; +import { FederationError } from "./errors"; + +export type { RouterModule }; + +let federationInstance: ReturnType | null = null; + +function getOrCreateFederationInstance(config: RuntimeConfig) { + if (federationInstance) return federationInstance; + + const existingInstance = getInstance(); + + const ssrEntryUrl = config.ui.ssrUrl + ? `${config.ui.ssrUrl}/remoteEntry.server.js` + : `${config.ui.url}/remoteEntry.server.js`; + + if (!ssrEntryUrl) { + throw new FederationError({ + remoteName: config.ui.name, + cause: new Error("SSR URL not configured. Set app.ui.ssr in bos.config.json to enable SSR."), + }); + } + + if (existingInstance) { + existingInstance.registerRemotes([{ + name: config.ui.name, + entry: ssrEntryUrl, + alias: config.ui.name, + }]); + federationInstance = existingInstance; + return federationInstance; + } + + federationInstance = createInstance({ + name: "host", + remotes: [ + { + name: config.ui.name, + entry: ssrEntryUrl, + alias: config.ui.name, + }, + ], + }); + + setGlobalFederationInstance(federationInstance); + return federationInstance; +} + +const isDev = process.env.NODE_ENV !== "production"; + +const retrySchedule = Schedule.exponential("500 millis").pipe( + Schedule.compose(Schedule.recurs(isDev ? 15 : 3)), + Schedule.tapOutput((count: number) => + Effect.logInfo(`[Federation] Retry attempt ${count + 1}...`) + ) +); + +export const loadRouterModule = (config: RuntimeConfig) => + Effect.tryPromise({ + try: async () => { + const mf = getOrCreateFederationInstance(config); + const routerModule = await mf.loadRemote(`${config.ui.name}/Router`); + + if (!routerModule) { + throw new Error(`Failed to load Router module from ${config.ui.name}`); + } + + return routerModule; + }, + catch: (e) => + new FederationError({ + remoteName: config.ui.name, + remoteUrl: config.ui.ssrUrl, + cause: e, + }), + }).pipe( + Effect.retry(retrySchedule), + Effect.tapError((e) => + Effect.logError(`[Federation] Failed to load Router module after retries: ${e.message}`) + ) + ); + +export class FederationServerService extends Context.Tag("host/FederationServerService")< + FederationServerService, + RouterModule +>() { + static Live = Layer.effect( + FederationServerService, + Effect.gen(function* () { + const config = yield* ConfigService; + return yield* loadRouterModule(config); + }) + ).pipe(Layer.provide(ConfigService.Default)); +} diff --git a/host/src/services/plugins.ts b/host/src/services/plugins.ts new file mode 100644 index 0000000..c76fb33 --- /dev/null +++ b/host/src/services/plugins.ts @@ -0,0 +1,125 @@ +import { Context, Effect, Layer } from "every-plugin/effect"; +import { createPluginRuntime } from "every-plugin"; +import { ConfigService } from "./config"; +import { PluginError } from "./errors"; + +export interface PluginStatus { + available: boolean; + pluginName: string | null; + error: string | null; + errorDetails: string | null; +} + +export interface PluginResult { + runtime: ReturnType | null; + api: unknown; + status: PluginStatus; +} + +function secretsFromEnv(keys: string[]): Record { + const out: Record = {}; + for (const k of keys) { + const v = process.env[k]; + if (typeof v === "string" && v.length > 0) out[k] = v; + } + return out; +} + +const unavailableResult = ( + pluginName: string | null, + error: string | null, + errorDetails: string | null +): PluginResult => ({ + runtime: null, + api: null, + status: { available: false, pluginName, error, errorDetails }, +}); + +export const initializePlugins = Effect.gen(function* () { + const config = yield* ConfigService; + const pluginConfig = config.api; + const pluginName = pluginConfig.name; + const pluginUrl = pluginConfig.url; + + console.log(`[Plugins] Registering remote: ${pluginName} from ${pluginUrl}`); + + const result = yield* Effect.tryPromise({ + try: async () => { + const runtime = createPluginRuntime({ + registry: { + [pluginName]: { + remote: pluginUrl, + }, + }, + secrets: {}, + }); + + const secrets = pluginConfig.secrets ? secretsFromEnv(pluginConfig.secrets) : {}; + const variables = pluginConfig.variables ?? {}; + + const api = await runtime.usePlugin(pluginName, { + // @ts-expect-error no plugin types loaded + variables, + // @ts-expect-error no plugin types loaded + secrets, + }); + + return { + runtime, + api, + status: { + available: true, + pluginName, + error: null, + errorDetails: null, + }, + } satisfies PluginResult; + }, + catch: (error) => + new PluginError({ + pluginName, + pluginUrl, + cause: error, + }), + }); + + return result; +}).pipe( + Effect.catchAll((error) => { + const pluginName = error instanceof PluginError ? error.pluginName : null; + const pluginUrl = error instanceof PluginError ? error.pluginUrl : null; + const errorMessage = error instanceof Error ? error.message : String(error); + const errorStack = error instanceof Error ? error.stack : undefined; + + console.error("[Plugins] ❌ Failed to initialize plugin"); + console.error(`[Plugins] Plugin: ${pluginName}`); + console.error(`[Plugins] URL: ${pluginUrl}`); + console.error(`[Plugins] Error: ${errorMessage}`); + console.warn("[Plugins] Server will continue without plugin functionality"); + + return Effect.succeed(unavailableResult(pluginName ?? null, errorMessage, errorStack ?? null)); + }) +); + +export class PluginsService extends Context.Tag("host/PluginsService")< + PluginsService, + PluginResult +>() { + static Live = Layer.scoped( + PluginsService, + Effect.gen(function* () { + const plugins = yield* initializePlugins; + + yield* Effect.addFinalizer(() => + Effect.sync(() => { + if (plugins.runtime) { + console.log("[Plugins] Shutting down plugin runtime..."); + plugins.runtime.shutdown(); + } + }) + ); + + return plugins; + }) + ).pipe(Layer.provide(ConfigService.Default)); +} diff --git a/host/src/services/router.ts b/host/src/services/router.ts new file mode 100644 index 0000000..30ef21d --- /dev/null +++ b/host/src/services/router.ts @@ -0,0 +1,28 @@ +import type { RouterClient } from "every-plugin/orpc"; +import { os } from "every-plugin/orpc"; +import type { PluginResult } from "./plugins"; + +export function createRouter(plugins: PluginResult) { + const baseRouter = { + health: os.route({ method: "GET", path: "/health" }).handler(() => "OK"), + } as const; + + if (!plugins.status.available || !plugins.api) { + console.warn("[Router] Plugin router not available, using base router only"); + return baseRouter; + } + + const pluginApi = plugins.api as { router?: Record }; + if (!pluginApi.router) { + console.warn("[Router] Plugin API has no router, using base router only"); + return baseRouter; + } + + return { + ...baseRouter, + ...pluginApi.router, + } as const; +} + +export type AppRouter = ReturnType; +export type AppRouterClient = RouterClient; diff --git a/host/src/ssr.tsx b/host/src/ssr.tsx deleted file mode 100644 index 21638d7..0000000 --- a/host/src/ssr.tsx +++ /dev/null @@ -1,254 +0,0 @@ -import { createElement } from "react"; -import { renderToReadableStream } from "react-dom/server"; -import { RouterProvider } from "@tanstack/react-router"; -import { createMemoryHistory } from "@tanstack/react-router"; -import type { AnyRouter } from "@tanstack/react-router"; -import { - QueryClientProvider, - dehydrate, - type QueryClient, -} from "@tanstack/react-query"; -import { loadRemoteModule } from "./federation.server"; -import type { RuntimeConfig } from "./config"; - -interface CreateRouterResult { - router: AnyRouter; - queryClient: QueryClient; -} - -interface RouterModule { - createRouter: (opts?: { - context?: { queryClient?: QueryClient }; - }) => CreateRouterResult; -} - -export interface SSRRenderOptions { - url: string; - config: RuntimeConfig; -} - -export interface HeadMeta { - title?: string; - name?: string; - property?: string; - content?: string; - charSet?: string; -} - -export interface HeadLink { - rel: string; - href: string; - type?: string; - sizes?: string; - crossorigin?: string; -} - -export interface HeadData { - meta?: HeadMeta[]; - links?: HeadLink[]; -} - -export interface SSRRenderResult { - stream: ReadableStream; - dehydratedState: unknown; - headData: HeadData; -} - -function safeJsonStringify(value: unknown): string { - return JSON.stringify(value) - .replace(//g, "\\u003e") - .replace(/&/g, "\\u0026") - .replace(/\u2028/g, "\\u2028") - .replace(/\u2029/g, "\\u2029"); -} - -function extractHeadData(router: AnyRouter): HeadData { - const meta: HeadMeta[] = []; - const links: HeadLink[] = []; - - try { - const matches = router.state?.matches || []; - - for (const match of matches) { - const route = router.routesById?.[match.routeId]; - const headFn = route?.options?.head; - if (typeof headFn === "function") { - const headResult = headFn({ - params: match.params, - loaderData: match.loaderData, - }); - - if (headResult?.meta) { - meta.push(...headResult.meta); - } - if (headResult?.links) { - links.push(...headResult.links); - } - } - } - } catch (error) { - console.error("[SSR] Failed to extract head data:", error); - } - - return { meta, links }; -} - -export async function renderToStream( - options: SSRRenderOptions -): Promise { - const { url, config } = options; - - const routerModule = await loadRemoteModule( - config.ui.name, - "Router" - ); - const { router, queryClient } = routerModule.createRouter(); - - const memoryHistory = createMemoryHistory({ - initialEntries: [url], - }); - - router.update({ history: memoryHistory }); - - await router.load(); - - const headData = extractHeadData(router); - - const App = createElement( - QueryClientProvider, - { client: queryClient }, - createElement(RouterProvider, { router }) - ); - - const stream = await renderToReadableStream(App, { - onError(error) { - console.error("[SSR] Render error:", error); - }, - }); - - const dehydratedState = dehydrate(queryClient); - - return { stream, dehydratedState, headData }; -} - -function getUiOrigin(url: string): string { - try { - return new URL(url).origin; - } catch { - return url; - } -} - -function renderMetaTags(headData: HeadData): { title: string; tags: string } { - const tags: string[] = []; - let title = ""; - - if (headData.meta) { - for (const meta of headData.meta) { - if (meta.title) { - title = meta.title; - continue; - } - - const attrs: string[] = []; - if (meta.name) attrs.push(`name="${meta.name}"`); - if (meta.property) attrs.push(`property="${meta.property}"`); - if (meta.content) - attrs.push(`content="${meta.content.replace(/"/g, """)}"`); - if (meta.charSet) attrs.push(`charset="${meta.charSet}"`); - - if (attrs.length > 0) { - tags.push(` `); - } - } - } - - if (headData.links) { - for (const link of headData.links) { - const attrs: string[] = [`rel="${link.rel}"`, `href="${link.href}"`]; - if (link.type) attrs.push(`type="${link.type}"`); - if (link.sizes) attrs.push(`sizes="${link.sizes}"`); - if (link.crossorigin) attrs.push(`crossorigin="${link.crossorigin}"`); - - tags.push(` `); - } - } - - return { title, tags: tags.join("\n") }; -} - -export function createSSRHtml( - bodyContent: string, - dehydratedState: unknown, - config: RuntimeConfig, - headData?: HeadData -): string { - const clientConfig = { - env: config.env, - title: config.title, - hostUrl: config.hostUrl, - ui: config.ui, - apiBase: "/api", - rpcBase: "/api/rpc", - }; - - const uiOrigin = getUiOrigin(config.ui.url); - - const { title, tags } = headData - ? renderMetaTags(headData) - : { title: config.title, tags: "" }; - - const pageTitle = title || config.title; - const serializedConfig = safeJsonStringify(clientConfig); - const serializedState = safeJsonStringify(dehydratedState); - - return ` - - - - - - - ${pageTitle} - - - - - - - - -${tags} - - - - - - - - - - - -
${bodyContent}
- - -`; -} diff --git a/host/src/types.ts b/host/src/types.ts new file mode 100644 index 0000000..f6b21e8 --- /dev/null +++ b/host/src/types.ts @@ -0,0 +1,17 @@ +export type { + CreateRouterOptions, + HeadData, + HeadLink, + HeadMeta, + HeadScript, + RenderOptions, + RenderResult, + RouterContext, + RouterModule, +} from "../../ui/src/types"; +export type { + ClientRuntimeConfig, + RuntimeConfig, + SourceMode, + WindowRuntimeConfig, +} from "./services/config"; diff --git a/host/src/ui.tsx b/host/src/ui.tsx index 8d5dc71..d3755a7 100644 --- a/host/src/ui.tsx +++ b/host/src/ui.tsx @@ -201,10 +201,12 @@ export const Loading: FC = () => ( style={{ width: "100%", height: "100%", + minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", - opacity: 0.7, + backgroundColor: "var(--host-bg, #ffffff)", + transition: "background-color 0.2s ease", }} /> ); diff --git a/host/src/utils/logger.ts b/host/src/utils/logger.ts new file mode 100644 index 0000000..897864b --- /dev/null +++ b/host/src/utils/logger.ts @@ -0,0 +1,7 @@ +import { Effect } from "every-plugin/effect" + +export const logger = { + info: (...args: unknown[]) => Effect.runSync(Effect.logInfo(...args)), + warn: (...args: unknown[]) => Effect.runSync(Effect.logWarning(...args)), + error: (...args: unknown[]) => Effect.runSync(Effect.logError(...args)), +} diff --git a/host/tests/integration/seo.test.ts b/host/tests/integration/seo.test.ts new file mode 100644 index 0000000..9e3d6c8 --- /dev/null +++ b/host/tests/integration/seo.test.ts @@ -0,0 +1,518 @@ +import { loadBosConfig, type RuntimeConfig } from "@/services/config"; +import { loadRouterModule } from "@/services/federation.server"; +import type { HeadData, RouterModule } from "@/types"; +import { Effect } from "every-plugin/effect"; +import { beforeAll, describe, expect, it, vi } from "vitest"; + +declare global { + var $apiClient: typeof mockApiClient; +} + +const mockApiClient = { + getValue: vi.fn().mockImplementation(({ key }: { key: string }) => + Promise.resolve({ key, value: `test-value-for-${key}` }) + ), + setValue: vi.fn().mockResolvedValue({ success: true }), + protected: vi.fn().mockResolvedValue({ message: "Protected data" }), +}; + +function escapeHtml(str: string): string { + return str + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +function renderHeadToString(head: HeadData): string { + const parts: string[] = []; + + for (const meta of head.meta) { + if (!meta) continue; + const metaObj = meta as Record; + if ("title" in metaObj && metaObj.title) { + parts.push(`${escapeHtml(String(metaObj.title))}`); + } else { + const attrs = Object.entries(metaObj) + .filter(([k, v]) => k !== "children" && v !== undefined) + .map(([k, v]) => `${k}="${escapeHtml(String(v))}"`) + .join(" "); + if (attrs) parts.push(``); + } + } + + for (const link of head.links) { + if (!link) continue; + const linkObj = link as Record; + const attrs = Object.entries(linkObj) + .filter(([, v]) => v !== undefined) + .map(([k, v]) => `${k}="${escapeHtml(String(v))}"`) + .join(" "); + if (attrs) parts.push(``); + } + + for (const script of head.scripts) { + if (!script) continue; + const scriptObj = script as Record; + const { children, ...rest } = scriptObj; + const attrs = Object.entries(rest) + .filter(([, v]) => v !== undefined) + .map(([k, v]) => + typeof v === "boolean" ? (v ? k : "") : `${k}="${escapeHtml(String(v))}"` + ) + .filter(Boolean) + .join(" "); + if (children) { + parts.push(``); + } else if (attrs) { + parts.push(``); + } + } + + return parts.join("\n"); +} + +describe("SEO Head Extraction", () => { + let routerModule: RouterModule; + let config: RuntimeConfig; + + beforeAll(async () => { + globalThis.$apiClient = mockApiClient; + + config = await loadBosConfig(); + routerModule = await Effect.runPromise(loadRouterModule(config)); + }); + + describe("Module Federation", () => { + it("loads RouterModule from production SSR remote", () => { + expect(routerModule).toBeDefined(); + expect(routerModule.getRouteHead).toBeTypeOf("function"); + expect(routerModule.createRouter).toBeTypeOf("function"); + expect(routerModule.routeTree).toBeDefined(); + }); + + }); + + describe("Root Route (/)", () => { + let head: HeadData; + + beforeAll(async () => { + head = await routerModule.getRouteHead("/", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + }); + + it("returns HeadData structure", () => { + expect(head).toHaveProperty("meta"); + expect(head).toHaveProperty("links"); + expect(head).toHaveProperty("scripts"); + expect(Array.isArray(head.meta)).toBe(true); + expect(Array.isArray(head.links)).toBe(true); + expect(Array.isArray(head.scripts)).toBe(true); + }); + + it("has title meta tag", () => { + const titleMeta = head.meta.find( + (m) => m && typeof m === "object" && "title" in m + ); + expect(titleMeta).toBeDefined(); + expect((titleMeta as { title: string }).title).toBeTruthy(); + }); + + it("has charset meta tag", () => { + const charsetMeta = head.meta.find( + (m) => m && typeof m === "object" && "charSet" in m + ); + expect(charsetMeta).toBeDefined(); + expect((charsetMeta as { charSet: string }).charSet).toBe("utf-8"); + }); + + it("has viewport meta tag", () => { + const viewportMeta = head.meta.find( + (m) => m && typeof m === "object" && "name" in m && (m as { name: string }).name === "viewport" + ); + expect(viewportMeta).toBeDefined(); + }); + + it("has description meta tag", () => { + const descMeta = head.meta.find( + (m) => + m && + typeof m === "object" && + "name" in m && + (m as { name: string }).name === "description" + ); + expect(descMeta).toBeDefined(); + expect((descMeta as { content: string }).content).toBeTruthy(); + }); + + it("has Open Graph tags", () => { + const ogTitle = head.meta.find( + (m) => + m && + typeof m === "object" && + "property" in m && + (m as { property: string }).property === "og:title" + ); + const ogDescription = head.meta.find( + (m) => + m && + typeof m === "object" && + "property" in m && + (m as { property: string }).property === "og:description" + ); + const ogType = head.meta.find( + (m) => + m && + typeof m === "object" && + "property" in m && + (m as { property: string }).property === "og:type" + ); + + expect(ogTitle).toBeDefined(); + expect(ogDescription).toBeDefined(); + expect(ogType).toBeDefined(); + }); + + it("has Twitter Card tags", () => { + const twitterCard = head.meta.find( + (m) => + m && + typeof m === "object" && + "name" in m && + (m as { name: string }).name === "twitter:card" + ); + const twitterTitle = head.meta.find( + (m) => + m && + typeof m === "object" && + "name" in m && + (m as { name: string }).name === "twitter:title" + ); + + expect(twitterCard).toBeDefined(); + expect(twitterTitle).toBeDefined(); + }); + + it("has canonical link", () => { + const canonical = head.links.find( + (l) => + l && typeof l === "object" && "rel" in l && (l as { rel: string }).rel === "canonical" + ); + expect(canonical).toBeDefined(); + }); + + it("has structured data script", () => { + const jsonLd = head.scripts.find( + (s) => + s && + typeof s === "object" && + "type" in s && + (s as { type: string }).type === "application/ld+json" + ); + expect(jsonLd).toBeDefined(); + + const scriptObj = jsonLd as { children?: string }; + if (scriptObj.children) { + const parsed = JSON.parse(scriptObj.children); + expect(parsed["@context"]).toBe("https://schema.org"); + expect(parsed["@type"]).toBe("WebSite"); + } + }); + }); + + describe("Dynamic Route (/keys/:key)", () => { + const testKey = "my-test-key-123"; + + it("includes key param in title", async () => { + const head = await routerModule.getRouteHead(`/keys/${testKey}`, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const titleMeta = head.meta.find( + (m) => m && typeof m === "object" && "title" in m + ); + expect(titleMeta).toBeDefined(); + expect((titleMeta as { title: string }).title).toContain(testKey); + }); + + it("includes key param in og:title", async () => { + const head = await routerModule.getRouteHead(`/keys/${testKey}`, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const ogTitle = head.meta.find( + (m) => + m && + typeof m === "object" && + "property" in m && + (m as { property: string }).property === "og:title" + ); + expect(ogTitle).toBeDefined(); + expect((ogTitle as { content: string }).content).toContain(testKey); + }); + + it("includes key param in description", async () => { + const head = await routerModule.getRouteHead(`/keys/${testKey}`, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const descMeta = head.meta.find( + (m) => + m && + typeof m === "object" && + "name" in m && + (m as { name: string }).name === "description" + ); + expect(descMeta).toBeDefined(); + expect((descMeta as { content: string }).content).toContain(testKey); + }); + + it("works with different key values", async () => { + const keys = ["foo", "bar-baz", "test_key", "KEY123"]; + + for (const key of keys) { + const head = await routerModule.getRouteHead(`/keys/${key}`, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const titleMeta = head.meta.find( + (m) => m && typeof m === "object" && "title" in m + ); + expect((titleMeta as { title: string }).title).toContain(key); + } + }); + + it("includes og:image meta tag", async () => { + const head = await routerModule.getRouteHead(`/keys/${testKey}`, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const ogImage = head.meta.find( + (m) => + m && + typeof m === "object" && + "property" in m && + (m as { property: string }).property === "og:image" + ); + expect(ogImage).toBeDefined(); + expect((ogImage as { content: string }).content).toBeTruthy(); + expect((ogImage as { content: string }).content).toContain("data:image/svg+xml;base64,"); + }); + + it("includes twitter:image meta tag", async () => { + const head = await routerModule.getRouteHead(`/keys/${testKey}`, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const twitterImage = head.meta.find( + (m) => + m && + typeof m === "object" && + "name" in m && + (m as { name: string }).name === "twitter:image" + ); + expect(twitterImage).toBeDefined(); + expect((twitterImage as { content: string }).content).toBeTruthy(); + expect((twitterImage as { content: string }).content).toContain("data:image/svg+xml;base64,"); + }); + + it("generates valid SVG data URL for og:image", async () => { + const head = await routerModule.getRouteHead(`/keys/${testKey}`, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const ogImage = head.meta.find( + (m) => + m && + typeof m === "object" && + "property" in m && + (m as { property: string }).property === "og:image" + ); + const content = (ogImage as { content: string }).content; + const base64Part = content.replace("data:image/svg+xml;base64,", ""); + const svgContent = atob(base64Part); + + expect(svgContent).toContain(" { + it("renders valid title tag", async () => { + const head = await routerModule.getRouteHead("/", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = renderHeadToString(head); + expect(html).toMatch(/.+<\/title>/); + }); + + it("renders meta tags with proper attributes", async () => { + const head = await routerModule.getRouteHead("/", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = renderHeadToString(head); + expect(html).toMatch(/<meta charSet="utf-8" \/>/); + expect(html).toMatch(/<meta name="viewport"/); + expect(html).toMatch(/<meta name="description"/); + expect(html).toMatch(/<meta property="og:title"/); + }); + + it("renders link tags", async () => { + const head = await routerModule.getRouteHead("/", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = renderHeadToString(head); + expect(html).toMatch(/<link rel="canonical"/); + expect(html).toMatch(/<link rel="icon"/); + }); + + it("renders structured data with valid JSON", async () => { + const head = await routerModule.getRouteHead("/", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = renderHeadToString(head); + const jsonLdMatch = html.match( + /<script type="application\/ld\+json">(.+?)<\/script>/s + ); + expect(jsonLdMatch).toBeTruthy(); + + if (jsonLdMatch) { + const jsonContent = jsonLdMatch[1]; + expect(() => JSON.parse(jsonContent)).not.toThrow(); + } + }); + + it("properly escapes HTML in meta content", async () => { + const head: HeadData = { + meta: [ + { title: 'Test <script>alert("xss")</script>' }, + { name: "description", content: 'Test & "quotes" < > symbols' }, + ], + links: [], + scripts: [], + }; + + const html = renderHeadToString(head); + expect(html).not.toContain("<script>"); + expect(html).toContain("<script>"); + expect(html).toContain("&"); + expect(html).toContain("""); + }); + }); +}); diff --git a/host/tests/integration/ssr.test.ts b/host/tests/integration/ssr.test.ts new file mode 100644 index 0000000..7796259 --- /dev/null +++ b/host/tests/integration/ssr.test.ts @@ -0,0 +1,360 @@ +import { Effect } from "every-plugin/effect"; +import { beforeAll, describe, expect, it, vi } from "vitest"; +import { loadBosConfig, type RuntimeConfig } from "@/services/config"; +import { loadRouterModule } from "@/services/federation.server"; +import type { RouterModule } from "@/types"; + +async function consumeStream(stream: ReadableStream): Promise<string> { + const reader = stream.getReader(); + const decoder = new TextDecoder(); + let html = ''; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + html += decoder.decode(value, { stream: true }); + } + html += decoder.decode(); + return html; +} + +const mockApiClient = { + getValue: vi.fn().mockImplementation(({ key }: { key: string }) => + Promise.resolve({ key, value: `test-value-for-${key}` }) + ), + setValue: vi.fn().mockResolvedValue({ success: true }), + protected: vi.fn().mockResolvedValue({ message: "Protected data" }), + listKeys: vi.fn().mockResolvedValue({ keys: [], total: 0, hasMore: false }), +}; + +describe("SSR Stream Lifecycle", () => { + let routerModule: RouterModule; + let config: RuntimeConfig; + + beforeAll(async () => { + globalThis.$apiClient = mockApiClient; + config = await loadBosConfig(); + routerModule = await Effect.runPromise(loadRouterModule(config)); + }); + + describe("Stream Completion", () => { + it("completes stream for root route without timeout", async () => { + const startTime = Date.now(); + + const head = await routerModule.getRouteHead("/", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const elapsed = Date.now() - startTime; + + expect(head).toBeDefined(); + expect(head.meta).toBeDefined(); + expect(elapsed).toBeLessThan(5000); + }); + + it("completes stream for layout routes", async () => { + const startTime = Date.now(); + + const head = await routerModule.getRouteHead("/login", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const elapsed = Date.now() - startTime; + + expect(head).toBeDefined(); + expect(elapsed).toBeLessThan(5000); + }); + + it("does not block on authenticated routes with ssr: false", async () => { + const startTime = Date.now(); + + const head = await routerModule.getRouteHead("/keys", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const elapsed = Date.now() - startTime; + + expect(head).toBeDefined(); + expect(elapsed).toBeLessThan(5000); + }); + + it("handles dynamic authenticated routes without blocking", async () => { + const startTime = Date.now(); + + const head = await routerModule.getRouteHead("/keys/test-key-123", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const elapsed = Date.now() - startTime; + + expect(head).toBeDefined(); + expect(elapsed).toBeLessThan(5000); + }); + }); + + describe("SSR Configuration", () => { + it("renders layout route metadata", async () => { + const head = await routerModule.getRouteHead("/", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const titleMeta = head.meta.find( + (m) => m && typeof m === "object" && "title" in m + ); + expect(titleMeta).toBeDefined(); + }); + + it("authenticated route head does not trigger auth check during SSR", async () => { + const authCallsBefore = mockApiClient.protected.mock.calls.length; + + await routerModule.getRouteHead("/keys", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const authCallsAfter = mockApiClient.protected.mock.calls.length; + expect(authCallsAfter).toBe(authCallsBefore); + }); + }); + + describe("Public SSR Routes", () => { + const STREAM_TIMEOUT = 5000; + + it("renders public /p/{key} route with full SSR", { timeout: 6000 }, async () => { + const request = new Request("http://localhost/p/test-public-key"); + const startTime = Date.now(); + + const result = await routerModule.renderToStream(request, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = await consumeStream(result.stream); + const elapsed = Date.now() - startTime; + + expect(elapsed).toBeLessThan(STREAM_TIMEOUT); + expect(result.statusCode).toBe(200); + expect(html).toContain("<!DOCTYPE html>"); + expect(html).toContain("</html>"); + expect(html).toContain("test-public-key"); + }); + + it("includes OG metadata in public route head", async () => { + const head = await routerModule.getRouteHead("/p/my-og-test", { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + expect(head).toBeDefined(); + expect(head.meta).toBeDefined(); + + const ogTitle = head.meta.find( + (m) => m && typeof m === "object" && "property" in m && m.property === "og:title" + ); + const ogDescription = head.meta.find( + (m) => m && typeof m === "object" && "property" in m && m.property === "og:description" + ); + const ogImage = head.meta.find( + (m) => m && typeof m === "object" && "property" in m && m.property === "og:image" + ); + + expect(ogTitle).toBeDefined(); + expect(ogDescription).toBeDefined(); + expect(ogImage).toBeDefined(); + }); + + it("renders key parameter in full SSR stream", { timeout: 6000 }, async () => { + const request = new Request("http://localhost/p/rendered-key-value"); + + const result = await routerModule.renderToStream(request, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = await consumeStream(result.stream); + + expect(html).toContain("rendered-key-value"); + expect(html).toContain("Public Page:"); + }); + }); + + describe("Full Stream Rendering", () => { + const STREAM_TIMEOUT = 5000; + + it("completes full stream render for root route", { timeout: 6000 }, async () => { + const request = new Request("http://localhost/"); + const startTime = Date.now(); + + const result = await routerModule.renderToStream(request, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = await consumeStream(result.stream); + const elapsed = Date.now() - startTime; + + expect(elapsed).toBeLessThan(STREAM_TIMEOUT); + expect(result.statusCode).toBe(200); + expect(html).toContain("<!DOCTYPE html>"); + expect(html).toContain("</html>"); + }); + + it("completes full stream render for /login route", { timeout: 6000 }, async () => { + const request = new Request("http://localhost/login"); + const startTime = Date.now(); + + const result = await routerModule.renderToStream(request, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = await consumeStream(result.stream); + const elapsed = Date.now() - startTime; + + expect(elapsed).toBeLessThan(STREAM_TIMEOUT); + expect(result.statusCode).toBe(200); + expect(html).toContain("<!DOCTYPE html>"); + }); + + it("completes full stream render for authenticated route /keys/test-key", { timeout: 6000 }, async () => { + const request = new Request("http://localhost/keys/test-key"); + const startTime = Date.now(); + + const result = await routerModule.renderToStream(request, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = await consumeStream(result.stream); + const elapsed = Date.now() - startTime; + + expect(elapsed).toBeLessThan(STREAM_TIMEOUT); + expect(result.statusCode).toBe(200); + expect(html).toContain("<!DOCTYPE html>"); + expect(html).toContain("test-key"); + }); + + it("does NOT call API during SSR for ssr:false authenticated routes", { timeout: 6000 }, async () => { + mockApiClient.getValue.mockClear(); + const request = new Request("http://localhost/keys/my-test-key"); + + const result = await routerModule.renderToStream(request, { + assetsUrl: config.ui.url, + runtimeConfig: { + env: config.env, + account: config.account, + title: config.title, + hostUrl: config.hostUrl, + apiBase: "/api", + rpcBase: "/api/rpc", + assetsUrl: config.ui.url, + }, + }); + + const html = await consumeStream(result.stream); + + expect(html).toContain("my-test-key"); + expect(mockApiClient.getValue).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/host/vitest.config.ts b/host/vitest.config.ts new file mode 100644 index 0000000..0092c5f --- /dev/null +++ b/host/vitest.config.ts @@ -0,0 +1,15 @@ +import tsconfigPaths from "vite-tsconfig-paths"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "node", + testTimeout: 30000, + include: ["tests/**/*.test.ts"], + }, + plugins: [ + tsconfigPaths({ + projects: ["./tsconfig.json"], + }), + ], +}); diff --git a/package.json b/package.json index 26c8190..4267db7 100644 --- a/package.json +++ b/package.json @@ -1,39 +1,55 @@ { "name": "monorepo", "private": true, - "workspaces": [ - "api", - "host", - "ui" - ], - "scripts": { - "dev": "turbo dev", - "dev:ui": "USE_REMOTE_API=true turbo dev --filter=host --filter=ui", - "dev:api": "USE_REMOTE_UI=true turbo dev --filter=host --filter=api", - "start": "turbo preview --filter=host", - "build": "turbo build", - "build:api": "turbo build --filter=api", - "build:host": "turbo build --filter=host", - "build:ui": "turbo build --filter=ui", - "deploy": "NODE_ENV=production turbo build --filter=ui --filter=api", - "typecheck": "turbo typecheck", - "db:push": "turbo db:push", - "db:studio": "turbo db:studio", - "db:generate": "turbo db:generate", - "db:migrate": "turbo db:migrate" + "workspaces": { + "packages": [ + "api", + "ui", + "host" + ], + "catalog": { + "react": "^19.2.3", + "react-dom": "^19.2.3", + "@tanstack/react-query": "^5.90.11", + "@tanstack/react-router": "^1.153.2", + "near-kit": "^0.10.0", + "@hot-labs/near-connect": "^0.8.2", + "drizzle-orm": "^0.45.1", + "drizzle-kit": "^0.31.8", + "@libsql/client": "^0.17.0", + "better-auth": "^1.4.15", + "better-near-auth": "^0.3.4", + "every-plugin": "0.8.8", + "typescript": "^5.9.3", + "vitest": "^4.0.17", + "@types/node": "^25.0.3", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "effect": "^3.19.15" + } }, - "devDependencies": { - "@types/node": "^25.0.9", - "turbo": "^2.7.5" + "scripts": { + "init": "bun run db:migrate", + "bos": "bunx everything-dev", + "dev": "bunx everything-dev dev", + "dev:ui": "bunx everything-dev dev --ui", + "dev:api": "bunx everything-dev dev --api", + "dev:host": "bunx everything-dev dev --host", + "dev:proxy": "bunx everything-dev dev --proxy", + "build": "bunx everything-dev build", + "build:api": "bun run --cwd api rsbuild build", + "build:host": "bun run --cwd host rsbuild build", + "build:ui": "bun run --cwd ui rsbuild build", + "deploy": "NODE_ENV=production bun run build:ui && bun run build:api", + "typecheck": "bun run --cwd host tsc --noEmit && bun run --cwd ui tsc --noEmit && bun run --cwd api tsc --noEmit", + "start": "NODE_ENV=production bunx everything-dev start --no-interactive", + "db:push": "bun run --cwd host drizzle-kit push", + "db:studio": "bun run --cwd host drizzle-kit studio", + "db:generate": "bun run --cwd host drizzle-kit generate", + "db:migrate": "bun run --cwd host drizzle-kit migrate" }, "packageManager": "bun@1.2.20", "dependencies": { - "@tanstack/router-plugin": "^1.151.1", - "drizzle-kit": "^0.31.8", - "esbuild": "^0.27.2", - "hono": "^4.11.4", - "tsx": "^4.21.0", - "vite-tsconfig-paths": "^6.0.4", - "vitest": "^4.0.17" + "@types/bun": "^1.3.6" } -} \ No newline at end of file +} diff --git a/turbo.json b/turbo.json deleted file mode 100644 index 385303e..0000000 --- a/turbo.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "https://turbo.build/schema.json", - "ui": "tui", - "envMode": "loose", - "globalPassThroughEnv": ["USE_REMOTE_API", "USE_REMOTE_UI", "NODE_ENV"], - "tasks": { - "dev": { - "cache": false, - "persistent": true - }, - "build": { - "dependsOn": ["^build"], - "outputs": ["dist/**", ".rsbuild/**"] - }, - "typecheck": { - "dependsOn": ["^typecheck"] - }, - "preview": { - - }, - "test": { - "dependsOn": ["^build"] - }, - "db:push": { - "cache": false - }, - "db:studio": { - "cache": false, - "persistent": true - }, - "db:generate": { - "cache": false - }, - "db:migrate": { - "cache": false - } - } -} diff --git a/ui/.cta.json b/ui/.cta.json index 4921e9c..5e01f18 100644 --- a/ui/.cta.json +++ b/ui/.cta.json @@ -1,5 +1,5 @@ { - "projectName": "agency", + "projectName": "demo", "mode": "file-router", "typescript": true, "tailwind": true, diff --git a/ui/README.md b/ui/README.md index 5d21b7f..6e81e97 100644 --- a/ui/README.md +++ b/ui/README.md @@ -1,15 +1,6 @@ # ui -Frontend application for NEAR AI chat with streaming responses and KV store demo. - -## Tech Stack - -- **Framework**: React 19 -- **Routing**: TanStack Router (file-based) -- **Data**: TanStack Query + oRPC client -- **Styling**: Tailwind CSS v4 -- **Build**: Rsbuild + Module Federation -- **Auth**: better-auth client +Remote frontend module with TanStack Router and SSR support. ## Module Federation @@ -17,18 +8,72 @@ Exposed as remote module for host consumption via `remoteEntry.js`: | Export | Path | Description | |--------|------|-------------| -| `./App` | `bootstrap.tsx` | Main app component | -| `./Router` | `router.tsx` | TanStack Router instance | +| `./Router` | `router.tsx` | TanStack Router instance (client) | +| `./Hydrate` | `hydrate.tsx` | Client hydration entry | | `./components` | `components/index.ts` | Reusable UI components | | `./providers` | `providers/index.tsx` | Context providers | +| `./hooks` | `hooks/index.ts` | React hooks | | `./types` | `types/index.ts` | TypeScript types | +**SSR Build** also exposes: +- `./Router` → `router.server.tsx` (server-side rendering) + **Shared dependencies** (singleton): - `react`, `react-dom` - `@tanstack/react-query`, `@tanstack/react-router` +- `@hot-labs/near-connect`, `near-kit` + +## Route Protection + +File-based routing with auth guards via TanStack Router: + +- `_authenticated.tsx` - Requires login, redirects to `/login` +- `_authenticated/_admin.tsx` - Requires admin role + +## Directory Structure + +``` +ui/ +├── src/ +│ ├── router.tsx # Client router +│ ├── router.server.tsx # Server router (SSR) +│ ├── hydrate.tsx # Client hydration entry +│ ├── components/ +│ │ ├── index.ts # Public component exports +│ │ ├── chat/ # Chat feature components +│ │ ├── kv/ # Key-value editor +│ │ └── ui/ # shadcn/ui primitives +│ ├── hooks/ # React hooks +│ ├── lib/ # Utilities (auth-client, utils) +│ ├── providers/ # Context providers +│ ├── routes/ # TanStack file-based routes +│ ├── types/ # TypeScript types +│ └── utils/ # API client (oRPC, streaming) +├── rsbuild.config.ts # Build configuration +└── package.json +``` + +## Tech Stack -**Configuration** (`bos.config.json`): +- **Framework**: React 19 +- **Routing**: TanStack Router (file-based) +- **Data**: TanStack Query + oRPC client +- **Styling**: Tailwind CSS v4 + shadcn/ui +- **Build**: Rsbuild + Module Federation +- **Auth**: better-auth client + +## Available Scripts + +- `bun dev` - Start dev server (port 3002) +- `bun build` - Build for production (client + server) +- `bun build:client` - Build client bundle only +- `bun build:server` - Build SSR bundle only +- `bun typecheck` - Type checking + +## Configuration + +**bos.config.json**: ```json { @@ -36,7 +81,8 @@ Exposed as remote module for host consumption via `remoteEntry.js`: "ui": { "name": "ui", "development": "http://localhost:3002", - "production": "https://", + "production": "https://cdn.example.com/ui", + "ssr": "https://cdn.example.com/ui-ssr", "exposes": { "App": "./App", "components": "./components", @@ -48,21 +94,9 @@ Exposed as remote module for host consumption via `remoteEntry.js`: } ``` -## Available Scripts - -- `bun dev` - Start dev server (port 3002) -- `bun build` - Build for production -- `bun preview` - Preview production build -- `bun typecheck` - Type checking +## Component Conventions -## Project Structure - -- `src/routes/` - File-based routes (TanStack Router) - - `/` - Chat interface (canonical) - - `/chat` - Redirect alias to `/` - - `/dashboard` - Admin dashboard (role-gated) -- `src/components/` - UI components (shadcn/ui) - - `chat/` - Chat UI components - - `kv/` - Key-value store demo -- `src/utils/` - API client (oRPC) -- `src/lib/` - Auth client (Better-Auth + NEAR) +- All component files use **kebab-case** naming: `chat-input.tsx`, `user-nav.tsx` +- UI primitives in `components/ui/` (shadcn/ui) +- Feature components in `components/<feature>/` +- Export public components via `components/index.ts` diff --git a/ui/index.html b/ui/index.html deleted file mode 100644 index be1ac68..0000000 --- a/ui/index.html +++ /dev/null @@ -1,52 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" /> - <meta name="color-scheme" content="light dark" /> - <meta name="format-detection" content="telephone=no" /> - - <!-- Favicon --> - <link rel="icon" type="image/x-icon" href="/favicon.ico" /> - <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" /> - <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" /> - <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" /> - <link rel="manifest" href="/manifest.json" /> - - <!-- Preconnect to font origins --> - <link rel="preconnect" href="https://fonts.googleapis.com" /> - <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> - - <!-- Theme --> - <meta name="theme-color" content="#171717" /> - - <!-- Theme flash prevention - runs before any render --> - <script> - (function() { - var t = localStorage.getItem('theme'); - if (t === 'dark' || (!t && window.matchMedia('(prefers-color-scheme: dark)').matches)) { - document.documentElement.classList.add('dark'); - } - })(); - </script> - - <style> - /* Minimal shell reset - matches host for dev consistency */ - *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } - html { height: 100%; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; } - body { - min-height: 100%; - -webkit-tap-highlight-color: transparent; - touch-action: manipulation; - } - #app { min-height: 100vh; } - @supports (min-height: 100dvh) { - #app { min-height: 100dvh; } - } - </style> - </head> - <body> - <div id="app"></div> - <script type="module" src="/src/main.tsx"></script> - </body> -</html> diff --git a/ui/package.json b/ui/package.json index 8810c46..71c1324 100644 --- a/ui/package.json +++ b/ui/package.json @@ -5,7 +5,9 @@ "type": "module", "scripts": { "dev": "rsbuild dev", - "build": "rsbuild build", + "build": "bun run build:client && bun run build:server", + "build:client": "BUILD_TARGET=client rsbuild build", + "build:server": "BUILD_TARGET=server rsbuild build", "preview": "rsbuild preview", "test": "vitest run", "typecheck": "tsc --noEmit", @@ -13,11 +15,8 @@ }, "dependencies": { "@hot-labs/near-connect": "^0.8.2", - "@orpc/client": "^1.13.4", + "@orpc/client": "^1.12.3", "@orpc/contract": "^1.13.4", - "@orpc/react-query": "^1.13.4", - "@orpc/server": "^1.13.4", - "@orpc/tanstack-query": "^1.13.4", "@radix-ui/react-aspect-ratio": "^1.1.8", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-checkbox": "^1.3.3", @@ -31,55 +30,52 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", - "@reactflow/background": "^11.3.14", - "@reactflow/controls": "^11.2.14", - "@reactflow/minimap": "^11.7.14", - "@tanstack/react-devtools": "^0.7.11", - "@tanstack/react-query": "^5.90.19", - "@tanstack/react-query-devtools": "^5.91.2", - "@tanstack/react-router": "^1.151.1", - "@tanstack/react-router-devtools": "^1.151.1", + "@tanstack/react-devtools": "^0.9.2", + "@tanstack/react-query": "catalog:", + "@tanstack/react-query-devtools": "^5.91.1", + "@tanstack/react-router": "catalog:", + "@tanstack/react-router-devtools": "^1.157.15", "@tanstack/react-table": "^8.21.3", - "better-auth": "^1.4.14", - "better-near-auth": "^0.3.4", + "better-auth": "catalog:", + "better-near-auth": "catalog:", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.544.0", - "near-kit": "^0.6.3", + "lucide-react": "^0.563.0", + "near-kit": "^0.10.0", "next-themes": "^0.4.6", "react": "^19.2.3", "react-dom": "^19.2.3", - "reactflow": "^11.11.4", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "tw-animate-css": "^1.4.0", - "zustand": "^5.0.10" + "zustand": "^5.0.9" }, "peerDependencies": { - "@hot-labs/near-connect": "^0.8.2", + "@hot-labs/near-connect": "^0.8.x", "@tanstack/react-query": "^5.x", "@tanstack/react-router": "^1.x", - "near-kit": "^0.6.x", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "near-kit": "^0.10.0", + "react": "^19.2.0", + "react-dom": "^19.2.0" }, "devDependencies": { - "@module-federation/enhanced": "^0.21.6", - "@module-federation/rsbuild-plugin": "^0.21.6", - "@rsbuild/core": "^1.7.2", - "@rsbuild/plugin-react": "^1.4.3", - "@tailwindcss/postcss": "^4.1.18", - "@tanstack/router-plugin": "^1.151.1", + "every-plugin": "catalog:", + "@module-federation/enhanced": "^0.23.0", + "@module-federation/node": "^2.7.26", + "@module-federation/rsbuild-plugin": "^0.23.0", + "@rsbuild/core": "^1.6.12", + "@rsbuild/plugin-react": "^1.4.2", + "@tailwindcss/postcss": "^4.1.17", + "@tanstack/router-plugin": "^1.157.15", "@testing-library/dom": "^10.4.1", - "@testing-library/react": "^16.3.1", - "@types/node": "^22.19.7", - "@types/react": "^19.2.8", - "@types/react-dom": "^19.2.3", - "jsdom": "^27.4.0", - "tailwindcss": "^4.1.18", - "typescript": "^5.9.3", - "vitest": "^3.2.4", - "web-vitals": "^5.1.0", - "zephyr-rsbuild-plugin": "^0.1.4" + "@testing-library/react": "^16.3.2", + "@types/node": "catalog:", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "jsdom": "^27.2.0", + "tailwindcss": "^4.1.17", + "typescript": "catalog:", + "vitest": "catalog:", + "zephyr-rsbuild-plugin": "^0.1.2" } } diff --git a/ui/rsbuild.config.ts b/ui/rsbuild.config.ts index bb8a4a9..b099327 100644 --- a/ui/rsbuild.config.ts +++ b/ui/rsbuild.config.ts @@ -1,10 +1,12 @@ import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; +import { ModuleFederationPlugin } from "@module-federation/enhanced/rspack"; import { pluginModuleFederation } from "@module-federation/rsbuild-plugin"; import { defineConfig } from "@rsbuild/core"; import { pluginReact } from "@rsbuild/plugin-react"; import { TanStackRouterRspack } from "@tanstack/router-plugin/rspack"; +import { getUISharedDependencies } from "every-plugin/build/rspack"; import { withZephyr } from "zephyr-rsbuild-plugin"; import pkg from "./package.json"; @@ -12,11 +14,10 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const normalizedName = pkg.name; const isProduction = process.env.NODE_ENV === "production"; +const buildTarget = process.env.BUILD_TARGET as "client" | "server" | undefined; +const isServerBuild = buildTarget === "server"; -const configPath = path.resolve(__dirname, "../bos.config.json"); -const bosConfig = JSON.parse(fs.readFileSync(configPath, "utf8")); - -function updateHostConfig(_name: string, url: string) { +function updateBosConfig(field: "production" | "ssr", url: string) { try { const configPath = path.resolve(__dirname, "../bos.config.json"); const config = JSON.parse(fs.readFileSync(configPath, "utf8")); @@ -26,9 +27,9 @@ function updateHostConfig(_name: string, url: string) { return; } - config.app.ui.production = url; - fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n"); - console.log(" ✅ Updated bos.config.json: app.ui.production"); + config.app.ui[field] = url; + fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`); + console.log(` ✅ Updated bos.config.json: app.ui.${field}`); } catch (err) { console.error( " ❌ Failed to update bos.config.json:", @@ -37,150 +38,160 @@ function updateHostConfig(_name: string, url: string) { } } -const plugins = [ - pluginReact(), - pluginModuleFederation({ - name: normalizedName, - filename: "remoteEntry.js", - dts: false, - exposes: { - "./App": "./src/bootstrap.tsx", - "./Router": "./src/router.tsx", - "./components": "./src/components/index.ts", - "./providers": "./src/providers/index.tsx", - "./hooks": "./src/hooks/index.ts", - "./types": "./src/types/index.ts", - }, - shared: { - react: { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies.react, +const uiSharedDeps = getUISharedDependencies(); + +function createClientConfig() { + const plugins = [ + pluginReact(), + pluginModuleFederation({ + name: normalizedName, + filename: "remoteEntry.js", + dts: false, + exposes: { + "./Router": "./src/router.tsx", + "./Hydrate": "./src/hydrate.tsx", + "./components": "./src/components/index.ts", + "./providers": "./src/providers/index.tsx", + "./hooks": "./src/hooks/index.ts", + "./types": "./src/types/index.ts", }, - "react-dom": { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies["react-dom"], + shared: uiSharedDeps, + }), + ]; + + if (isProduction) { + plugins.push( + withZephyr({ + hooks: { + onDeployComplete: (info) => { + console.log("🚀 UI Client Deployed:", info.url); + updateBosConfig("production", info.url); + }, + }, + }) + ); + } + + return defineConfig({ + plugins, + source: { + entry: { + index: "./src/hydrate.tsx", }, - "@tanstack/react-query": { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies["@tanstack/react-query"], + }, + resolve: { + alias: { + "@": "./src", }, - "@tanstack/react-router": { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies["@tanstack/react-router"], + }, + dev: { + lazyCompilation: false, + progressBar: false, + client: { + overlay: false, }, - "@hot-labs/near-connect": { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies["@hot-labs/near-connect"], + }, + server: { + port: 3002, + printUrls: ({ urls }) => urls.filter((url) => url.includes("localhost")), + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type", }, - "near-kit": { - singleton: true, - eager: true, - requiredVersion: pkg.dependencies["near-kit"], + publicDir: { + name: "dist", + copyOnBuild: false, }, }, - }), -]; - -if (isProduction) { - plugins.push( - withZephyr({ - hooks: { - onDeployComplete: (info) => { - console.log("🚀 UI Deployed:", info.url); - updateHostConfig(normalizedName, info.url); + tools: { + rspack: { + target: "web", + output: { + uniqueName: normalizedName, }, + infrastructureLogging: { level: "error" }, + stats: "errors-warnings", + plugins: [ + TanStackRouterRspack({ + target: "react", + autoCodeSplitting: true, + }), + ], }, - }) - ); -} - -export default defineConfig({ - plugins, - source: { - define: { - "import.meta.env.PUBLIC_ACCOUNT_ID": JSON.stringify(bosConfig.account), - }, - entry: { - index: "./src/main.tsx", - remote: "./src/remote.tsx", }, - }, - resolve: { - alias: { - "@": "./src", + output: { + distPath: { root: "dist", css: "static/css", js: "static/js" }, + assetPrefix: "auto", + filename: { js: "[name].js", css: "style.css" }, + copy: [{ from: path.resolve(__dirname, "public"), to: "./" }], }, - }, - html: { - template: "./index.html", - }, - dev: { - lazyCompilation: false, - progressBar: false, - client: { - overlay: false, - }, - }, - server: { - port: 3002, - printUrls: ({ urls }) => urls.filter((url) => url.includes("localhost")), - headers: { - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "GET, POST, OPTIONS", - "Access-Control-Allow-Headers": "Content-Type", - }, - }, - tools: { - rspack: { - target: "web", - output: { - library: { - name: normalizedName, - type: "var", + }); +} + +function createServerConfig() { + const plugins = [pluginReact()]; + + if (isProduction) { + plugins.push( + withZephyr({ + hooks: { + onDeployComplete: (info) => { + console.log("🚀 UI SSR Deployed:", info.url); + updateBosConfig("ssr", info.url); + }, }, + }) + ); + } + + return defineConfig({ + plugins, + source: { + entry: { + index: "./src/router.server.tsx", }, - externalsType: "module", - externals: { - fs: "commonjs fs", - path: "commonjs path", - crypto: "commonjs crypto", - "node:fs": "commonjs node:fs", - "node:fs/promises": "commonjs node:fs/promises", - "node:path": "commonjs node:path", - "node:crypto": "commonjs node:crypto", - }, - infrastructureLogging: { - level: "error", + }, + resolve: { + alias: { + "@": "./src", + "@tanstack/react-devtools": false, + "@tanstack/react-router-devtools": false, }, - stats: "errors-warnings", - plugins: [ - TanStackRouterRspack({ - target: "react", - autoCodeSplitting: true, - }), - ], }, - }, - output: { - distPath: { - root: 'dist', + tools: { + rspack: { + target: "async-node", + output: { + uniqueName: `${normalizedName}_server`, + publicPath: "/", + library: { type: "commonjs-module" }, + }, + externals: [ + /^node:/, + ], + infrastructureLogging: { level: "error" }, + stats: "errors-warnings", + plugins: [ + TanStackRouterRspack({ target: "react", autoCodeSplitting: false }), + new ModuleFederationPlugin({ + name: normalizedName, + filename: "remoteEntry.server.js", + dts: false, + runtimePlugins: [require.resolve("@module-federation/node/runtimePlugin")], + library: { type: "commonjs-module" }, + exposes: { "./Router": "./src/router.server.tsx" }, + shared: uiSharedDeps, + }), + ], + }, }, - assetPrefix: "auto", - // assetPrefix: isProduction - // ? `${bosConfig.app.ui.production}/` - // : "auto", - filename: { - css: "static/css/[name].css", + output: { + distPath: { root: "dist" }, + assetPrefix: "auto", + cleanDistPath: false, }, - copy: [ - { - from: path.resolve(__dirname, "public"), - to: "./", - }, - ], - }, -}); + }); +} + +export default isServerBuild ? createServerConfig() : createClientConfig(); diff --git a/ui/src/assets/logo_full.png b/ui/src/assets/logo_full.png deleted file mode 100644 index b12422e7a0f3c106c8a1238a27b0b84d7f76831a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79058 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 E0H*81HUIzs diff --git a/ui/src/bootstrap.tsx b/ui/src/bootstrap.tsx deleted file mode 100644 index 0dfe1e1..0000000 --- a/ui/src/bootstrap.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { createRouter, RouterProvider } from "@tanstack/react-router"; -import { HydrationBoundary, type DehydratedState } from "@tanstack/react-query"; -import { ThemeProvider } from "next-themes"; -import { StrictMode } from "react"; -import { Toaster } from "sonner"; - -import * as TanStackQueryProvider from "./integrations/tanstack-query/root-provider.tsx"; - -import { routeTree } from "./routeTree.gen.ts"; - -import "./styles.css"; - -declare global { - interface Window { - __DEHYDRATED_STATE__?: DehydratedState; - } -} - -const TanStackQueryProviderContext = TanStackQueryProvider.getContext(); -const dehydratedState = typeof window !== 'undefined' ? window.__DEHYDRATED_STATE__ : undefined; -function NotFoundComponent() { - return ( - <div className="min-h-screen flex items-center justify-center bg-background"> - <div className="text-center"> - <h1 className="text-4xl font-bold text-foreground mb-4">404</h1> - <p className="text-muted-foreground mb-8">Page not found</p> - <a - href="/" - className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2" - > - Go Home - </a> - </div> - </div> - ); -} - -function ErrorComponent({ error }: { error: Error }) { - return ( - <div className="min-h-screen flex items-center justify-center bg-background"> - <div className="text-center"> - <h1 className="text-4xl font-bold text-foreground mb-4">Oops!</h1> - <p className="text-muted-foreground mb-4">Something went wrong</p> - <details className="text-sm text-muted-foreground bg-muted p-4 rounded mb-8"> - <summary className="cursor-pointer">Error Details</summary> - <pre className="mt-2 whitespace-pre-wrap text-left"> - {error.message} - </pre> - </details> - <button - type="button" - onClick={() => window.location.reload()} - className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2" - > - Reload Page - </button> - </div> - </div> - ); -} - -const router = createRouter({ - routeTree, - context: { - ...TanStackQueryProviderContext, - }, - defaultPreload: "intent", - scrollRestoration: true, - defaultStructuralSharing: true, - defaultPreloadStaleTime: 0, - defaultNotFoundComponent: NotFoundComponent, - defaultErrorComponent: ErrorComponent, -}); - -declare module "@tanstack/react-router" { - interface Register { - router: typeof router; - } -} - -export function App() { - return ( - <StrictMode> - <TanStackQueryProvider.Provider {...TanStackQueryProviderContext}> - <HydrationBoundary state={dehydratedState}> - <ThemeProvider attribute="class" defaultTheme="system" enableSystem> - <RouterProvider router={router} /> - <Toaster position="bottom-right" richColors closeButton /> - </ThemeProvider> - </HydrationBoundary> - </TanStackQueryProvider.Provider> - </StrictMode> - ); -} - -export default App; diff --git a/ui/src/components/chat/ChatInput.tsx b/ui/src/components/chat/chat-input.tsx similarity index 100% rename from ui/src/components/chat/ChatInput.tsx rename to ui/src/components/chat/chat-input.tsx diff --git a/ui/src/components/chat/ChatMessage.tsx b/ui/src/components/chat/chat-message.tsx similarity index 100% rename from ui/src/components/chat/ChatMessage.tsx rename to ui/src/components/chat/chat-message.tsx diff --git a/ui/src/components/chat/ChatPage.tsx b/ui/src/components/chat/chat-page.tsx similarity index 98% rename from ui/src/components/chat/ChatPage.tsx rename to ui/src/components/chat/chat-page.tsx index 9b3dab5..13d675b 100644 --- a/ui/src/components/chat/ChatPage.tsx +++ b/ui/src/components/chat/chat-page.tsx @@ -11,8 +11,8 @@ import { isCompleteData, isErrorData, } from "../../utils/stream"; -import { ChatMessage } from "../../components/chat/ChatMessage"; -import { ChatInput } from "../../components/chat/ChatInput"; +import { ChatMessage } from "./chat-message"; +import { ChatInput } from "./chat-input"; interface Message { id: string; diff --git a/ui/src/components/kv/KVEditor.tsx b/ui/src/components/kv/kv-editor.tsx similarity index 100% rename from ui/src/components/kv/KVEditor.tsx rename to ui/src/components/kv/kv-editor.tsx diff --git a/ui/src/components/ui/markdown.tsx b/ui/src/components/ui/markdown.tsx new file mode 100644 index 0000000..93cde67 --- /dev/null +++ b/ui/src/components/ui/markdown.tsx @@ -0,0 +1,189 @@ +import { cn } from "@/lib/utils"; + +interface MarkdownProps { + content: string; + className?: string; +} + +export function Markdown({ content, className }: MarkdownProps) { + const html = parseMarkdown(content); + + return ( + // biome-ignore lint/security/noDangerouslySetInnerHtml: markdown rendering requires HTML injection + <article + className={cn( + "prose prose-neutral dark:prose-invert max-w-none", + "prose-headings:font-semibold prose-headings:tracking-tight", + "prose-h1:text-3xl prose-h1:mb-6", + "prose-h2:text-2xl prose-h2:mt-8 prose-h2:mb-4 prose-h2:border-b prose-h2:border-border prose-h2:pb-2", + "prose-h3:text-xl prose-h3:mt-6 prose-h3:mb-3", + "prose-p:text-muted-foreground prose-p:leading-relaxed", + "prose-a:text-primary prose-a:no-underline hover:prose-a:underline", + "prose-code:bg-muted prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded prose-code:text-sm prose-code:font-mono prose-code:before:content-none prose-code:after:content-none", + "prose-pre:bg-muted prose-pre:border prose-pre:border-border prose-pre:rounded-lg", + "prose-blockquote:border-l-primary prose-blockquote:bg-muted/30 prose-blockquote:py-1 prose-blockquote:not-italic", + "prose-li:text-muted-foreground", + "prose-table:border prose-table:border-border", + "prose-th:bg-muted prose-th:border prose-th:border-border prose-th:px-4 prose-th:py-2", + "prose-td:border prose-td:border-border prose-td:px-4 prose-td:py-2", + "prose-hr:border-border", + className + )} + dangerouslySetInnerHTML={{ __html: html }} + /> + ); +} + +function parseMarkdown(md: string): string { + let html = md; + + html = html.replace(/^### (.*$)/gim, '<h3>$1</h3>'); + html = html.replace(/^## (.*$)/gim, '<h2>$1</h2>'); + html = html.replace(/^# (.*$)/gim, '<h1>$1</h1>'); + + html = html.replace(/\*\*\*(.*?)\*\*\*/gim, '<strong><em>$1</em></strong>'); + html = html.replace(/\*\*(.*?)\*\*/gim, '<strong>$1</strong>'); + html = html.replace(/\*(.*?)\*/gim, '<em>$1</em>'); + + html = html.replace(/`{3}(\w*)\n([\s\S]*?)\n`{3}/gim, (_, lang, code) => { + const escapedCode = escapeHtml(code); + return `<pre><code class="language-${lang || 'text'}">${escapedCode}</code></pre>`; + }); + html = html.replace(/`([^`]+)`/gim, (_, code) => { + return `<code>${escapeHtml(code)}</code>`; + }); + + html = html.replace(/^\|(.+)\|$/gim, (match) => { + return match; + }); + + const lines = html.split('\n'); + const processedLines: string[] = []; + let inTable = false; + let tableRows: string[] = []; + let inList = false; + let listItems: string[] = []; + let listType: 'ul' | 'ol' = 'ul'; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + + if (line.match(/^\|(.+)\|$/)) { + if (!inTable) { + inTable = true; + tableRows = []; + } + + if (line.match(/^\|[\s\-:|]+\|$/)) { + continue; + } + tableRows.push(line); + } else { + if (inTable) { + processedLines.push(buildTable(tableRows)); + inTable = false; + tableRows = []; + } + + const ulMatch = line.match(/^[\s]*[-*]\s+(.+)$/); + const olMatch = line.match(/^[\s]*\d+\.\s+(.+)$/); + + if (ulMatch) { + if (!inList || listType !== 'ul') { + if (inList) { + processedLines.push(buildList(listItems, listType)); + } + inList = true; + listType = 'ul'; + listItems = []; + } + listItems.push(ulMatch[1]); + } else if (olMatch) { + if (!inList || listType !== 'ol') { + if (inList) { + processedLines.push(buildList(listItems, listType)); + } + inList = true; + listType = 'ol'; + listItems = []; + } + listItems.push(olMatch[1]); + } else { + if (inList) { + processedLines.push(buildList(listItems, listType)); + inList = false; + listItems = []; + } + + if (line.match(/^>\s*(.*)/)) { + const quoteContent = line.replace(/^>\s*/, ''); + processedLines.push(`<blockquote><p>${quoteContent}</p></blockquote>`); + } else if (line.match(/^---+$/)) { + processedLines.push('<hr />'); + } else if (line.trim() === '') { + processedLines.push(''); + } else if (!line.match(/^<h[1-6]>/)) { + processedLines.push(`<p>${line}</p>`); + } else { + processedLines.push(line); + } + } + } + } + + if (inTable) { + processedLines.push(buildTable(tableRows)); + } + if (inList) { + processedLines.push(buildList(listItems, listType)); + } + + html = processedLines.join('\n'); + + html = html.replace( + /\[([^\]]+)\]\(([^)]+)\)/gim, + '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>' + ); + + return html; +} + +function buildTable(rows: string[]): string { + if (rows.length === 0) return ''; + + const headerRow = rows[0]; + const dataRows = rows.slice(1); + + const headerCells = headerRow + .split('|') + .filter((c) => c.trim()) + .map((c) => `<th>${c.trim()}</th>`) + .join(''); + + const bodyRows = dataRows + .map((row) => { + const cells = row + .split('|') + .filter((c) => c.trim()) + .map((c) => `<td>${c.trim()}</td>`) + .join(''); + return `<tr>${cells}</tr>`; + }) + .join(''); + + return `<div class="overflow-x-auto"><table><thead><tr>${headerCells}</tr></thead><tbody>${bodyRows}</tbody></table></div>`; +} + +function buildList(items: string[], type: 'ul' | 'ol'): string { + const listItems = items.map((item) => `<li>${item}</li>`).join(''); + return `<${type}>${listItems}</${type}>`; +} + +function escapeHtml(text: string): string { + return text + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} diff --git a/ui/src/components/user-nav.tsx b/ui/src/components/user-nav.tsx new file mode 100644 index 0000000..e3830ea --- /dev/null +++ b/ui/src/components/user-nav.tsx @@ -0,0 +1,49 @@ +import { useQuery } from "@tanstack/react-query"; +import { Link, useRouter } from "@tanstack/react-router"; +import { authClient } from "../lib/auth-client"; +import { sessionQueryOptions } from "../lib/session"; +import { queryClient } from "../utils/orpc"; + +export function UserNav() { + const router = useRouter(); + const { data: session } = useQuery(sessionQueryOptions); + const accountId = session?.user?.id; + + const handleSignOut = async () => { + try { + await authClient.signOut(); + await authClient.near.disconnect(); + queryClient.invalidateQueries({ queryKey: ["session"] }); + router.invalidate(); + window.location.href = "/"; + } catch (error) { + console.error("Sign out error:", error); + } + }; + + if (accountId) { + return ( + <> + <span className="text-xs text-muted-foreground font-mono"> + {accountId} + </span> + <button + type="button" + onClick={handleSignOut} + className="text-xs text-muted-foreground hover:text-foreground transition-colors font-mono" + > + sign out + </button> + </> + ); + } + + return ( + <Link + to="/login" + className="text-xs text-muted-foreground hover:text-foreground transition-colors font-mono" + > + login + </Link> + ); +} diff --git a/ui/src/env.d.ts b/ui/src/env.d.ts index 2155f2d..ae4ce79 100644 --- a/ui/src/env.d.ts +++ b/ui/src/env.d.ts @@ -1,15 +1,8 @@ /// <reference types="@rsbuild/core/types" /> -interface ImportMetaEnv { - readonly PUBLIC_ACCOUNT_ID: string; -} - -interface ImportMeta { - readonly env: ImportMetaEnv; -} - interface RuntimeConfig { env: string; + account: string; title: string; hostUrl: string; ui: { diff --git a/ui/src/hydrate.tsx b/ui/src/hydrate.tsx new file mode 100644 index 0000000..976a2c4 --- /dev/null +++ b/ui/src/hydrate.tsx @@ -0,0 +1,36 @@ +import type { ClientRuntimeConfig } from "./types"; + +export async function hydrate() { + console.log("[Hydrate] Starting..."); + + const runtimeConfig = (window as { __RUNTIME_CONFIG__?: ClientRuntimeConfig }) + .__RUNTIME_CONFIG__; + if (!runtimeConfig) { + console.error("[Hydrate] No runtime config found"); + return; + } + + const { hydrateRoot } = await import("react-dom/client"); + const { RouterClient } = await import("@tanstack/react-router/ssr/client"); + const { QueryClientProvider } = await import("@tanstack/react-query"); + const { createRouter } = await import("./router"); + + const { router, queryClient } = createRouter({ + context: { + assetsUrl: runtimeConfig.assetsUrl, + runtimeConfig, + }, + }); + + console.log("[Hydrate] Calling hydrateRoot..."); + hydrateRoot( + document, + <QueryClientProvider client={queryClient}> + <RouterClient router={router} /> + </QueryClientProvider>, + ); + + console.log("[Hydrate] Complete!"); +} + +export default hydrate; diff --git a/ui/src/integrations/api/index.ts b/ui/src/integrations/api/index.ts deleted file mode 100644 index 7e60e83..0000000 --- a/ui/src/integrations/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -// keep \ No newline at end of file diff --git a/ui/src/integrations/tanstack-query/root-provider.tsx b/ui/src/integrations/tanstack-query/root-provider.tsx deleted file mode 100644 index d2b91f3..0000000 --- a/ui/src/integrations/tanstack-query/root-provider.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; - -export function getContext() { - const queryClient = new QueryClient({ - defaultOptions: { - queries: { - staleTime: 5 * 60 * 1000, - gcTime: 30 * 60 * 1000, - refetchOnWindowFocus: false, - retry: 1, - }, - }, - }); - return { - queryClient, - }; -} - -export function Provider({ - children, - queryClient, -}: { - children: React.ReactNode; - queryClient: QueryClient; -}) { - return ( - <QueryClientProvider client={queryClient}>{children}</QueryClientProvider> - ); -} diff --git a/ui/src/lib/auth-client.ts b/ui/src/lib/auth-client.ts index d02a221..41d55f1 100644 --- a/ui/src/lib/auth-client.ts +++ b/ui/src/lib/auth-client.ts @@ -1,24 +1,35 @@ import { adminClient } from "better-auth/client/plugins"; -import { createAuthClient } from "better-auth/react"; +import { createAuthClient as createBetterAuthClient } from "better-auth/react"; import { siwnClient } from "better-near-auth/client"; -function getBaseURL(): string { - if (typeof window !== 'undefined' && window.__RUNTIME_CONFIG__?.hostUrl) { - return window.__RUNTIME_CONFIG__.hostUrl; - } - if (typeof window !== 'undefined') { - return window.location.origin; +function getAuthBaseUrl(): string { + if (typeof window === "undefined") return ""; + return window.__RUNTIME_CONFIG__?.hostUrl ?? window.location.origin; +} + +function createAuthClient() { + return createBetterAuthClient({ + baseURL: getAuthBaseUrl(), + fetchOptions: { credentials: "include" }, + plugins: [ + siwnClient({ + domain: typeof window !== "undefined" + ? (window.__RUNTIME_CONFIG__?.account ?? "every.near") + : "every.near", + networkId: "mainnet", + }), + adminClient(), + ], + }); +} + +let _authClient: ReturnType<typeof createAuthClient> | undefined; + +export function getAuthClient() { + if (_authClient === undefined) { + _authClient = createAuthClient(); } - return ''; + return _authClient; } -export const authClient = createAuthClient({ - baseURL: getBaseURL(), - plugins: [ - siwnClient({ - domain: import.meta.env.PUBLIC_ACCOUNT_ID || "every.near", - networkId: "mainnet", - }), - adminClient(), - ], -}); +export const authClient = getAuthClient(); diff --git a/ui/src/lib/auth-utils.ts b/ui/src/lib/auth-utils.ts index d8e4bbb..fdf9c06 100644 --- a/ui/src/lib/auth-utils.ts +++ b/ui/src/lib/auth-utils.ts @@ -1,20 +1,15 @@ -import type { Account } from "better-auth"; -import type { Dispatch, SetStateAction } from "react"; - -type LinkedAccount = Pick<Account, "providerId" | "accountId">; - -export function getNearAccountId(linkedAccounts: LinkedAccount[]): string | null { +export function getNearAccountId(linkedAccounts: any[]): string | null { const nearAccount = linkedAccounts.find(account => account.providerId === 'siwn'); return (nearAccount?.accountId)?.split(":")[0] || nearAccount?.providerId || null; } -export function getLinkedProviders(linkedAccounts: LinkedAccount[]): string[] { +export function getLinkedProviders(linkedAccounts: any[]): string[] { return linkedAccounts.map(account => account.providerId); } export function handleAccountLinkRefresh( - _componentState: unknown, - _setLinkedAccounts: Dispatch<SetStateAction<LinkedAccount[]>>, + _componentState: any, + _setLinkedAccounts: React.Dispatch<React.SetStateAction<any[]>>, refreshAccounts: () => Promise<void> ) { refreshAccounts(); diff --git a/ui/src/lib/session.ts b/ui/src/lib/session.ts index 1cf41e2..9a3ede8 100644 --- a/ui/src/lib/session.ts +++ b/ui/src/lib/session.ts @@ -9,4 +9,5 @@ export const sessionQueryOptions = queryOptions({ }, staleTime: 0, gcTime: 1000 * 60 * 10, + enabled: typeof window !== 'undefined', }); diff --git a/ui/src/main.tsx b/ui/src/main.tsx deleted file mode 100644 index 2719c38..0000000 --- a/ui/src/main.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { StrictMode } from 'react'; -import ReactDOM from 'react-dom/client'; -import { App } from './bootstrap'; -import reportWebVitals from './reportWebVitals'; - -const rootElement = document.getElementById('app'); -if (rootElement) { - const root = ReactDOM.createRoot(rootElement); - root.render( - <StrictMode> - <App /> - </StrictMode> - ); -} - -reportWebVitals(); diff --git a/ui/src/providers/index.tsx b/ui/src/providers/index.tsx index bfe2472..68fd5ad 100644 --- a/ui/src/providers/index.tsx +++ b/ui/src/providers/index.tsx @@ -1,55 +1,9 @@ -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { QueryClientProvider } from "@tanstack/react-query"; import { ThemeProvider } from "next-themes"; import { Toaster } from "sonner"; -import type { Network } from "near-kit"; -import { ErrorBoundary } from "@/components/error-boundary"; export * from "@/hooks"; -const defaultQueryClient = new QueryClient({ - defaultOptions: { - queries: { - staleTime: 5 * 60 * 1000, - gcTime: 30 * 60 * 1000, - refetchOnWindowFocus: false, - retry: 1, - }, - }, -}); - -export interface AppProviderProps { - children: React.ReactNode; - network?: Network; - queryClient?: QueryClient; -} - -export function AppProvider({ - children, - queryClient = defaultQueryClient, -}: AppProviderProps) { - return ( - <ErrorBoundary> - <ThemeProvider attribute="class" defaultTheme="system" enableSystem> - <QueryClientProvider client={queryClient}> - {children} - <Toaster position="top-center" richColors closeButton /> - </QueryClientProvider> - </ThemeProvider> - </ErrorBoundary> - ); -} - export { QueryClientProvider }; - -export function createQueryClient() { - return new QueryClient({ - defaultOptions: { - queries: { - staleTime: 5 * 60 * 1000, - gcTime: 30 * 60 * 1000, - refetchOnWindowFocus: false, - retry: 1, - }, - }, - }); -} +export { ThemeProvider }; +export { Toaster }; diff --git a/ui/src/remote.tsx b/ui/src/remote.tsx deleted file mode 100644 index b93c7a0..0000000 --- a/ui/src/remote.tsx +++ /dev/null @@ -1 +0,0 @@ -import('./bootstrap'); diff --git a/ui/src/routeTree.gen.ts b/ui/src/routeTree.gen.ts index 367ee0e..7b53950 100644 --- a/ui/src/routeTree.gen.ts +++ b/ui/src/routeTree.gen.ts @@ -11,11 +11,8 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as LayoutRouteImport } from './routes/_layout' import { Route as LayoutLoginRouteImport } from './routes/_layout/login' -import { Route as LayoutPageRouteImport } from './routes/_layout/_page' import { Route as LayoutAuthenticatedRouteImport } from './routes/_layout/_authenticated' import { Route as LayoutAuthenticatedIndexRouteImport } from './routes/_layout/_authenticated/index' -import { Route as LayoutPageTermsOfServiceRouteImport } from './routes/_layout/_page/terms-of-service' -import { Route as LayoutPagePrivacyPolicyRouteImport } from './routes/_layout/_page/privacy-policy' import { Route as LayoutAuthenticatedSettingsRouteImport } from './routes/_layout/_authenticated/settings' import { Route as LayoutAuthenticatedAdminRouteImport } from './routes/_layout/_authenticated/_admin' import { Route as LayoutAuthenticatedChatIndexRouteImport } from './routes/_layout/_authenticated/chat/index' @@ -31,10 +28,6 @@ const LayoutLoginRoute = LayoutLoginRouteImport.update({ path: '/login', getParentRoute: () => LayoutRoute, } as any) -const LayoutPageRoute = LayoutPageRouteImport.update({ - id: '/_page', - getParentRoute: () => LayoutRoute, -} as any) const LayoutAuthenticatedRoute = LayoutAuthenticatedRouteImport.update({ id: '/_authenticated', getParentRoute: () => LayoutRoute, @@ -45,17 +38,6 @@ const LayoutAuthenticatedIndexRoute = path: '/', getParentRoute: () => LayoutAuthenticatedRoute, } as any) -const LayoutPageTermsOfServiceRoute = - LayoutPageTermsOfServiceRouteImport.update({ - id: '/terms-of-service', - path: '/terms-of-service', - getParentRoute: () => LayoutPageRoute, - } as any) -const LayoutPagePrivacyPolicyRoute = LayoutPagePrivacyPolicyRouteImport.update({ - id: '/privacy-policy', - path: '/privacy-policy', - getParentRoute: () => LayoutPageRoute, -} as any) const LayoutAuthenticatedSettingsRoute = LayoutAuthenticatedSettingsRouteImport.update({ id: '/settings', @@ -90,8 +72,6 @@ export interface FileRoutesByFullPath { '/': typeof LayoutAuthenticatedIndexRoute '/login': typeof LayoutLoginRoute '/settings': typeof LayoutAuthenticatedSettingsRoute - '/privacy-policy': typeof LayoutPagePrivacyPolicyRoute - '/terms-of-service': typeof LayoutPageTermsOfServiceRoute '/dashboard': typeof LayoutAuthenticatedAdminDashboardRoute '/keys/$key': typeof LayoutAuthenticatedKeysKeyRoute '/chat/': typeof LayoutAuthenticatedChatIndexRoute @@ -100,8 +80,6 @@ export interface FileRoutesByTo { '/': typeof LayoutAuthenticatedIndexRoute '/login': typeof LayoutLoginRoute '/settings': typeof LayoutAuthenticatedSettingsRoute - '/privacy-policy': typeof LayoutPagePrivacyPolicyRoute - '/terms-of-service': typeof LayoutPageTermsOfServiceRoute '/dashboard': typeof LayoutAuthenticatedAdminDashboardRoute '/keys/$key': typeof LayoutAuthenticatedKeysKeyRoute '/chat': typeof LayoutAuthenticatedChatIndexRoute @@ -110,12 +88,9 @@ export interface FileRoutesById { __root__: typeof rootRouteImport '/_layout': typeof LayoutRouteWithChildren '/_layout/_authenticated': typeof LayoutAuthenticatedRouteWithChildren - '/_layout/_page': typeof LayoutPageRouteWithChildren '/_layout/login': typeof LayoutLoginRoute '/_layout/_authenticated/_admin': typeof LayoutAuthenticatedAdminRouteWithChildren '/_layout/_authenticated/settings': typeof LayoutAuthenticatedSettingsRoute - '/_layout/_page/privacy-policy': typeof LayoutPagePrivacyPolicyRoute - '/_layout/_page/terms-of-service': typeof LayoutPageTermsOfServiceRoute '/_layout/_authenticated/': typeof LayoutAuthenticatedIndexRoute '/_layout/_authenticated/_admin/dashboard': typeof LayoutAuthenticatedAdminDashboardRoute '/_layout/_authenticated/keys/$key': typeof LayoutAuthenticatedKeysKeyRoute @@ -127,31 +102,18 @@ export interface FileRouteTypes { | '/' | '/login' | '/settings' - | '/privacy-policy' - | '/terms-of-service' | '/dashboard' | '/keys/$key' | '/chat/' fileRoutesByTo: FileRoutesByTo - to: - | '/' - | '/login' - | '/settings' - | '/privacy-policy' - | '/terms-of-service' - | '/dashboard' - | '/keys/$key' - | '/chat' + to: '/' | '/login' | '/settings' | '/dashboard' | '/keys/$key' | '/chat' id: | '__root__' | '/_layout' | '/_layout/_authenticated' - | '/_layout/_page' | '/_layout/login' | '/_layout/_authenticated/_admin' | '/_layout/_authenticated/settings' - | '/_layout/_page/privacy-policy' - | '/_layout/_page/terms-of-service' | '/_layout/_authenticated/' | '/_layout/_authenticated/_admin/dashboard' | '/_layout/_authenticated/keys/$key' @@ -178,13 +140,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LayoutLoginRouteImport parentRoute: typeof LayoutRoute } - '/_layout/_page': { - id: '/_layout/_page' - path: '' - fullPath: '/' - preLoaderRoute: typeof LayoutPageRouteImport - parentRoute: typeof LayoutRoute - } '/_layout/_authenticated': { id: '/_layout/_authenticated' path: '' @@ -199,20 +154,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LayoutAuthenticatedIndexRouteImport parentRoute: typeof LayoutAuthenticatedRoute } - '/_layout/_page/terms-of-service': { - id: '/_layout/_page/terms-of-service' - path: '/terms-of-service' - fullPath: '/terms-of-service' - preLoaderRoute: typeof LayoutPageTermsOfServiceRouteImport - parentRoute: typeof LayoutPageRoute - } - '/_layout/_page/privacy-policy': { - id: '/_layout/_page/privacy-policy' - path: '/privacy-policy' - fullPath: '/privacy-policy' - preLoaderRoute: typeof LayoutPagePrivacyPolicyRouteImport - parentRoute: typeof LayoutPageRoute - } '/_layout/_authenticated/settings': { id: '/_layout/_authenticated/settings' path: '/settings' @@ -285,29 +226,13 @@ const LayoutAuthenticatedRouteChildren: LayoutAuthenticatedRouteChildren = { const LayoutAuthenticatedRouteWithChildren = LayoutAuthenticatedRoute._addFileChildren(LayoutAuthenticatedRouteChildren) -interface LayoutPageRouteChildren { - LayoutPagePrivacyPolicyRoute: typeof LayoutPagePrivacyPolicyRoute - LayoutPageTermsOfServiceRoute: typeof LayoutPageTermsOfServiceRoute -} - -const LayoutPageRouteChildren: LayoutPageRouteChildren = { - LayoutPagePrivacyPolicyRoute: LayoutPagePrivacyPolicyRoute, - LayoutPageTermsOfServiceRoute: LayoutPageTermsOfServiceRoute, -} - -const LayoutPageRouteWithChildren = LayoutPageRoute._addFileChildren( - LayoutPageRouteChildren, -) - interface LayoutRouteChildren { LayoutAuthenticatedRoute: typeof LayoutAuthenticatedRouteWithChildren - LayoutPageRoute: typeof LayoutPageRouteWithChildren LayoutLoginRoute: typeof LayoutLoginRoute } const LayoutRouteChildren: LayoutRouteChildren = { LayoutAuthenticatedRoute: LayoutAuthenticatedRouteWithChildren, - LayoutPageRoute: LayoutPageRouteWithChildren, LayoutLoginRoute: LayoutLoginRoute, } diff --git a/ui/src/router.server.tsx b/ui/src/router.server.tsx new file mode 100644 index 0000000..7e7309a --- /dev/null +++ b/ui/src/router.server.tsx @@ -0,0 +1,173 @@ +import { QueryClientProvider } from "@tanstack/react-query"; +import type { AnyRoute } from "@tanstack/react-router"; +import { createMemoryHistory, createRouter as createTanStackRouter } from "@tanstack/react-router"; +import { createRequestHandler, renderRouterToStream, RouterServer } from "@tanstack/react-router/ssr/server"; +import { createRouter } from "./router"; +import { routeTree } from "./routeTree.gen"; +import type { + HeadData, + HeadLink, + HeadMeta, + HeadScript, + RenderOptions, + RenderResult, + RouterContext, +} from "./types"; + +export { createRouter, routeTree } from "./router"; +export type { + ClientRuntimeConfig, + CreateRouterOptions, + HeadData, + RenderOptions, + RenderResult, + RouterContext, +} from "./types"; + +function getMetaKey(meta: HeadMeta): string { + if (!meta) return "null"; + if ("title" in meta) return "title"; + if ("charSet" in meta) return "charSet"; + if ("name" in meta) return `name:${(meta as { name: string }).name}`; + if ("property" in meta) return `property:${(meta as { property: string }).property}`; + if ("httpEquiv" in meta) return `httpEquiv:${(meta as { httpEquiv: string }).httpEquiv}`; + return JSON.stringify(meta); +} + +function getLinkKey(link: HeadLink): string { + const rel = (link as { rel?: string }).rel ?? ""; + const href = (link as { href?: string }).href ?? ""; + return `${rel}:${href}`; +} + +function getScriptKey(script: HeadScript): string { + if (!script) return "null"; + if ("src" in script && script.src) return `src:${script.src}`; + if ("children" in script && script.children) return `children:${typeof script.children === "string" ? script.children : JSON.stringify(script.children)}`; + return JSON.stringify(script); +} + +export async function getRouteHead( + pathname: string, + context?: Partial<RouterContext> +): Promise<HeadData> { + const history = createMemoryHistory({ initialEntries: [pathname] }); + + const router = createTanStackRouter({ + routeTree, + history, + context: { + queryClient: undefined as never, + assetsUrl: context?.assetsUrl ?? "", + runtimeConfig: context?.runtimeConfig, + }, + }); + + const matches = router.matchRoutes(pathname); + + const metaMap = new Map<string, HeadMeta>(); + const linkMap = new Map<string, HeadLink>(); + const scriptMap = new Map<string, HeadScript>(); + + for (const match of matches) { + const route = router.looseRoutesById[match.routeId] as AnyRoute | undefined; + if (!route?.options?.head) continue; + + let loaderData: unknown = undefined; + const loaderFn = route.options.loader; + + if (loaderFn) { + try { + loaderData = await loaderFn({ + params: match.params, + context: router.options.context, + abortController: new AbortController(), + preload: false, + cause: "enter", + } as Parameters<typeof loaderFn>[0]); + } catch (error) { + console.warn( + `[getRouteHead] Loader failed for ${match.routeId}:`, + error + ); + } + } + + try { + const headResult = await route.options.head({ + loaderData, + matches, + match, + params: match.params, + } as Parameters<typeof route.options.head>[0]); + + if (headResult?.meta) { + for (const meta of headResult.meta) { + metaMap.set(getMetaKey(meta), meta); + } + } + if (headResult?.links) { + for (const link of headResult.links) { + linkMap.set(getLinkKey(link), link); + } + } + if (headResult?.scripts) { + for (const script of headResult.scripts) { + scriptMap.set(getScriptKey(script), script); + } + } + } catch (error) { + console.warn(`[getRouteHead] head() failed for ${match.routeId}:`, error); + } + } + + return { + meta: [...metaMap.values()], + links: [...linkMap.values()], + scripts: [...scriptMap.values()], + }; +} + +export async function renderToStream( + request: Request, + options: RenderOptions +): Promise<RenderResult> { + const url = new URL(request.url); + const history = createMemoryHistory({ initialEntries: [url.pathname + url.search] }); + + let queryClientRef: typeof import("@tanstack/react-query").QueryClient.prototype | null = null; + + const handler = createRequestHandler({ + request, + createRouter: () => { + const { router, queryClient } = createRouter({ + history, + context: { + assetsUrl: options.assetsUrl, + runtimeConfig: options.runtimeConfig, + }, + }); + queryClientRef = queryClient; + return router; + }, + }); + + const response = await handler(({ request, responseHeaders, router }) => + renderRouterToStream({ + request, + responseHeaders, + router, + children: ( + <QueryClientProvider client={queryClientRef!}> + <RouterServer router={router} /> + </QueryClientProvider> + ), + }), + ); + + return { + stream: response.body!, + statusCode: response.status, + headers: new Headers(response.headers), + }; +} diff --git a/ui/src/router.tsx b/ui/src/router.tsx index 269acca..b0ca78c 100644 --- a/ui/src/router.tsx +++ b/ui/src/router.tsx @@ -1,32 +1,93 @@ -import { createRouter as createTanStackRouter } from '@tanstack/react-router'; -import { QueryClient } from '@tanstack/react-query'; -import { routeTree } from './routeTree.gen'; +import { QueryClient } from "@tanstack/react-query"; +import { + createBrowserHistory, + createRouter as createTanStackRouter, +} from "@tanstack/react-router"; +import { routeTree } from "./routeTree.gen"; +import "./styles.css"; +import type { CreateRouterOptions } from "./types"; -export interface RouterContext { - queryClient: QueryClient; +export type { + ClientRuntimeConfig, CreateRouterOptions, RouterContext, RouterModule +} from "./types"; + +function NotFoundComponent() { + return ( + <div className="min-h-screen flex items-center justify-center bg-background"> + <div className="text-center"> + <h1 className="text-4xl font-bold text-foreground mb-4">404</h1> + <p className="text-muted-foreground mb-8">Page not found</p> + <a + href="/" + className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2" + > + Go Home + </a> + </div> + </div> + ); +} + +function ErrorComponent({ error }: { error: Error }) { + return ( + <div className="min-h-screen flex items-center justify-center bg-background"> + <div className="text-center"> + <h1 className="text-4xl font-bold text-foreground mb-4">Oops!</h1> + <p className="text-muted-foreground mb-4">Something went wrong</p> + <details className="text-sm text-muted-foreground bg-muted p-4 rounded mb-8"> + <summary className="cursor-pointer">Error Details</summary> + <pre className="mt-2 whitespace-pre-wrap text-left"> + {error.message} + </pre> + </details> + <button + type="button" + onClick={() => window.location.reload()} + className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2" + > + Reload Page + </button> + </div> + </div> + ); +} + +function PendingComponent() { + return <div className="min-h-screen w-full bg-background" />; } -export function createRouter(opts?: { context?: Partial<RouterContext> }) { - const queryClient = opts?.context?.queryClient ?? new QueryClient({ - defaultOptions: { - queries: { - staleTime: 5 * 60 * 1000, - gcTime: 30 * 60 * 1000, - refetchOnWindowFocus: false, - retry: 1, +export function createRouter(opts: CreateRouterOptions = {}) { + const queryClient = + opts.context?.queryClient ?? + new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60 * 1000, + gcTime: 30 * 60 * 1000, + refetchOnWindowFocus: false, + retry: 1, + }, }, - }, - }); + }); + + const history = opts.history ?? createBrowserHistory(); const router = createTanStackRouter({ routeTree, + history, context: { queryClient, + assetsUrl: opts.context?.assetsUrl ?? "", + runtimeConfig: opts.context?.runtimeConfig, }, - defaultPreload: 'intent', + defaultPreload: "intent", scrollRestoration: true, defaultStructuralSharing: true, defaultPreloadStaleTime: 0, + defaultNotFoundComponent: NotFoundComponent, + defaultErrorComponent: ErrorComponent, + defaultPendingComponent: PendingComponent, + defaultPendingMinMs: 100, }); return { router, queryClient }; @@ -34,8 +95,8 @@ export function createRouter(opts?: { context?: Partial<RouterContext> }) { export { routeTree }; -declare module '@tanstack/react-router' { +declare module "@tanstack/react-router" { interface Register { - router: ReturnType<typeof createRouter>['router']; + router: ReturnType<typeof createRouter>["router"]; } } diff --git a/ui/src/routes/__root.tsx b/ui/src/routes/__root.tsx index 870dd52..d3601b3 100644 --- a/ui/src/routes/__root.tsx +++ b/ui/src/routes/__root.tsx @@ -1,53 +1,114 @@ import { TanStackDevtools } from "@tanstack/react-devtools"; -import type { QueryClient } from "@tanstack/react-query"; import { ClientOnly, createRootRouteWithContext, HeadContent, Outlet, + Scripts, } from "@tanstack/react-router"; import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools"; +import { ThemeProvider } from "next-themes"; +import { Toaster } from "sonner"; +import type { RouterContext } from "@/types"; import TanStackQueryDevtools from "../integrations/tanstack-query/devtools"; -interface MyRouterContext { - queryClient: QueryClient; -} - -function getAssetBase(): string { - if (typeof window !== "undefined" && window.__RUNTIME_CONFIG__?.ui?.url) { - return window.__RUNTIME_CONFIG__.ui.url; - } - return ""; -} +export const Route = createRootRouteWithContext<RouterContext>()({ + loader: ({ context }) => ({ + assetsUrl: context.assetsUrl || "", + runtimeConfig: context.runtimeConfig, + }), + head: ({ loaderData }) => { + const assetsUrl = loaderData?.assetsUrl || ""; + const runtimeConfig = loaderData?.runtimeConfig; + const siteUrl = runtimeConfig?.hostUrl || ""; + const title = runtimeConfig?.title || "demo.everything"; + const description = + "Demo application showcasing Module Federation with SSR, TanStack Router, and oRPC"; + const siteName = "Every Demo"; + const ogImage = `${assetsUrl}/metadata.png`; -export const Route = createRootRouteWithContext<MyRouterContext>()({ - head: () => { - const assetBase = getAssetBase(); return { meta: [ - { title: "NEAR Agency" }, + { charSet: "utf-8" }, { - name: "description", - content: - "NEAR AI application showcasing Module Federation with SSR, TanStack Router, and oRPC", + name: "viewport", + content: "width=device-width, initial-scale=1.0, viewport-fit=cover", }, + { title }, + { name: "description", content: description }, { name: "theme-color", content: "#171717" }, - { name: "application-name", content: "NEAR Agency" }, + { name: "color-scheme", content: "light dark" }, + { name: "application-name", content: siteName }, { name: "mobile-web-app-capable", content: "yes" }, { name: "apple-mobile-web-app-status-bar-style", content: "black-translucent", }, + { name: "format-detection", content: "telephone=no" }, + { name: "robots", content: "index, follow" }, + { property: "og:title", content: title }, + { property: "og:description", content: description }, + { property: "og:type", content: "website" }, + { property: "og:url", content: siteUrl }, + { property: "og:image", content: ogImage }, + { property: "og:site_name", content: siteName }, + { name: "twitter:card", content: "summary_large_image" }, + { name: "twitter:title", content: title }, + { name: "twitter:description", content: description }, + { name: "twitter:image", content: ogImage }, ], links: [ - { rel: "icon", type: "image/x-icon", href: `${assetBase}/favicon.ico` }, - { rel: "icon", type: "image/svg+xml", href: `${assetBase}/icon.svg` }, + { rel: "canonical", href: siteUrl }, + { rel: "stylesheet", href: `${assetsUrl}/static/css/async/style.css` }, + { rel: "preconnect", href: "https://fonts.googleapis.com" }, + { + rel: "preconnect", + href: "https://fonts.gstatic.com", + crossOrigin: "anonymous", + }, + { rel: "icon", type: "image/x-icon", href: `${assetsUrl}/favicon.ico` }, + { rel: "icon", type: "image/svg+xml", href: `${assetsUrl}/icon.svg` }, { rel: "apple-touch-icon", sizes: "180x180", - href: `${assetBase}/apple-touch-icon.png`, + href: `${assetsUrl}/apple-touch-icon.png`, + }, + { rel: "manifest", href: `${assetsUrl}/manifest.json` }, + ], + scripts: [ + { + src: `${assetsUrl}/remoteEntry.js`, + }, + { + children: `(function(){var t=localStorage.getItem('theme');if(t==='dark'||(!t&&window.matchMedia('(prefers-color-scheme: dark)').matches)){document.documentElement.classList.add('dark');}})();`, + }, + { + type: "application/ld+json", + children: JSON.stringify({ + "@context": "https://schema.org", + "@type": "WebSite", + name: siteName, + url: siteUrl, + description, + }), + }, + { + children: ` +window.__RUNTIME_CONFIG__=${JSON.stringify(runtimeConfig)}; +function __hydrate(){ + var container = window['ui']; + if (!container) { console.error('[Hydrate] Container not found'); return; } + container.init({}).then(function(){ + return container.get('./Hydrate'); + }).then(function(mod){ + return mod().hydrate(); + }).catch(function(e){ + console.error('[Hydrate] Failed:', e); + }); +} +if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',__hydrate);}else{__hydrate();} + `.trim(), }, - { rel: "manifest", href: `${assetBase}/manifest.json` }, ], }; }, @@ -56,23 +117,44 @@ export const Route = createRootRouteWithContext<MyRouterContext>()({ function RootComponent() { return ( - <> - <HeadContent /> - <Outlet /> - <ClientOnly> - <TanStackDevtools - config={{ - position: "bottom-right", + <html lang="en" suppressHydrationWarning> + <head> + <HeadContent /> + <style + dangerouslySetInnerHTML={{ + __html: ` + :root { --host-bg: #ffffff; --host-fg: #171717; } + .dark { --host-bg: #1c1c1e; --host-fg: #fafafa; } + *, *::before, *::after { box-sizing: border-box; } + html { height: 100%; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; color-scheme: light dark; } + body { min-height: 100%; margin: 0; background-color: var(--host-bg); color: var(--host-fg); -webkit-tap-highlight-color: transparent; touch-action: manipulation; transition: background-color 0.2s ease; } + #root { min-height: 100vh; background-color: var(--host-bg); } + @supports (min-height: 100dvh) { #root { min-height: 100dvh; } } + `, }} - plugins={[ - { - name: "Tanstack Router", - render: <TanStackRouterDevtoolsPanel />, - }, - TanStackQueryDevtools, - ]} /> - </ClientOnly> - </> + </head> + <body> + <ThemeProvider attribute="class" defaultTheme="system" enableSystem> + <div id="root"> + <Outlet /> + </div> + <Toaster position="bottom-right" richColors closeButton /> + </ThemeProvider> + <Scripts /> + <ClientOnly> + <TanStackDevtools + config={{ position: "bottom-right" }} + plugins={[ + { + name: "Tanstack Router", + render: <TanStackRouterDevtoolsPanel />, + }, + TanStackQueryDevtools, + ]} + /> + </ClientOnly> + </body> + </html> ); } diff --git a/ui/src/routes/_layout.tsx b/ui/src/routes/_layout.tsx index 26ed92b..547a211 100644 --- a/ui/src/routes/_layout.tsx +++ b/ui/src/routes/_layout.tsx @@ -1,81 +1,21 @@ -import { useSuspenseQuery } from "@tanstack/react-query"; -import { - createFileRoute, - Link, - Outlet, - useRouter, -} from "@tanstack/react-router"; +import { ClientOnly, createFileRoute, Outlet } from "@tanstack/react-router"; import { ThemeToggle } from "../components/theme-toggle"; -import { authClient } from "../lib/auth-client"; -import { sessionQueryOptions } from "../lib/session"; -import { queryClient } from "../utils/orpc"; +import { UserNav } from "../components/user-nav"; export const Route = createFileRoute("/_layout")({ - beforeLoad: async ({ context }) => { - await context.queryClient.ensureQueryData(sessionQueryOptions); - }, component: Layout, }); function Layout() { - const router = useRouter(); - const { data: session } = useSuspenseQuery(sessionQueryOptions); - const accountId = session?.user?.id; - const userRole = (session?.user as { role?: string })?.role; - - const handleSignOut = async () => { - try { - await authClient.signOut(); - await authClient.near.disconnect(); - queryClient.invalidateQueries({ queryKey: ["session"] }); - router.invalidate(); - window.location.href = "/"; - } catch (error) { - console.error("Sign out error:", error); - } - }; - return ( <div className="h-dvh w-full flex flex-col bg-background text-foreground overflow-hidden"> <header className="shrink-0 border-b border-border/50"> <div className="max-w-5xl mx-auto px-4 sm:px-6 py-3 sm:py-4"> <div className="flex items-center justify-end gap-4"> <ThemeToggle /> - {accountId ? ( - <> - {userRole === "admin" && ( - <Link - to="/dashboard" - className="text-xs text-muted-foreground hover:text-foreground transition-colors font-mono" - > - admin - </Link> - )} - <Link - to="/settings" - className="text-xs text-muted-foreground hover:text-foreground transition-colors font-mono" - > - settings - </Link> - <span className="text-xs text-muted-foreground font-mono"> - {accountId} - </span> - <button - type="button" - onClick={handleSignOut} - className="text-xs text-muted-foreground hover:text-foreground transition-colors font-mono" - > - sign out - </button> - </> - ) : ( - <Link - to="/login" - className="text-xs text-muted-foreground hover:text-foreground transition-colors font-mono" - > - login - </Link> - )} + <ClientOnly fallback={<span className="text-xs text-muted-foreground font-mono">...</span>}> + <UserNav /> + </ClientOnly> </div> </div> </header> diff --git a/ui/src/routes/_layout/_authenticated.tsx b/ui/src/routes/_layout/_authenticated.tsx index bb04706..43b114c 100644 --- a/ui/src/routes/_layout/_authenticated.tsx +++ b/ui/src/routes/_layout/_authenticated.tsx @@ -1,7 +1,8 @@ +import { createFileRoute, Outlet, redirect } from "@tanstack/react-router"; import { authClient } from "@/lib/auth-client"; -import { createFileRoute, redirect, Outlet } from "@tanstack/react-router"; export const Route = createFileRoute("/_layout/_authenticated")({ + ssr: false, beforeLoad: async ({ location }) => { const { data: session } = await authClient.getSession(); if (!session?.user) { diff --git a/ui/src/routes/_layout/_authenticated/index.tsx b/ui/src/routes/_layout/_authenticated/index.tsx index ef57272..376b9bc 100644 --- a/ui/src/routes/_layout/_authenticated/index.tsx +++ b/ui/src/routes/_layout/_authenticated/index.tsx @@ -1,5 +1,5 @@ import { createFileRoute } from "@tanstack/react-router"; -import { ChatPage } from "../../../components/chat/ChatPage"; +import { ChatPage } from "../../../components/chat/chat-page"; export const Route = createFileRoute("/_layout/_authenticated/")({ component: IndexPage, diff --git a/ui/src/routes/_layout/_authenticated/settings.tsx b/ui/src/routes/_layout/_authenticated/settings.tsx index 9386449..dd1948c 100644 --- a/ui/src/routes/_layout/_authenticated/settings.tsx +++ b/ui/src/routes/_layout/_authenticated/settings.tsx @@ -1,5 +1,5 @@ import { createFileRoute } from "@tanstack/react-router"; -import { KVEditor } from "../../../components/kv/KVEditor"; +import { KVEditor } from "../../../components/kv/kv-editor"; export const Route = createFileRoute("/_layout/_authenticated/settings")({ component: SettingsPage, diff --git a/ui/src/routes/_layout/_page.tsx b/ui/src/routes/_layout/_page.tsx deleted file mode 100644 index 35e5b21..0000000 --- a/ui/src/routes/_layout/_page.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { createFileRoute, Outlet } from "@tanstack/react-router"; - -export const Route = createFileRoute("/_layout/_page")({ - component: PageLayout, -}); - -function PageLayout() { - return ( - <div className="max-w-4xl mx-auto px-4 md:px-8 py-12"> - <Outlet /> - </div> - ); -} diff --git a/ui/src/routes/_layout/_page/privacy-policy.tsx b/ui/src/routes/_layout/_page/privacy-policy.tsx deleted file mode 100644 index f2bbbc9..0000000 --- a/ui/src/routes/_layout/_page/privacy-policy.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; - -export const Route = createFileRoute("/_layout/_page/privacy-policy")({ - component: PrivacyPolicy, -}); - -function PrivacyPolicy() { - return ( - <> - <h1 className="text-base font-normal mb-2">Privacy Policy</h1> - <p className="text-sm text-muted-foreground mb-8"> - Last updated: December 16, 2025 - </p> - - <div className="bg-muted/30 p-6 rounded-lg mb-8"> - <p className="text-sm text-muted-foreground"> - This is a placeholder for the Privacy Policy. Replace this content with your - actual privacy practices and policies. - </p> - </div> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">1. Introduction</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Introduce your commitment to privacy and the purpose of this policy.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">2. Information We Collect</h2> - <p className="text-muted-foreground mb-3"> - [Placeholder: Describe the types of information collected from users:] - </p> - <ul className="list-disc pl-6 space-y-2 text-muted-foreground"> - <li>Personal information (name, email, shipping address)</li> - <li>Payment information</li> - <li>NEAR wallet addresses</li> - <li>Browser and device information</li> - <li>Usage data and analytics</li> - </ul> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">3. How We Use Your Information</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Explain how collected information is used - order processing, - communications, service improvement, etc.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">4. Information Sharing</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Detail when and with whom information may be shared - payment processors, - shipping partners, legal requirements, etc.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">5. Blockchain and Cryptocurrency</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Explain privacy implications of blockchain transactions, wallet addresses - being public, and NEAR Protocol integration.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">6. Cookies and Tracking</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Describe use of cookies, analytics tools, and tracking technologies.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">7. Data Security</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Outline security measures taken to protect user information and - limitations of security.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">8. Data Retention</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Explain how long different types of data are retained and deletion - policies.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">9. Your Privacy Rights</h2> - <p className="text-muted-foreground mb-3"> - [Placeholder: Detail user rights regarding their personal information:] - </p> - <ul className="list-disc pl-6 space-y-2 text-muted-foreground"> - <li>Access and review your data</li> - <li>Request corrections or updates</li> - <li>Request deletion of your data</li> - <li>Opt-out of marketing communications</li> - <li>Data portability</li> - </ul> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">10. Third-Party Services</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Describe integration with third-party services and their privacy - practices.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">11. International Data Transfers</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: If applicable, explain how data is transferred and protected - internationally.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">12. Children's Privacy</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: State policies regarding collection of information from children under - 13.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">13. Regional Privacy Laws</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Address GDPR (California), and other regional privacy - regulations as applicable.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">14. Policy Updates</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Explain how users will be notified of privacy policy changes.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">15. Contact Us</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Provide contact information for privacy-related questions and data - requests.] - </p> - <hr className="border-t border-border my-6" /> - <p className="text-muted-foreground"> - For privacy-related questions or to exercise your privacy rights, please contact us at{" "} - <a href="mailto:privacy@near.org" className="text-primary hover:underline"> - privacy@near.org - </a> - </p> - </section> - </> - ); -} diff --git a/ui/src/routes/_layout/_page/terms-of-service.tsx b/ui/src/routes/_layout/_page/terms-of-service.tsx deleted file mode 100644 index 95825c5..0000000 --- a/ui/src/routes/_layout/_page/terms-of-service.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; - -export const Route = createFileRoute("/_layout/_page/terms-of-service")({ - component: TermsOfService, -}); - -function TermsOfService() { - return ( - <> - <h1 className="text-base font-normal mb-2">Terms of Service</h1> - <p className="text-sm text-muted-foreground mb-8"> - Last updated: December 16, 2025 - </p> - - <div className="bg-muted/30 p-6 rounded-lg mb-8"> - <p className="text-sm text-muted-foreground"> - This is a placeholder for the Terms of Service. Replace this content with your - actual terms and conditions. - </p> - </div> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">1. Acceptance of Terms</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Explain that by using the service, users agree to these terms.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">2. Use of Service</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Define acceptable use of the platform and user responsibilities.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">3. Account Responsibilities</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Detail user account obligations, security, and NEAR wallet integration requirements.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">4. Products and Pricing</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Explain product descriptions, pricing accuracy, and availability disclaimers.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">5. Payment Terms</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Detail payment methods, processing, blockchain transaction terms, and fees.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">6. Shipping and Delivery</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Outline shipping policies, delivery timeframes, and risk of loss transfer.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">7. Returns and Refunds</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Define return policy, refund process, and conditions for returns.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">8. Intellectual Property Rights</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: State ownership of content, trademarks, and user license grants.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">9. Prohibited Activities</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: List prohibited uses including fraud, unauthorized access, and illegal activities.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">10. Disclaimers and Warranties</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Include "as-is" disclaimers and warranty limitations.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">11. Limitation of Liability</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Limit liability for damages, losses, and service interruptions.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">12. Indemnification</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Require user indemnification for violations and third-party claims.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">13. Termination and Suspension</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Define termination rights, suspension conditions, and effects of termination.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">14. Dispute Resolution</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Specify arbitration requirements, class action waivers, and dispute procedures.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">15. Governing Law</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: State applicable jurisdiction and choice of law.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">16. Changes to Terms</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Explain modification rights and user notification procedures.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">17. General Provisions</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Include severability, waiver, entire agreement, and assignment clauses.] - </p> - </section> - - <section className="mb-8"> - <h2 className="text-xl font-semibold mb-4">18. Contact Information</h2> - <p className="text-muted-foreground mb-4"> - [Placeholder: Provide official contact details for legal notices and questions.] - </p> - <hr className="border-t border-border my-6" /> - <p className="text-muted-foreground"> - For questions about these Terms of Service, please contact us at{" "} - <a href="mailto:legal@near.org" className="text-primary hover:underline"> - legal@near.org - </a> - </p> - </section> - </> - ); -} diff --git a/ui/src/routes/_layout/login.tsx b/ui/src/routes/_layout/login.tsx index 842d34b..fd685dd 100644 --- a/ui/src/routes/_layout/login.tsx +++ b/ui/src/routes/_layout/login.tsx @@ -4,33 +4,12 @@ import { toast } from "sonner"; import { authClient } from "../../lib/auth-client"; import { queryClient } from "../../utils/orpc"; -type AuthErrorLike = { - code?: string; - message?: string; -}; - -function getErrorCode(error: unknown): string | undefined { - if (typeof error === "object" && error) { - const code = (error as AuthErrorLike).code; - if (typeof code === "string") return code; - } - return undefined; -} - -function getErrorMessage(error: unknown): string | undefined { - if (error instanceof Error) return error.message; - if (typeof error === "object" && error) { - const message = (error as AuthErrorLike).message; - if (typeof message === "string") return message; - } - return undefined; -} - type SearchParams = { redirect?: string; }; export const Route = createFileRoute("/_layout/login")({ + ssr: false, validateSearch: (search: Record<string, unknown>): SearchParams => ({ redirect: typeof search.redirect === "string" ? search.redirect : undefined, }), @@ -58,20 +37,19 @@ function LoginPage() { setIsConnectingWallet(true); try { await authClient.requestSignIn.near( - { recipient: import.meta.env.PUBLIC_ACCOUNT_ID || "every.near" }, + { recipient: window.__RUNTIME_CONFIG__?.account ?? "every.near" }, { onSuccess: () => { setIsConnectingWallet(false); toast.success("Wallet connected"); }, - onError: (error: unknown) => { + onError: (error: any) => { setIsConnectingWallet(false); console.error("Wallet connection failed:", error); - const errorCode = getErrorCode(error); const errorMessage = - errorCode === "SIGNER_NOT_AVAILABLE" + error.code === "SIGNER_NOT_AVAILABLE" ? "NEAR wallet not available" - : getErrorMessage(error) || "Failed to connect wallet"; + : error.message || "Failed to connect wallet"; toast.error(errorMessage); }, } @@ -87,7 +65,7 @@ function LoginPage() { setIsSigningInWithNear(true); try { await authClient.signIn.near( - { recipient: import.meta.env.PUBLIC_ACCOUNT_ID || "every.near" }, + { recipient: window.__RUNTIME_CONFIG__?.account ?? "every.near" }, { onSuccess: () => { setIsSigningInWithNear(false); @@ -96,17 +74,19 @@ function LoginPage() { navigate({ to: redirect ?? "/", replace: true }); toast.success(`Signed in as: ${accountId}`); }, - onError: (error: unknown) => { + onError: (error: any) => { setIsSigningInWithNear(false); console.error("NEAR sign in error:", error); - if (getErrorCode(error) === "NONCE_NOT_FOUND") { + if ((error as any)?.code === "NONCE_NOT_FOUND") { toast.error("Session expired. Please reconnect your wallet."); handleWalletDisconnect(); return; } - toast.error(getErrorMessage(error) || "Authentication failed"); + toast.error( + error instanceof Error ? error.message : "Authentication failed" + ); }, } ); @@ -114,7 +94,7 @@ function LoginPage() { setIsSigningInWithNear(false); console.error("NEAR sign in error:", error); - if (getErrorCode(error) === "NONCE_NOT_FOUND") { + if ((error as any)?.code === "NONCE_NOT_FOUND") { toast.error("Session expired. Please reconnect your wallet."); handleWalletDisconnect(); return; @@ -145,10 +125,6 @@ function LoginPage() { isSigningInWithNear || isDisconnectingWallet; - if (!authClient) { - return null; - } - return ( <div className="min-h-[80vh] w-full flex items-center justify-center px-6"> <div className="w-full max-w-sm space-y-3"> diff --git a/ui/src/types/index.ts b/ui/src/types/index.ts index 5b10c68..39901a9 100644 --- a/ui/src/types/index.ts +++ b/ui/src/types/index.ts @@ -1 +1,63 @@ -export type { Network } from "near-kit"; \ No newline at end of file +export type { Network } from "near-kit"; + +import type { QueryClient } from "@tanstack/react-query"; +import type { AnyRouteMatch, AnyRouter, RouterHistory } from "@tanstack/react-router"; + +// TODO: shared with host +export interface ClientRuntimeConfig { + env: string; + account: string; + title: string; + hostUrl: string; + assetsUrl: string; + apiBase: string; + rpcBase: string; +} + +export interface RouterContext { + queryClient: QueryClient; + assetsUrl: string; + runtimeConfig?: ClientRuntimeConfig; +} + +export interface CreateRouterOptions { + history?: RouterHistory; + context?: Partial<RouterContext>; +} + +export type HeadMeta = NonNullable<AnyRouteMatch["meta"]>[number]; +export type HeadLink = NonNullable<AnyRouteMatch["links"]>[number]; +export type HeadScript = NonNullable<AnyRouteMatch["headScripts"]>[number]; + +export interface HeadData { + meta: HeadMeta[]; + links: HeadLink[]; + scripts: HeadScript[]; +} + +export interface RenderOptions { + assetsUrl: string; + runtimeConfig: ClientRuntimeConfig; +} + +export interface RenderResult { + stream: ReadableStream; + statusCode: number; + headers: Headers; +} + +export interface RouterModule { + createRouter: (opts?: CreateRouterOptions) => { + router: AnyRouter; + queryClient: QueryClient; + }; + getRouteHead: ( + pathname: string, + context?: Partial<RouterContext> + ) => Promise<HeadData>; + renderToStream: ( + request: Request, + options: RenderOptions + ) => Promise<RenderResult>; + routeTree: AnyRouter["routeTree"]; +} diff --git a/ui/src/utils/orpc.ts b/ui/src/utils/orpc.ts index 2397d46..ddcc936 100644 --- a/ui/src/utils/orpc.ts +++ b/ui/src/utils/orpc.ts @@ -16,7 +16,8 @@ function getApiUrl(): string { if (typeof window === 'undefined') { throw new Error('RPCLink is not allowed on the server side. Use server-side client instead.'); } - return `${window.location.origin}/api/rpc`; + const base = window.__RUNTIME_CONFIG__?.rpcBase; + return base ? `${window.location.origin}${base}` : `${window.location.origin}/api/rpc`; } export const queryClient = new QueryClient({ From f42c288969112203002c0f874dcef466cb0587ba Mon Sep 17 00:00:00 2001 From: Elliot Braem <elliot@ejlbraem.com> Date: Mon, 26 Jan 2026 14:44:26 -0600 Subject: [PATCH 2/4] update --- bos.config.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bos.config.json b/bos.config.json index 985690a..42101d9 100644 --- a/bos.config.json +++ b/bos.config.json @@ -18,24 +18,24 @@ "BETTER_AUTH_SECRET", "BETTER_AUTH_URL" ], - "remote": "https://elliot-braem-1742-host-cyborg-near-everythi-0068d5f00-ze.zephyrcloud.app" + "remote": "https://elliot-braem-1785-host-cyborg-nearbuilders-70f3ffd9f-ze.zephyrcloud.app" }, "ui": { "name": "ui", "development": "http://localhost:3002", - "production": "https://elliot-braem-1743-ui-cyborg-nearbuilders-a7a278431-ze.zephyrcloud.app", + "production": "https://elliot-braem-1786-ui-cyborg-nearbuilders-46d98f16b-ze.zephyrcloud.app", "exposes": { "App": "./App", "components": "./components", "providers": "./providers", "types": "./types" }, - "ssr": "https://elliot-braem-1784-ui-cyborg-nearbuilders-3d795fd44-ze.zephyrcloud.app" + "ssr": "https://elliot-braem-1787-ui-cyborg-nearbuilders-3be8dde30-ze.zephyrcloud.app" }, "api": { "name": "api", "development": "http://localhost:3014", - "production": "https://elliot-braem-1745-api-cyborg-near-everythin-330ba1944-ze.zephyrcloud.app", + "production": "https://elliot-braem-1788-api-cyborg-nearbuilders-ac0e7b73a-ze.zephyrcloud.app", "variables": { "NEAR_AI_MODEL": "deepseek-ai/DeepSeek-V3.1" }, From eb1e0a1ad863e4f5b749debe349085eaaf7e8489 Mon Sep 17 00:00:00 2001 From: Elliot Braem <elliot@ejlbraem.com> Date: Mon, 26 Jan 2026 14:47:16 -0600 Subject: [PATCH 3/4] update --- bos.config.json | 2 +- bun.lock | 6 ++++++ index.ts | 1 + package.json | 8 ++++++++ tsconfig.json | 29 +++++++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 index.ts create mode 100644 tsconfig.json diff --git a/bos.config.json b/bos.config.json index 42101d9..5391757 100644 --- a/bos.config.json +++ b/bos.config.json @@ -11,7 +11,7 @@ "title": "NEAR Agent", "description": "Template for building NEAR AI applications", "development": "http://localhost:3000", - "production": "https://elliot-braem-1733-host-cyborg-near-everythi-33abe003c-ze.zephyrcloud.app", + "production": "https://elliot-braem-1785-host-cyborg-nearbuilders-70f3ffd9f-ze.zephyrcloud.app", "secrets": [ "HOST_DATABASE_URL", "HOST_DATABASE_AUTH_TOKEN", diff --git a/bun.lock b/bun.lock index 5818811..1235ca9 100644 --- a/bun.lock +++ b/bun.lock @@ -7,6 +7,12 @@ "dependencies": { "@types/bun": "^1.3.6", }, + "devDependencies": { + "@types/bun": "latest", + }, + "peerDependencies": { + "typescript": "^5", + }, }, "api": { "name": "api", diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..f67b2c6 --- /dev/null +++ b/index.ts @@ -0,0 +1 @@ +console.log("Hello via Bun!"); \ No newline at end of file diff --git a/package.json b/package.json index 4267db7..e92b4c7 100644 --- a/package.json +++ b/package.json @@ -51,5 +51,13 @@ "packageManager": "bun@1.2.20", "dependencies": { "@types/bun": "^1.3.6" + }, + "module": "index.ts", + "type": "module", + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..bfa0fea --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} From bc7c9e1d68725e87dcf7dae1a3163355a92b822e Mon Sep 17 00:00:00 2001 From: Elliot Braem <elliot@ejlbraem.com> Date: Mon, 26 Jan 2026 14:47:34 -0600 Subject: [PATCH 4/4] update --- index.ts | 1 - tsconfig.json | 29 ----------------------------- 2 files changed, 30 deletions(-) delete mode 100644 index.ts delete mode 100644 tsconfig.json diff --git a/index.ts b/index.ts deleted file mode 100644 index f67b2c6..0000000 --- a/index.ts +++ /dev/null @@ -1 +0,0 @@ -console.log("Hello via Bun!"); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index bfa0fea..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - // Environment setup & latest features - "lib": ["ESNext"], - "target": "ESNext", - "module": "Preserve", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, - - // Bundler mode - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, - - // Best practices - "strict": true, - "skipLibCheck": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, - - // Some stricter flags (disabled by default) - "noUnusedLocals": false, - "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false - } -}