diff --git a/.npmrc b/.npmrc index b6f27f1..d5831dd 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ engine-strict=true +legacy-peer-deps=true diff --git a/api/bundled.yaml b/api/bundled.yaml index 69acdf8..acc4ab1 100644 --- a/api/bundled.yaml +++ b/api/bundled.yaml @@ -2180,6 +2180,9 @@ components: type: object additionalProperties: $ref: '#/components/schemas/ConfigProperty' + optionsEndpoint: + $ref: '#/components/schemas/OptionsEndpoint' + description: REST endpoint to fetch options dynamically at runtime required: - type ConfigSchema: @@ -3602,6 +3605,52 @@ components: items: type: string description: Improvement suggestions + OptionsEndpoint: + type: object + description: Configuration for fetching select field options from a REST endpoint at runtime + required: + - url + properties: + url: + type: string + description: URL to fetch options from. Supports template variables {nodeTypeId}, {instanceId}, {workflowId} + example: /api/flowdrop/secrets + method: + type: string + enum: + - GET + - POST + default: GET + description: HTTP method for the request + headers: + type: object + additionalProperties: + type: string + description: Custom headers to include in the request + parameterMapping: + type: object + additionalProperties: + type: string + description: Maps template variables to node context paths + example: + nodeTypeId: metadata.id + instanceId: id + valuePath: + type: string + default: value + description: JSON path to extract option value from each item + labelPath: + type: string + default: label + description: JSON path to extract option label from each item + cacheTtl: + type: integer + default: 300000 + description: Cache TTL in milliseconds (default 5 minutes) + timeout: + type: integer + default: 10000 + description: Request timeout in milliseconds responses: BadRequest: description: Bad request - invalid parameters or request body diff --git a/api/components/schemas/config.yaml b/api/components/schemas/config.yaml index 76c0f7e..599f1b2 100644 --- a/api/components/schemas/config.yaml +++ b/api/components/schemas/config.yaml @@ -66,7 +66,7 @@ PortConfig: version: type: string description: Version of the port configuration - example: "1.0.0" + example: '1.0.0' defaultDataType: type: string description: Default data type to use when none specified @@ -85,6 +85,51 @@ PortConfig: - dataTypes - defaultDataType +OptionsEndpoint: + type: object + description: Configuration for fetching select field options from a REST endpoint at runtime + required: + - url + properties: + url: + type: string + description: URL to fetch options from. Supports template variables {nodeTypeId}, {instanceId}, {workflowId} + example: '/api/flowdrop/secrets' + method: + type: string + enum: [GET, POST] + default: GET + description: HTTP method for the request + headers: + type: object + additionalProperties: + type: string + description: Custom headers to include in the request + parameterMapping: + type: object + additionalProperties: + type: string + description: Maps template variables to node context paths + example: + nodeTypeId: 'metadata.id' + instanceId: 'id' + valuePath: + type: string + default: 'value' + description: JSON path to extract option value from each item + labelPath: + type: string + default: 'label' + description: JSON path to extract option label from each item + cacheTtl: + type: integer + default: 300000 + description: Cache TTL in milliseconds (default 5 minutes) + timeout: + type: integer + default: 10000 + description: Request timeout in milliseconds + ConfigProperty: type: object properties: @@ -143,6 +188,9 @@ ConfigProperty: type: object additionalProperties: $ref: '#/ConfigProperty' + optionsEndpoint: + $ref: '#/OptionsEndpoint' + description: REST endpoint to fetch options dynamically at runtime required: - type diff --git a/docs/plans/2026-01-27-options-endpoint-design.md b/docs/plans/2026-01-27-options-endpoint-design.md new file mode 100644 index 0000000..99bb6d1 --- /dev/null +++ b/docs/plans/2026-01-27-options-endpoint-design.md @@ -0,0 +1,308 @@ +# Design: REST Endpoint for Dynamic Enum Options + +**Issue:** https://github.com/flowdrop-io/flowdrop/issues/5 +**Date:** 2026-01-27 +**Status:** Approved + +## Summary + +Add support for fetching enum/select options from a REST endpoint at runtime, without requiring a full dynamic schema. Individual fields in a `configSchema` can specify an `optionsEndpoint` to populate their options dynamically. + +## Use Case + +An LLM node has an `api_key` field that should show a dropdown of available tenant secrets. The schema is static, but the options need to be fetched at runtime based on the current tenant. + +Currently, the only way to achieve this is via `configEdit.dynamicSchema`, which replaces the entire schema. This is overkill when only one field needs dynamic options. + +## Design Decisions + +| Decision | Choice | Rationale | +|----------|--------|-----------| +| Fetch strategy | Auto-fetch on render | Simplest UX, predictable behavior | +| Static vs fetched options | Fetched replaces static | Clear mental model; static serves as fallback on error | +| Configuration location | Field-level (`optionsEndpoint` on each field) | Consistent with existing `enum`, `options`, `format` patterns | +| Fetch timing | Pre-fetch in ConfigForm before rendering | Keeps FormField synchronous and simple | + +## Data Model + +### New Type: `OptionsEndpoint` + +Location: `src/lib/types/index.ts` + +```typescript +export interface OptionsEndpoint { + /** URL to fetch options from. Supports {nodeTypeId}, {instanceId}, {workflowId} variables */ + url: string; + /** HTTP method (default: GET) */ + method?: HttpMethod; + /** Custom headers for the request */ + headers?: Record; + /** Maps URL variables to node context paths */ + parameterMapping?: Record; + /** JSON path to extract option value from each item (default: "value") */ + valuePath?: string; + /** JSON path to extract option label from each item (default: "label") */ + labelPath?: string; + /** Cache TTL in milliseconds (default: 300000 = 5 minutes) */ + cacheTtl?: number; + /** Request timeout in milliseconds (default: 10000) */ + timeout?: number; +} +``` + +### Extended `FieldSchema` + +Location: `src/lib/components/form/types.ts` + +```typescript +export interface FieldSchema { + // ... existing properties ... + + /** REST endpoint to fetch options dynamically at runtime */ + optionsEndpoint?: OptionsEndpoint; +} +``` + +### Usage Example + +```json +{ + "configSchema": { + "type": "object", + "properties": { + "api_key": { + "type": "string", + "title": "API Key", + "optionsEndpoint": { + "url": "/api/flowdrop/secrets", + "valuePath": "name", + "labelPath": "label" + } + }, + "model": { + "type": "string", + "title": "Model", + "enum": ["gpt-4o", "gpt-4", "gpt-3.5-turbo"] + } + } + } +} +``` + +## Service Layer + +### New File: `src/lib/services/optionsService.ts` + +Follows the pattern established by `dynamicSchemaService.ts`. + +```typescript +import type { FieldOption } from '../components/form/types.js'; +import type { OptionsEndpoint, ConfigSchema, WorkflowNode } from '../types/index.js'; + +interface OptionsResult { + success: boolean; + options?: FieldOption[]; + error?: string; + fromCache?: boolean; +} + +interface AllOptionsResult { + options: Map; + errors: Map; +} + +// Fetch options for a single field +export async function fetchFieldOptions( + endpoint: OptionsEndpoint, + node: WorkflowNode, + workflowId?: string +): Promise; + +// Fetch options for all fields with optionsEndpoint in a schema (parallel) +export async function fetchAllFieldOptions( + schema: ConfigSchema, + node: WorkflowNode, + workflowId?: string +): Promise; + +// Check if schema has any fields with optionsEndpoint +export function hasFieldsWithOptionsEndpoint(schema: ConfigSchema): boolean; + +// Merge fetched options into schema (returns new schema) +export function mergeOptionsIntoSchema( + schema: ConfigSchema, + options: Map +): ConfigSchema; + +// Cache management +export function invalidateOptionsCache(pattern?: string): void; +``` + +### Key Behaviors + +1. **URL Resolution**: Reuse `resolveTemplate()` from shared utils for `{nodeTypeId}`, `{instanceId}`, `{workflowId}` variables +2. **Caching**: Cache by resolved URL with configurable TTL (default 5 minutes) +3. **Response Normalization**: Extract values using `valuePath`/`labelPath`, handle both array and wrapped responses +4. **Parallel Fetching**: `fetchAllFieldOptions` fetches all endpoints concurrently + +### Response Format Support + +The endpoint can return: + +**Direct array:** +```json +[ + { "name": "OPENAI_KEY", "label": "OpenAI Production" }, + { "name": "ANTHROPIC_KEY", "label": "Anthropic Claude" } +] +``` + +**Wrapped in object:** +```json +{ + "options": [ + { "value": "OPENAI_KEY", "label": "OpenAI Production" } + ] +} +``` + +With `valuePath: "name"` and `labelPath: "label"`, the service normalizes to: +```typescript +[ + { value: "OPENAI_KEY", label: "OpenAI Production" }, + { value: "ANTHROPIC_KEY", label: "Anthropic Claude" } +] +``` + +## Integration: ConfigForm.svelte + +### New State + +```typescript +let optionsLoading = $state(false); +let optionsErrors = $state>(new Map()); +let fetchedOptions = $state>(new Map()); +``` + +### Loading Flow + +```typescript +async function loadFieldOptions(schema: ConfigSchema): Promise { + if (!node) return; + + optionsLoading = true; + optionsErrors = new Map(); + + try { + const results = await fetchAllFieldOptions(schema, node, workflowId); + fetchedOptions = results.options; + optionsErrors = results.errors; + } finally { + optionsLoading = false; + } +} + +// Trigger loading when schema is ready +$effect(() => { + const schema = effectiveSchema; + if (schema && hasFieldsWithOptionsEndpoint(schema)) { + loadFieldOptions(schema); + } +}); +``` + +### Schema Enrichment + +```typescript +const enrichedSchema = $derived.by(() => { + if (!effectiveSchema || fetchedOptions.size === 0) return effectiveSchema; + return mergeOptionsIntoSchema(effectiveSchema, fetchedOptions); +}); +``` + +### Data Flow + +``` +Schema ready + → scan for optionsEndpoint fields + → fetch all in parallel + → merge into schema + → render form with populated options +``` + +## Shared Utilities + +### New File: `src/lib/utils/templateResolver.ts` + +Extract from `dynamicSchemaService.ts` for reuse: + +```typescript +export interface NodeContext { + id: string; + type: string; + metadata: WorkflowNode['data']['metadata']; + config: Record; + extensions?: WorkflowNode['data']['extensions']; + workflowId?: string; +} + +export function resolveVariablePath(context: NodeContext, path: string): string | undefined; + +export function resolveTemplate( + template: string, + parameterMapping: Record | undefined, + context: NodeContext +): string; + +export function buildNodeContext(node: WorkflowNode, workflowId?: string): NodeContext; +``` + +## Files to Create/Modify + +### New Files + +| File | Purpose | +|------|---------| +| `src/lib/services/optionsService.ts` | Options fetching, caching, response normalization | +| `src/lib/utils/templateResolver.ts` | Shared URL template resolution utilities | +| `tests/unit/services/optionsService.test.ts` | Unit tests for options service | +| `tests/integration/optionsEndpoint.test.ts` | Integration test with mock API | + +### Modified Files + +| File | Changes | +|------|---------| +| `src/lib/types/index.ts` | Add `OptionsEndpoint` interface | +| `src/lib/components/form/types.ts` | Add `optionsEndpoint` to `FieldSchema` | +| `src/lib/components/ConfigForm.svelte` | Add options loading, schema enrichment, loading/error UI | +| `src/lib/services/dynamicSchemaService.ts` | Import shared utils from `templateResolver.ts` | +| `src/lib/core/index.ts` | Export `OptionsEndpoint` type | +| `api/components/schemas/config.yaml` | Add `optionsEndpoint` to OpenAPI spec | + +## UI Behavior + +1. **Loading**: Show spinner/skeleton in the form while options are being fetched +2. **Success**: Populate select fields with fetched options +3. **Partial Failure**: Show per-field error message if specific endpoint fails; other fields still work +4. **Complete Failure**: Fall back to static `enum`/`options` if defined, otherwise show error + +## Out of Scope + +- Lazy loading on field focus (decided: auto-fetch on render) +- Merging fetched with static options (decided: fetched replaces static) +- Node-level optionsEndpoints configuration (decided: field-level only) +- Refresh button per field (can be added later if needed) + +## Testing Strategy + +1. **Unit tests** for `optionsService.ts`: + - URL template resolution + - Response normalization with various `valuePath`/`labelPath` combinations + - Cache hit/miss/expiry + - Error handling (timeout, HTTP errors, malformed response) + +2. **Integration tests**: + - Mock API with MSW + - ConfigForm renders with fetched options + - Fallback to static options on error + - Parallel fetching of multiple fields diff --git a/docs/plans/2026-01-27-options-endpoint-implementation.md b/docs/plans/2026-01-27-options-endpoint-implementation.md new file mode 100644 index 0000000..402596b --- /dev/null +++ b/docs/plans/2026-01-27-options-endpoint-implementation.md @@ -0,0 +1,1545 @@ +# Options Endpoint Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Implement REST endpoint support for dynamic field options, allowing select fields to fetch their options from an API at runtime. + +**Architecture:** Field-level `optionsEndpoint` property on schema fields. New `optionsService.ts` handles fetching with caching. `ConfigForm.svelte` pre-fetches all options before rendering and merges them into the schema. + +**Tech Stack:** TypeScript, Svelte 5 (runes), Vitest for testing + +--- + +## Task 1: Add OptionsEndpoint Type + +**Files:** +- Modify: `src/lib/types/index.ts` (after `DynamicSchemaEndpoint` interface, around line 260) + +**Step 1: Add the OptionsEndpoint interface** + +Add after the `DynamicSchemaEndpoint` interface (around line 260): + +```typescript +/** + * Options endpoint configuration for fetching select field options at runtime. + * Used when field options need to be populated dynamically from a REST API. + * + * @example + * ```typescript + * const optionsEndpoint: OptionsEndpoint = { + * url: "/api/flowdrop/secrets", + * valuePath: "name", + * labelPath: "label", + * cacheTtl: 300000 + * }; + * ``` + */ +export interface OptionsEndpoint { + /** + * URL to fetch options from. + * Supports template variables: {nodeTypeId}, {instanceId}, {workflowId} + */ + url: string; + + /** + * HTTP method for the request. + * @default "GET" + */ + method?: HttpMethod; + + /** + * Custom headers to include in the request. + */ + headers?: Record; + + /** + * Maps template variables to their source paths in node context. + * Keys are variable names, values are dot-notation paths. + */ + parameterMapping?: Record; + + /** + * JSON path to extract the option value from each item. + * @default "value" + */ + valuePath?: string; + + /** + * JSON path to extract the option label from each item. + * @default "label" + */ + labelPath?: string; + + /** + * Cache TTL in milliseconds. + * @default 300000 (5 minutes) + */ + cacheTtl?: number; + + /** + * Request timeout in milliseconds. + * @default 10000 + */ + timeout?: number; +} +``` + +**Step 2: Verify no TypeScript errors** + +Run: `npm run check` +Expected: No errors related to OptionsEndpoint + +**Step 3: Commit** + +```bash +jj desc -m "feat(types): add OptionsEndpoint interface for dynamic field options" +``` + +--- + +## Task 2: Export OptionsEndpoint from Core + +**Files:** +- Modify: `src/lib/core/index.ts` (around line 54, in the type exports) + +**Step 1: Add OptionsEndpoint to exports** + +Find this section (around line 52-58): + +```typescript + // Admin/Edit configuration types + HttpMethod, + DynamicSchemaEndpoint, + ExternalEditLink, + ConfigEditOptions, +``` + +Change to: + +```typescript + // Admin/Edit configuration types + HttpMethod, + DynamicSchemaEndpoint, + ExternalEditLink, + ConfigEditOptions, + OptionsEndpoint, +``` + +**Step 2: Verify export works** + +Run: `npm run check` +Expected: No errors + +**Step 3: Commit** + +```bash +jj desc -m "feat(core): export OptionsEndpoint type" +``` + +--- + +## Task 3: Extend FieldSchema with optionsEndpoint + +**Files:** +- Modify: `src/lib/components/form/types.ts` (around line 215, in FieldSchema interface) + +**Step 1: Add import for OptionsEndpoint** + +At the top of the file, add: + +```typescript +import type { OptionsEndpoint } from '$lib/types/index.js'; +``` + +**Step 2: Add optionsEndpoint to FieldSchema** + +Find the FieldSchema interface (starts around line 215). Add after the `[key: string]: unknown;` line (around line 257): + +```typescript + /** + * REST endpoint to fetch options dynamically at runtime. + * When specified, options are fetched from this endpoint and used + * instead of static `enum` or `options` values. + */ + optionsEndpoint?: OptionsEndpoint; +``` + +**Step 3: Verify no TypeScript errors** + +Run: `npm run check` +Expected: No errors + +**Step 4: Commit** + +```bash +jj desc -m "feat(form): add optionsEndpoint property to FieldSchema" +``` + +--- + +## Task 4: Create Template Resolver Utility + +**Files:** +- Create: `src/lib/utils/templateResolver.ts` +- Test: `tests/unit/utils/templateResolver.test.ts` + +**Step 1: Write the failing test** + +Create `tests/unit/utils/templateResolver.test.ts`: + +```typescript +/** + * Unit Tests - Template Resolver Utility + */ + +import { describe, it, expect } from 'vitest'; +import { + resolveVariablePath, + resolveTemplate, + buildNodeContext +} from '$lib/utils/templateResolver.js'; +import { createTestNode } from '../../utils/index.js'; + +describe('templateResolver', () => { + describe('resolveVariablePath', () => { + it('should resolve top-level properties', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node', name: 'LLM' }, + config: {} + }; + + expect(resolveVariablePath(context, 'id')).toBe('node-123'); + expect(resolveVariablePath(context, 'type')).toBe('default'); + }); + + it('should resolve nested properties with dot notation', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node', name: 'LLM Node' }, + config: { apiKey: 'secret-key' } + }; + + expect(resolveVariablePath(context, 'metadata.id')).toBe('llm-node'); + expect(resolveVariablePath(context, 'metadata.name')).toBe('LLM Node'); + expect(resolveVariablePath(context, 'config.apiKey')).toBe('secret-key'); + }); + + it('should return undefined for non-existent paths', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node' }, + config: {} + }; + + expect(resolveVariablePath(context, 'nonexistent')).toBeUndefined(); + expect(resolveVariablePath(context, 'metadata.nonexistent')).toBeUndefined(); + }); + }); + + describe('resolveTemplate', () => { + it('should replace variables with mapped values', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node' }, + config: {} + }; + const mapping = { nodeTypeId: 'metadata.id', instanceId: 'id' }; + + const result = resolveTemplate( + '/api/nodes/{nodeTypeId}/options/{instanceId}', + mapping, + context + ); + + expect(result).toBe('/api/nodes/llm-node/options/node-123'); + }); + + it('should URL-encode values', () => { + const context = { + id: 'node with spaces', + type: 'default', + metadata: { id: 'special/chars' }, + config: {} + }; + + const result = resolveTemplate('/api/{id}', { id: 'id' }, context); + + expect(result).toBe('/api/node%20with%20spaces'); + }); + + it('should resolve unmapped variables directly from context', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node' }, + config: {}, + workflowId: 'workflow-456' + }; + + const result = resolveTemplate('/api/{workflowId}/nodes', undefined, context); + + expect(result).toBe('/api/workflow-456/nodes'); + }); + }); + + describe('buildNodeContext', () => { + it('should build context from WorkflowNode', () => { + const node = createTestNode({ + id: 'test-node-1', + type: 'simple', + data: { + label: 'Test', + config: { setting: 'value' }, + metadata: { + id: 'test_node', + name: 'Test Node', + description: 'A test node', + category: 'processing', + version: '1.0.0', + inputs: [], + outputs: [] + } + } + }); + + const context = buildNodeContext(node, 'workflow-123'); + + expect(context.id).toBe('test-node-1'); + expect(context.type).toBe('simple'); + expect(context.metadata.id).toBe('test_node'); + expect(context.config.setting).toBe('value'); + expect(context.workflowId).toBe('workflow-123'); + }); + }); +}); +``` + +**Step 2: Run test to verify it fails** + +Run: `npm test -- tests/unit/utils/templateResolver.test.ts` +Expected: FAIL - module not found + +**Step 3: Create the templateResolver utility** + +Create `src/lib/utils/templateResolver.ts`: + +```typescript +/** + * Template Resolver Utility + * + * Provides URL template resolution for dynamic endpoints. + * Extracted from dynamicSchemaService for reuse across services. + * + * @module utils/templateResolver + */ + +import type { WorkflowNode } from '../types/index.js'; + +/** + * Context object containing all available data for resolving template variables + */ +export interface NodeContext { + /** Node instance ID */ + id: string; + /** Node type from xyflow */ + type: string; + /** Node metadata (id, name, type, category, etc.) */ + metadata: WorkflowNode['data']['metadata']; + /** Node configuration values */ + config: Record; + /** Node extensions */ + extensions?: WorkflowNode['data']['extensions']; + /** Current workflow ID (if available) */ + workflowId?: string; +} + +/** + * Resolves a template variable path from the node context. + * Supports dot-notation paths like "metadata.id", "config.apiKey", "id" + * + * @param context - The node context containing all available data + * @param path - Dot-notation path to resolve (e.g., "metadata.id") + * @returns The resolved value as a string, or undefined if not found + */ +export function resolveVariablePath( + context: Record, + path: string +): string | undefined { + const parts = path.split('.'); + let current: unknown = context; + + for (const part of parts) { + if (current === null || current === undefined) { + return undefined; + } + if (typeof current === 'object' && part in current) { + current = (current as Record)[part]; + } else { + return undefined; + } + } + + if (current === null || current === undefined) { + return undefined; + } + return String(current); +} + +/** + * Replaces template variables in a URL or string with values from the node context. + * Template variables use curly brace syntax: {variableName} + * + * @param template - The template string with variables + * @param parameterMapping - Maps variable names to context paths + * @param context - The node context containing all available data + * @returns The resolved string with all variables replaced + */ +export function resolveTemplate( + template: string, + parameterMapping: Record | undefined, + context: NodeContext +): string { + let resolved = template; + + // Replace each mapped variable + if (parameterMapping) { + for (const [variableName, contextPath] of Object.entries(parameterMapping)) { + const value = resolveVariablePath(context, contextPath); + if (value !== undefined) { + const regex = new RegExp(`\\{${variableName}\\}`, 'g'); + resolved = resolved.replace(regex, encodeURIComponent(value)); + } + } + } + + // Also try to resolve any unmapped variables directly from context + const remainingVariables = resolved.match(/\{([^}]+)\}/g); + if (remainingVariables) { + for (const variable of remainingVariables) { + const variableName = variable.slice(1, -1); + const value = resolveVariablePath(context, variableName); + if (value !== undefined) { + resolved = resolved.replace(variable, encodeURIComponent(value)); + } + } + } + + return resolved; +} + +/** + * Builds a NodeContext from a WorkflowNode. + * + * @param node - The workflow node + * @param workflowId - Optional workflow ID + * @returns The node context for template resolution + */ +export function buildNodeContext(node: WorkflowNode, workflowId?: string): NodeContext { + return { + id: node.id, + type: node.type, + metadata: node.data.metadata, + config: node.data.config, + extensions: node.data.extensions, + workflowId + }; +} +``` + +**Step 4: Run test to verify it passes** + +Run: `npm test -- tests/unit/utils/templateResolver.test.ts` +Expected: PASS + +**Step 5: Commit** + +```bash +jj desc -m "feat(utils): add templateResolver utility for URL template resolution" +``` + +--- + +## Task 5: Create Options Service + +**Files:** +- Create: `src/lib/services/optionsService.ts` +- Test: `tests/unit/services/optionsService.test.ts` + +**Step 1: Write the failing test** + +Create `tests/unit/services/optionsService.test.ts`: + +```typescript +/** + * Unit Tests - Options Service + */ + +import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; +import { + fetchFieldOptions, + fetchAllFieldOptions, + hasFieldsWithOptionsEndpoint, + mergeOptionsIntoSchema, + clearOptionsCache +} from '$lib/services/optionsService.js'; +import { createTestNode, mockFetchResponse, mockFetchError } from '../../utils/index.js'; +import type { ConfigSchema, OptionsEndpoint } from '$lib/types/index.js'; + +describe('optionsService', () => { + beforeEach(() => { + vi.clearAllMocks(); + clearOptionsCache(); + global.fetch = vi.fn(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('fetchFieldOptions', () => { + it('should fetch and normalize options with default paths', async () => { + const mockData = [ + { value: 'opt1', label: 'Option 1' }, + { value: 'opt2', label: 'Option 2' } + ]; + global.fetch = vi.fn(() => Promise.resolve(mockFetchResponse(mockData))); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(true); + expect(result.options).toEqual([ + { value: 'opt1', label: 'Option 1' }, + { value: 'opt2', label: 'Option 2' } + ]); + }); + + it('should normalize options with custom valuePath and labelPath', async () => { + const mockData = [ + { name: 'KEY_1', description: 'First Key' }, + { name: 'KEY_2', description: 'Second Key' } + ]; + global.fetch = vi.fn(() => Promise.resolve(mockFetchResponse(mockData))); + + const endpoint: OptionsEndpoint = { + url: '/api/secrets', + valuePath: 'name', + labelPath: 'description' + }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(true); + expect(result.options).toEqual([ + { value: 'KEY_1', label: 'First Key' }, + { value: 'KEY_2', label: 'Second Key' } + ]); + }); + + it('should handle wrapped response format', async () => { + const mockData = { + options: [ + { value: 'a', label: 'A' }, + { value: 'b', label: 'B' } + ] + }; + global.fetch = vi.fn(() => + Promise.resolve({ + ok: true, + status: 200, + json: async () => mockData + } as Response) + ); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(true); + expect(result.options).toHaveLength(2); + }); + + it('should return error on fetch failure', async () => { + global.fetch = vi.fn(() => Promise.resolve(mockFetchError('Not found', 404))); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(false); + expect(result.error).toContain('404'); + }); + + it('should cache results', async () => { + const mockData = [{ value: 'cached', label: 'Cached' }]; + global.fetch = vi.fn(() => Promise.resolve(mockFetchResponse(mockData))); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + // First call + await fetchFieldOptions(endpoint, node); + // Second call + const result = await fetchFieldOptions(endpoint, node); + + expect(global.fetch).toHaveBeenCalledTimes(1); + expect(result.fromCache).toBe(true); + }); + }); + + describe('hasFieldsWithOptionsEndpoint', () => { + it('should return true when schema has fields with optionsEndpoint', () => { + const schema: ConfigSchema = { + type: 'object', + properties: { + field1: { type: 'string' }, + field2: { type: 'string', optionsEndpoint: { url: '/api/options' } } + } + }; + + expect(hasFieldsWithOptionsEndpoint(schema)).toBe(true); + }); + + it('should return false when no fields have optionsEndpoint', () => { + const schema: ConfigSchema = { + type: 'object', + properties: { + field1: { type: 'string' }, + field2: { type: 'string', enum: ['a', 'b'] } + } + }; + + expect(hasFieldsWithOptionsEndpoint(schema)).toBe(false); + }); + }); + + describe('mergeOptionsIntoSchema', () => { + it('should merge fetched options into schema fields', () => { + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { + type: 'string', + title: 'API Key', + optionsEndpoint: { url: '/api/secrets' } + }, + model: { + type: 'string', + enum: ['gpt-4', 'gpt-3.5'] + } + } + }; + + const options = new Map([ + ['api_key', [{ value: 'KEY_1', label: 'Key 1' }, { value: 'KEY_2', label: 'Key 2' }]] + ]); + + const result = mergeOptionsIntoSchema(schema, options); + + expect(result.properties?.api_key?.options).toEqual([ + { value: 'KEY_1', label: 'Key 1' }, + { value: 'KEY_2', label: 'Key 2' } + ]); + // Original enum should be unchanged + expect(result.properties?.model?.enum).toEqual(['gpt-4', 'gpt-3.5']); + }); + }); + + describe('fetchAllFieldOptions', () => { + it('should fetch options for all fields in parallel', async () => { + global.fetch = vi.fn((url: string) => { + if (url.includes('secrets')) { + return Promise.resolve(mockFetchResponse([{ value: 'secret1', label: 'Secret 1' }])); + } + if (url.includes('models')) { + return Promise.resolve(mockFetchResponse([{ value: 'gpt-4', label: 'GPT-4' }])); + } + return Promise.resolve(mockFetchError('Not found', 404)); + }); + + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { type: 'string', optionsEndpoint: { url: '/api/secrets' } }, + model: { type: 'string', optionsEndpoint: { url: '/api/models' } } + } + }; + const node = createTestNode(); + + const result = await fetchAllFieldOptions(schema, node); + + expect(result.options.get('api_key')).toEqual([{ value: 'secret1', label: 'Secret 1' }]); + expect(result.options.get('model')).toEqual([{ value: 'gpt-4', label: 'GPT-4' }]); + expect(result.errors.size).toBe(0); + }); + + it('should collect errors for failed fetches', async () => { + global.fetch = vi.fn((url: string) => { + if (url.includes('secrets')) { + return Promise.resolve(mockFetchResponse([{ value: 'secret1', label: 'Secret 1' }])); + } + return Promise.resolve(mockFetchError('Server error', 500)); + }); + + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { type: 'string', optionsEndpoint: { url: '/api/secrets' } }, + model: { type: 'string', optionsEndpoint: { url: '/api/models' } } + } + }; + const node = createTestNode(); + + const result = await fetchAllFieldOptions(schema, node); + + expect(result.options.get('api_key')).toBeDefined(); + expect(result.errors.get('model')).toContain('500'); + }); + }); +}); +``` + +**Step 2: Run test to verify it fails** + +Run: `npm test -- tests/unit/services/optionsService.test.ts` +Expected: FAIL - module not found + +**Step 3: Create the optionsService** + +Create `src/lib/services/optionsService.ts`: + +```typescript +/** + * Options Service + * + * Handles fetching select field options from REST endpoints at runtime. + * Provides caching, parallel fetching, and response normalization. + * + * @module services/optionsService + */ + +import type { FieldOption } from '../components/form/types.js'; +import type { OptionsEndpoint, ConfigSchema, WorkflowNode } from '../types/index.js'; +import { resolveTemplate, buildNodeContext } from '../utils/templateResolver.js'; +import { getEndpointConfig } from './api.js'; + +/** + * Result of fetching options for a single field + */ +export interface OptionsResult { + /** Whether the fetch was successful */ + success: boolean; + /** The fetched options (if successful) */ + options?: FieldOption[]; + /** Error message (if failed) */ + error?: string; + /** Whether the result was loaded from cache */ + fromCache?: boolean; +} + +/** + * Result of fetching options for all fields + */ +export interface AllOptionsResult { + /** Map of field key to fetched options */ + options: Map; + /** Map of field key to error message */ + errors: Map; +} + +/** + * Cache entry for storing fetched options + */ +interface OptionsCacheEntry { + options: FieldOption[]; + cachedAt: number; + cacheKey: string; +} + +/** Options cache with TTL support */ +const optionsCache = new Map(); + +/** Default cache TTL: 5 minutes */ +const DEFAULT_CACHE_TTL = 5 * 60 * 1000; + +/** Default request timeout: 10 seconds */ +const DEFAULT_TIMEOUT = 10000; + +/** + * Checks if a cached entry is still valid + */ +function isCacheValid(entry: OptionsCacheEntry, ttl: number): boolean { + return Date.now() - entry.cachedAt < ttl; +} + +/** + * Generates a cache key based on resolved URL + */ +function generateCacheKey(resolvedUrl: string): string { + return `options:${resolvedUrl}`; +} + +/** + * Extracts a value from an object using a path + */ +function extractValue(obj: Record, path: string): unknown { + const parts = path.split('.'); + let current: unknown = obj; + + for (const part of parts) { + if (current === null || current === undefined) { + return undefined; + } + if (typeof current === 'object' && part in current) { + current = (current as Record)[part]; + } else { + return undefined; + } + } + + return current; +} + +/** + * Normalizes API response to FieldOption array + */ +function normalizeOptions( + data: unknown, + valuePath: string = 'value', + labelPath: string = 'label' +): FieldOption[] { + // Handle wrapped response: { options: [...] } or { data: [...] } + let items: unknown[]; + if (Array.isArray(data)) { + items = data; + } else if (typeof data === 'object' && data !== null) { + const obj = data as Record; + if (Array.isArray(obj.options)) { + items = obj.options; + } else if (Array.isArray(obj.data)) { + items = obj.data; + } else { + return []; + } + } else { + return []; + } + + return items + .map((item) => { + if (typeof item !== 'object' || item === null) { + return null; + } + const obj = item as Record; + const value = extractValue(obj, valuePath); + const label = extractValue(obj, labelPath); + + if (value === undefined) { + return null; + } + + return { + value: String(value), + label: String(label ?? value) + }; + }) + .filter((opt): opt is FieldOption => opt !== null); +} + +/** + * Fetches options for a single field from a REST endpoint. + * + * @param endpoint - The options endpoint configuration + * @param node - The workflow node instance + * @param workflowId - Optional workflow ID for context + * @returns A promise that resolves to the options result + */ +export async function fetchFieldOptions( + endpoint: OptionsEndpoint, + node: WorkflowNode, + workflowId?: string +): Promise { + const context = buildNodeContext(node, workflowId); + const cacheTtl = endpoint.cacheTtl ?? DEFAULT_CACHE_TTL; + const timeout = endpoint.timeout ?? DEFAULT_TIMEOUT; + + // Resolve URL with template variables + let url = resolveTemplate(endpoint.url, endpoint.parameterMapping, context); + + // Prepend base URL for relative URLs + if (url.startsWith('/')) { + const currentConfig = getEndpointConfig(); + if (currentConfig?.baseUrl) { + const baseUrl = currentConfig.baseUrl.replace(/\/$/, ''); + url = `${baseUrl}${url}`; + } + } + + // Check cache + const cacheKey = generateCacheKey(url); + const cached = optionsCache.get(cacheKey); + if (cached && isCacheValid(cached, cacheTtl)) { + return { + success: true, + options: cached.options, + fromCache: true + }; + } + + // Prepare request + const method = endpoint.method ?? 'GET'; + const headers: Record = { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...endpoint.headers + }; + + // Add auth headers from endpoint config + const currentConfig = getEndpointConfig(); + if (currentConfig?.auth) { + if (currentConfig.auth.type === 'bearer' && currentConfig.auth.token) { + headers['Authorization'] = `Bearer ${currentConfig.auth.token}`; + } else if (currentConfig.auth.type === 'api_key' && currentConfig.auth.apiKey) { + headers['X-API-Key'] = currentConfig.auth.apiKey; + } else if (currentConfig.auth.type === 'custom' && currentConfig.auth.headers) { + Object.assign(headers, currentConfig.auth.headers); + } + } + + const fetchOptions: RequestInit = { + method, + headers, + signal: AbortSignal.timeout(timeout) + }; + + try { + const response = await fetch(url, fetchOptions); + + if (!response.ok) { + const errorText = await response.text(); + return { + success: false, + error: `HTTP ${response.status}: ${errorText || response.statusText}` + }; + } + + const data = await response.json(); + const options = normalizeOptions(data, endpoint.valuePath, endpoint.labelPath); + + // Cache the result + optionsCache.set(cacheKey, { + options, + cachedAt: Date.now(), + cacheKey + }); + + return { + success: true, + options, + fromCache: false + }; + } catch (error) { + if (error instanceof Error) { + if (error.name === 'AbortError' || error.name === 'TimeoutError') { + return { + success: false, + error: `Request timed out after ${timeout}ms` + }; + } + return { + success: false, + error: error.message + }; + } + return { + success: false, + error: 'Unknown error occurred while fetching options' + }; + } +} + +/** + * Checks if a schema has any fields with optionsEndpoint configured. + * + * @param schema - The config schema to check + * @returns True if any field has optionsEndpoint + */ +export function hasFieldsWithOptionsEndpoint(schema: ConfigSchema): boolean { + if (!schema.properties) { + return false; + } + + return Object.values(schema.properties).some( + (prop) => typeof prop === 'object' && prop !== null && 'optionsEndpoint' in prop + ); +} + +/** + * Fetches options for all fields with optionsEndpoint in a schema. + * Fetches are performed in parallel for efficiency. + * + * @param schema - The config schema + * @param node - The workflow node instance + * @param workflowId - Optional workflow ID for context + * @returns A promise with options and errors maps + */ +export async function fetchAllFieldOptions( + schema: ConfigSchema, + node: WorkflowNode, + workflowId?: string +): Promise { + const options = new Map(); + const errors = new Map(); + + if (!schema.properties) { + return { options, errors }; + } + + // Collect all fields with optionsEndpoint + const fieldsToFetch: Array<{ key: string; endpoint: OptionsEndpoint }> = []; + for (const [key, prop] of Object.entries(schema.properties)) { + if (typeof prop === 'object' && prop !== null && 'optionsEndpoint' in prop) { + const endpoint = prop.optionsEndpoint as OptionsEndpoint; + if (endpoint) { + fieldsToFetch.push({ key, endpoint }); + } + } + } + + // Fetch all in parallel + const results = await Promise.all( + fieldsToFetch.map(async ({ key, endpoint }) => { + const result = await fetchFieldOptions(endpoint, node, workflowId); + return { key, result }; + }) + ); + + // Collect results + for (const { key, result } of results) { + if (result.success && result.options) { + options.set(key, result.options); + } else if (result.error) { + errors.set(key, result.error); + } + } + + return { options, errors }; +} + +/** + * Merges fetched options into a schema, returning a new schema. + * Options are added to the `options` property of each field. + * + * @param schema - The original config schema + * @param fetchedOptions - Map of field key to options + * @returns A new schema with options merged in + */ +export function mergeOptionsIntoSchema( + schema: ConfigSchema, + fetchedOptions: Map +): ConfigSchema { + if (!schema.properties || fetchedOptions.size === 0) { + return schema; + } + + const newProperties: Record = {}; + + for (const [key, prop] of Object.entries(schema.properties)) { + const options = fetchedOptions.get(key); + if (options) { + // Clone the property and add options + newProperties[key] = { + ...(prop as object), + options + }; + } else { + newProperties[key] = prop; + } + } + + return { + ...schema, + properties: newProperties + }; +} + +/** + * Clears the options cache. + * + * @param pattern - Optional pattern to match cache keys + */ +export function clearOptionsCache(pattern?: string): void { + if (!pattern) { + optionsCache.clear(); + return; + } + + for (const key of optionsCache.keys()) { + if (key.includes(pattern)) { + optionsCache.delete(key); + } + } +} + +/** + * Invalidates cache for a specific URL pattern. + * + * @param urlPattern - URL pattern to invalidate + */ +export function invalidateOptionsCache(urlPattern: string): void { + clearOptionsCache(urlPattern); +} +``` + +**Step 4: Run test to verify it passes** + +Run: `npm test -- tests/unit/services/optionsService.test.ts` +Expected: PASS (or most tests pass - some may need adjustment based on actual response format) + +**Step 5: Commit** + +```bash +jj desc -m "feat(services): add optionsService for fetching dynamic field options" +``` + +--- + +## Task 6: Integrate Options Loading in ConfigForm + +**Files:** +- Modify: `src/lib/components/ConfigForm.svelte` + +**Step 1: Add imports** + +At the top of the script section (around line 28), add: + +```typescript +import { + fetchAllFieldOptions, + hasFieldsWithOptionsEndpoint, + mergeOptionsIntoSchema +} from '$lib/services/optionsService.js'; +import type { FieldOption } from '$lib/components/form/types.js'; +``` + +**Step 2: Add state for options loading** + +After the dynamic schema state (around line 74), add: + +```typescript +/** + * State for field options loading + */ +let optionsLoading = $state(false); +let optionsErrors = $state>(new Map()); +let fetchedOptions = $state>(new Map()); +``` + +**Step 3: Add the loadFieldOptions function** + +After the `loadDynamicSchema` function (around line 190), add: + +```typescript +/** + * Load options for fields with optionsEndpoint + */ +async function loadFieldOptions(schema: ConfigSchema): Promise { + if (!node) return; + + optionsLoading = true; + optionsErrors = new Map(); + + try { + const result = await fetchAllFieldOptions(schema, node, workflowId); + fetchedOptions = result.options; + optionsErrors = result.errors; + } catch (err) { + console.error('Failed to load field options:', err); + } finally { + optionsLoading = false; + } +} +``` + +**Step 4: Add effect to trigger options loading** + +After the dynamic schema effect (around line 230), add: + +```typescript +/** + * Load field options when schema is available + */ +$effect(() => { + const schema = configSchema; + if (schema && hasFieldsWithOptionsEndpoint(schema) && !optionsLoading) { + loadFieldOptions(schema); + } +}); +``` + +**Step 5: Add enrichedSchema derived state** + +After the `effectiveSchema` derived (if exists) or after `configSchema` derived, add: + +```typescript +/** + * Schema with fetched options merged in + */ +const enrichedSchema = $derived.by(() => { + if (!configSchema) return configSchema; + if (fetchedOptions.size === 0) return configSchema; + return mergeOptionsIntoSchema(configSchema, fetchedOptions); +}); +``` + +**Step 6: Update the SchemaForm to use enrichedSchema** + +Find where `SchemaForm` is rendered (search for ` +``` + +**Step 7: Add loading indicator for options** + +Near the existing loading indicator (around line 384), add a condition for options loading: + +```svelte +{#if dynamicSchemaLoading || optionsLoading} +
+ +
+{/if} +``` + +**Step 8: Verify no TypeScript errors** + +Run: `npm run check` +Expected: No errors + +**Step 9: Commit** + +```bash +jj desc -m "feat(ConfigForm): integrate optionsService for dynamic field options" +``` + +--- + +## Task 7: Update dynamicSchemaService to use shared utils + +**Files:** +- Modify: `src/lib/services/dynamicSchemaService.ts` + +**Step 1: Add import for shared utils** + +Replace the `NodeContext` interface and `resolveVariablePath`/`resolveTemplate` functions with imports: + +At the top of the file, add: + +```typescript +import { resolveTemplate, buildNodeContext, type NodeContext } from '../utils/templateResolver.js'; +``` + +**Step 2: Remove duplicated code** + +Remove the following from dynamicSchemaService.ts (they're now in templateResolver.ts): +- The `NodeContext` interface (lines ~21-34) +- The `resolveVariablePath` function (lines ~88-108) +- The `resolveTemplate` function (lines ~128-162) + +**Step 3: Update function calls** + +The `fetchDynamicSchema` function should already work since we're using the same function signatures. Update the context building to use `buildNodeContext`: + +Replace: +```typescript +const context: NodeContext = { + id: node.id, + type: node.type, + metadata: node.data.metadata, + config: node.data.config, + extensions: node.data.extensions, + workflowId +}; +``` + +With: +```typescript +const context = buildNodeContext(node, workflowId); +``` + +**Step 4: Verify tests still pass** + +Run: `npm test` +Expected: All existing tests pass + +**Step 5: Commit** + +```bash +jj desc -m "refactor(dynamicSchemaService): use shared templateResolver utils" +``` + +--- + +## Task 8: Add OpenAPI Spec for optionsEndpoint + +**Files:** +- Modify: `api/components/schemas/config.yaml` + +**Step 1: Add OptionsEndpoint schema** + +Add after the existing schema definitions: + +```yaml +OptionsEndpoint: + type: object + description: Configuration for fetching select field options from a REST endpoint + required: + - url + properties: + url: + type: string + description: URL to fetch options from. Supports template variables {nodeTypeId}, {instanceId}, {workflowId} + example: "/api/flowdrop/secrets" + method: + type: string + enum: [GET, POST] + default: GET + description: HTTP method for the request + headers: + type: object + additionalProperties: + type: string + description: Custom headers to include in the request + parameterMapping: + type: object + additionalProperties: + type: string + description: Maps template variables to node context paths + valuePath: + type: string + default: "value" + description: JSON path to extract option value from each item + labelPath: + type: string + default: "label" + description: JSON path to extract option label from each item + cacheTtl: + type: integer + default: 300000 + description: Cache TTL in milliseconds (default 5 minutes) + timeout: + type: integer + default: 10000 + description: Request timeout in milliseconds +``` + +**Step 2: Update ConfigProperty to include optionsEndpoint** + +Find the ConfigProperty schema and add: + +```yaml +optionsEndpoint: + $ref: '#/components/schemas/OptionsEndpoint' +``` + +**Step 3: Bundle the spec** + +Run: `npm run api:bundle` (or the equivalent command) +Expected: bundled.yaml is updated + +**Step 4: Commit** + +```bash +jj desc -m "docs(api): add OptionsEndpoint to OpenAPI spec" +``` + +--- + +## Task 9: Final Integration Test + +**Files:** +- Create: `tests/integration/optionsEndpoint.test.ts` + +**Step 1: Write integration test** + +Create `tests/integration/optionsEndpoint.test.ts`: + +```typescript +/** + * Integration Test - Options Endpoint Feature + */ + +import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; +import { + fetchAllFieldOptions, + mergeOptionsIntoSchema, + clearOptionsCache +} from '$lib/services/optionsService.js'; +import { createTestNode, mockFetchResponse } from '../utils/index.js'; +import type { ConfigSchema } from '$lib/types/index.js'; + +describe('Options Endpoint Integration', () => { + beforeEach(() => { + vi.clearAllMocks(); + clearOptionsCache(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('should fetch options and merge into schema for form rendering', async () => { + // Mock API response + global.fetch = vi.fn(() => + Promise.resolve( + mockFetchResponse([ + { name: 'OPENAI_KEY', label: 'OpenAI Production Key' }, + { name: 'ANTHROPIC_KEY', label: 'Anthropic Claude Key' } + ]) + ) + ); + + // Schema with optionsEndpoint + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { + type: 'string', + title: 'API Key', + optionsEndpoint: { + url: '/api/secrets', + valuePath: 'name', + labelPath: 'label' + } + }, + temperature: { + type: 'number', + title: 'Temperature', + minimum: 0, + maximum: 2 + } + } + }; + + const node = createTestNode(); + + // Fetch options + const result = await fetchAllFieldOptions(schema, node); + expect(result.options.has('api_key')).toBe(true); + expect(result.errors.size).toBe(0); + + // Merge into schema + const enrichedSchema = mergeOptionsIntoSchema(schema, result.options); + + // Verify merged schema + expect(enrichedSchema.properties?.api_key?.options).toEqual([ + { value: 'OPENAI_KEY', label: 'OpenAI Production Key' }, + { value: 'ANTHROPIC_KEY', label: 'Anthropic Claude Key' } + ]); + + // Non-options fields should be unchanged + expect(enrichedSchema.properties?.temperature?.minimum).toBe(0); + }); + + it('should fall back gracefully on fetch error', async () => { + global.fetch = vi.fn(() => Promise.reject(new Error('Network error'))); + + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { + type: 'string', + title: 'API Key', + enum: ['default-key'], // Static fallback + optionsEndpoint: { url: '/api/secrets' } + } + } + }; + + const node = createTestNode(); + const result = await fetchAllFieldOptions(schema, node); + + // Should have error, no options + expect(result.errors.has('api_key')).toBe(true); + expect(result.options.has('api_key')).toBe(false); + + // Merge returns original schema when no options + const enrichedSchema = mergeOptionsIntoSchema(schema, result.options); + expect(enrichedSchema.properties?.api_key?.enum).toEqual(['default-key']); + }); +}); +``` + +**Step 2: Run integration test** + +Run: `npm test -- tests/integration/optionsEndpoint.test.ts` +Expected: PASS + +**Step 3: Run full test suite** + +Run: `npm test` +Expected: All tests pass + +**Step 4: Commit** + +```bash +jj desc -m "test: add integration tests for optionsEndpoint feature" +``` + +--- + +## Task 10: Final Verification and Squash + +**Step 1: Run all checks** + +```bash +npm run lint +npm run check +npm test +``` + +Expected: All pass + +**Step 2: Update bookmark and squash commits** + +```bash +jj log -r '::@' +jj squash --into -m "feat: implement optionsEndpoint for dynamic field options (fixes #5)" +jj bookmark set feat/options-endpoint +``` + +**Step 3: Push to remote** + +```bash +jj git push -b feat/options-endpoint +``` + +--- + +## Summary + +This plan implements: + +1. **Types**: `OptionsEndpoint` interface in `types/index.ts` +2. **Utilities**: `templateResolver.ts` for shared URL template resolution +3. **Service**: `optionsService.ts` for fetching, caching, and normalizing options +4. **Integration**: `ConfigForm.svelte` pre-fetches and merges options into schema +5. **Refactor**: `dynamicSchemaService.ts` uses shared utilities +6. **Docs**: OpenAPI spec updated with `OptionsEndpoint` +7. **Tests**: Unit and integration tests + +Total estimated time: 2-3 hours diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..13db921 --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +node = "20.19" diff --git a/package-lock.json b/package-lock.json index e02f145..10a3b86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,8 @@ "vite": "^6.2.6", "vite-plugin-devtools-json": "^0.2.1", "vitest": "^3.2.3", - "vitest-browser-svelte": "^0.1.0" + "vitest-browser-svelte": "^0.1.0", + "yaml": "^2.8.2" }, "peerDependencies": { "@iconify/svelte": "^5.0.0", @@ -98,13 +99,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -133,13 +134,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.28.6" }, "bin": { "parser": "bin/babel-parser.js" @@ -149,9 +150,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "dev": true, "license": "MIT", "engines": { @@ -159,9 +160,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { @@ -183,14 +184,14 @@ } }, "node_modules/@chromatic-com/storybook": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-4.1.1.tgz", - "integrity": "sha512-+Ib4cHtEjKl/Do+4LyU0U1FhLPbIU2Q/zgbOKHBCV+dTC4T3/vGzPqiGsgkdnZyTsK/zXg96LMPSPC4jjOiapg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-4.1.3.tgz", + "integrity": "sha512-hc0HO9GAV9pxqDE6fTVOV5KeLpTiCfV8Jrpk5ogKLiIgeq2C+NPjpt74YnrZTjiK8E19fYcMP+2WY9ZtX7zHmw==", "dev": true, "license": "MIT", "dependencies": { "@neoconfetti/react": "^1.0.0", - "chromatic": "^12.0.0", + "chromatic": "^13.3.3", "filesize": "^10.0.12", "jsonfile": "^6.1.0", "strip-ansi": "^7.1.0" @@ -200,7 +201,7 @@ "yarn": ">=1.22.18" }, "peerDependencies": { - "storybook": "^0.0.0-0 || ^9.0.0 || ^9.1.0-0 || ^9.2.0-0 || ^10.0.0-0" + "storybook": "^0.0.0-0 || ^9.0.0 || ^9.1.0-0 || ^9.2.0-0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0" } }, "node_modules/@codemirror/autocomplete": { @@ -263,20 +264,20 @@ } }, "node_modules/@codemirror/search": { - "version": "6.5.11", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz", - "integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.6.0.tgz", + "integrity": "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", + "@codemirror/view": "^6.37.0", "crelt": "^1.0.5" } }, "node_modules/@codemirror/state": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.3.tgz", - "integrity": "sha512-MerMzJzlXogk2fxWFU1nKp36bY5orBG59HnPiz0G9nLRebWa0zXuv2siH6PLIHBvv5TH8CkQRqjBs0MlxCZu+A==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.4.tgz", + "integrity": "sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==", "license": "MIT", "dependencies": { "@marijn/find-cluster-break": "^1.0.0" @@ -295,9 +296,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.39.8", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.8.tgz", - "integrity": "sha512-1rASYd9Z/mE3tkbC9wInRlCNyCkSn+nLsiQKZhEDUUJiUfs/5FHDpCUDaQpoTIaNGeDc6/bhaEAyLmeEucEFPw==", + "version": "6.39.11", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.11.tgz", + "integrity": "sha512-bWdeR8gWM87l4DB/kYSF9A+dVackzDb/V56Tq7QVrQ7rn86W0rgZFtlL3g3pem6AeGcb9NQNoy3ao4WpW4h5tQ==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.5.0", @@ -331,9 +332,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", - "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -348,9 +349,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", - "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -365,9 +366,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", - "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -382,9 +383,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", - "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -399,9 +400,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", - "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -416,9 +417,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", - "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -433,9 +434,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", - "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -450,9 +451,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", - "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -467,9 +468,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", - "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -484,9 +485,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", - "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -501,9 +502,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", - "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -518,9 +519,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", - "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -535,9 +536,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", - "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -552,9 +553,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", - "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -569,9 +570,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", - "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -586,9 +587,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", - "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -603,9 +604,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", - "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -620,9 +621,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", - "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], @@ -637,9 +638,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", - "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -654,9 +655,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", - "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], @@ -671,9 +672,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", - "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -688,9 +689,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", - "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", "cpu": [ "arm64" ], @@ -705,9 +706,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", - "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -722,9 +723,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", - "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -739,9 +740,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", - "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -756,9 +757,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", - "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -773,9 +774,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -815,13 +816,13 @@ } }, "node_modules/@eslint/compat": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.4.0.tgz", - "integrity": "sha512-DEzm5dKeDBPm3r08Ixli/0cmxr8LkRdwxMRUIJBlSCpAwSrvFEJpVBzV+66JhDxiaqKxnRzCXhtiMiczF7Hglg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.4.1.tgz", + "integrity": "sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.16.0" + "@eslint/core": "^0.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -851,22 +852,22 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.1.tgz", - "integrity": "sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.16.0" + "@eslint/core": "^0.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", - "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -877,9 +878,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -889,7 +890,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -900,6 +901,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -913,10 +931,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/@eslint/js": { - "version": "9.38.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", - "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { @@ -937,13 +962,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", - "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.16.0", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { @@ -1031,9 +1056,9 @@ } }, "node_modules/@iconify/svelte": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@iconify/svelte/-/svelte-5.0.2.tgz", - "integrity": "sha512-1iWUT+1veS/QOAzKDG0NPgBtJYGoJqEPwF97voTm8jw6PQ6yU0hL73lEwFoTGMrZmatLvh9cjRBmeSHHaltmrg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@iconify/svelte/-/svelte-5.2.1.tgz", + "integrity": "sha512-zHmsIPmnIhGd5gc95bNN5FL+GifwMZv7M2rlZEpa7IXYGFJm/XGHdWf6PWQa6OBoC+R69WyiPO9NAj5wjfjbow==", "dev": true, "license": "MIT", "dependencies": { @@ -1043,7 +1068,7 @@ "url": "https://github.com/sponsors/cyberalien" }, "peerDependencies": { - "svelte": ">4.0.0" + "svelte": ">5.0.0" } }, "node_modules/@iconify/types": { @@ -1113,6 +1138,56 @@ } } }, + "node_modules/@inquirer/core/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@inquirer/core/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/core/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@inquirer/figures": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", @@ -1182,62 +1257,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -1252,6 +1271,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1262,6 +1282,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1272,6 +1293,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1292,12 +1314,14 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1331,9 +1355,9 @@ } }, "node_modules/@lezer/lr": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.5.tgz", - "integrity": "sha512-/YTRKP5yPPSo1xImYQk7AZZMAgap0kegzqCSYHjAL9x1AZ0ZQW+IpcEzMKagCsbTsLnVeWkxYrCNeXG8xEPrjg==", + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.8.tgz", + "integrity": "sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==", "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" @@ -1401,44 +1425,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@open-draft/deferred-promise": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", @@ -1685,13 +1671,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", - "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", + "version": "1.58.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.0.tgz", + "integrity": "sha512-fWza+Lpbj6SkQKCrU6si4iu+fD2dD3gxNHFhUPxsfXBPhnv3rRSQVd0NtBUT9Z/RhF/boCBcuUaMUSTRTopjZg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.56.1" + "playwright": "1.58.0" }, "bin": { "playwright": "cli.js" @@ -1782,9 +1768,9 @@ "license": "BSD-3-Clause" }, "node_modules/@publint/pack": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@publint/pack/-/pack-0.1.2.tgz", - "integrity": "sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@publint/pack/-/pack-0.1.3.tgz", + "integrity": "sha512-dHDWeutAerz+Z2wFYAce7Y51vd4rbLBfUh0BNnyul4xKoVsPUVJBrOAFsJvtvYBwGFJSqKsxyyHf/7evZ8+Q5Q==", "dev": true, "license": "MIT", "engines": { @@ -1811,13 +1797,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@redocly/ajv/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/@redocly/cli": { "version": "2.14.9", "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-2.14.9.tgz", @@ -1863,11 +1842,44 @@ "npm": ">=10" } }, - "node_modules/@redocly/cli/node_modules/ajv": { + "node_modules/@redocly/config": { + "version": "0.41.2", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.41.2.tgz", + "integrity": "sha512-G6muhdTKcEV2TECBFzuT905p4a27OgUtwBqRVnMx1JebO6i8zlm6bPB2H3fD1Hl+MiUpk7Jx2kwGmLVgpz5nIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "2.7.2" + } + }, + "node_modules/@redocly/openapi-core": { + "version": "2.14.9", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-2.14.9.tgz", + "integrity": "sha512-PIWVxm7Os3U276XMhLIh+qftaA6TxVwOuoyDaobGSkd609fp25tp57G2k/uzzKjrhUD4g2QzeJ4lfCoaBgEjhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/ajv": "^8.17.2", + "@redocly/config": "^0.41.2", + "ajv": "npm:@redocly/ajv@8.17.2", + "ajv-formats": "^3.0.1", + "colorette": "^1.2.0", + "js-levenshtein": "^1.1.6", + "js-yaml": "^4.1.0", + "picomatch": "^4.0.3", + "pluralize": "^8.0.0", + "yaml-ast-parser": "0.0.43" + }, + "engines": { + "node": ">=22.12.0 || >=20.19.0 <21.0.0", + "npm": ">=10" + } + }, + "node_modules/@redocly/openapi-core/node_modules/ajv": { "name": "@redocly/ajv", - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==", + "version": "8.17.2", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.17.2.tgz", + "integrity": "sha512-rcbDZOfXAgGEJeJ30aWCVVJvxV9ooevb/m1/SFblO2qHs4cqTk178gx7T/vdslf57EA4lTofrwsq5K8rxK9g+g==", "dev": true, "license": "MIT", "dependencies": { @@ -1881,338 +1893,36 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@redocly/cli/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/@redocly/respect-core": { + "version": "2.14.9", + "resolved": "https://registry.npmjs.org/@redocly/respect-core/-/respect-core-2.14.9.tgz", + "integrity": "sha512-kP3rylB04NZV52IoEa1t8ObkSxpRZy3zpkRAxYOiLtggRETOnLdcDbYep4ipbk6t0suZamznOLOgiAeBYHo/ig==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "@faker-js/faker": "^7.6.0", + "@noble/hashes": "^1.8.0", + "@redocly/ajv": "8.17.1", + "@redocly/openapi-core": "2.14.9", + "ajv": "npm:@redocly/ajv@8.17.1", + "better-ajv-errors": "^1.2.0", + "colorette": "^2.0.20", + "json-pointer": "^0.6.2", + "jsonpath-rfc9535": "1.3.0", + "openapi-sampler": "^1.6.1", + "outdent": "^0.8.0" }, "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=22.12.0 || >=20.19.0 <21.0.0", + "npm": ">=10" } }, - "node_modules/@redocly/cli/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/@redocly/respect-core/node_modules/@redocly/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==", "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/@redocly/cli/node_modules/glob": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", - "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@redocly/cli/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@redocly/cli/node_modules/jackspeak": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", - "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@redocly/cli/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@redocly/cli/node_modules/lru-cache": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@redocly/cli/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@redocly/cli/node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@redocly/cli/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/@redocly/cli/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@redocly/cli/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@redocly/cli/node_modules/yargs": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", - "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@redocly/cli/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/@redocly/config": { - "version": "0.41.2", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.41.2.tgz", - "integrity": "sha512-G6muhdTKcEV2TECBFzuT905p4a27OgUtwBqRVnMx1JebO6i8zlm6bPB2H3fD1Hl+MiUpk7Jx2kwGmLVgpz5nIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-schema-to-ts": "2.7.2" - } - }, - "node_modules/@redocly/openapi-core": { - "version": "2.14.9", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-2.14.9.tgz", - "integrity": "sha512-PIWVxm7Os3U276XMhLIh+qftaA6TxVwOuoyDaobGSkd609fp25tp57G2k/uzzKjrhUD4g2QzeJ4lfCoaBgEjhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@redocly/ajv": "^8.17.2", - "@redocly/config": "^0.41.2", - "ajv": "npm:@redocly/ajv@8.17.2", - "ajv-formats": "^3.0.1", - "colorette": "^1.2.0", - "js-levenshtein": "^1.1.6", - "js-yaml": "^4.1.0", - "picomatch": "^4.0.3", - "pluralize": "^8.0.0", - "yaml-ast-parser": "0.0.43" - }, - "engines": { - "node": ">=22.12.0 || >=20.19.0 <21.0.0", - "npm": ">=10" - } - }, - "node_modules/@redocly/openapi-core/node_modules/ajv": { - "name": "@redocly/ajv", - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.17.2.tgz", - "integrity": "sha512-rcbDZOfXAgGEJeJ30aWCVVJvxV9ooevb/m1/SFblO2qHs4cqTk178gx7T/vdslf57EA4lTofrwsq5K8rxK9g+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@redocly/openapi-core/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@redocly/openapi-core/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@redocly/respect-core": { - "version": "2.14.9", - "resolved": "https://registry.npmjs.org/@redocly/respect-core/-/respect-core-2.14.9.tgz", - "integrity": "sha512-kP3rylB04NZV52IoEa1t8ObkSxpRZy3zpkRAxYOiLtggRETOnLdcDbYep4ipbk6t0suZamznOLOgiAeBYHo/ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@faker-js/faker": "^7.6.0", - "@noble/hashes": "^1.8.0", - "@redocly/ajv": "8.17.1", - "@redocly/openapi-core": "2.14.9", - "ajv": "npm:@redocly/ajv@8.17.1", - "better-ajv-errors": "^1.2.0", - "colorette": "^2.0.20", - "json-pointer": "^0.6.2", - "jsonpath-rfc9535": "1.3.0", - "openapi-sampler": "^1.6.1", - "outdent": "^0.8.0" - }, - "engines": { - "node": ">=22.12.0 || >=20.19.0 <21.0.0", - "npm": ">=10" - } - }, - "node_modules/@redocly/respect-core/node_modules/@redocly/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@redocly/respect-core/node_modules/ajv": { - "name": "@redocly/ajv", - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==", - "dev": true, - "license": "MIT", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -2231,13 +1941,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@redocly/respect-core/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/plugin-commonjs": { "version": "28.0.9", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.9.tgz", @@ -2250,69 +1953,21 @@ "estree-walker": "^2.0.2", "fdir": "^6.2.0", "is-reference": "1.2.1", - "magic-string": "^0.30.3", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=16.0.0 || 14 >= 14.17" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/plugin-commonjs/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" + }, "engines": { - "node": ">=12.0.0" + "node": ">=16.0.0 || 14 >= 14.17" }, "peerDependencies": { - "picomatch": "^3 || ^4" + "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { - "picomatch": { + "rollup": { "optional": true } } }, - "node_modules/@rollup/plugin-commonjs/node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@rollup/plugin-json": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", @@ -2382,30 +2037,10 @@ } } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", - "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.56.0.tgz", + "integrity": "sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw==", "cpu": [ "arm" ], @@ -2417,9 +2052,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", - "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.56.0.tgz", + "integrity": "sha512-lfbVUbelYqXlYiU/HApNMJzT1E87UPGvzveGg2h0ktUNlOCxKlWuJ9jtfvs1sKHdwU4fzY7Pl8sAl49/XaEk6Q==", "cpu": [ "arm64" ], @@ -2431,9 +2066,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", - "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.56.0.tgz", + "integrity": "sha512-EgxD1ocWfhoD6xSOeEEwyE7tDvwTgZc8Bss7wCWe+uc7wO8G34HHCUH+Q6cHqJubxIAnQzAsyUsClt0yFLu06w==", "cpu": [ "arm64" ], @@ -2445,9 +2080,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", - "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.56.0.tgz", + "integrity": "sha512-1vXe1vcMOssb/hOF8iv52A7feWW2xnu+c8BV4t1F//m9QVLTfNVpEdja5ia762j/UEJe2Z1jAmEqZAK42tVW3g==", "cpu": [ "x64" ], @@ -2459,9 +2094,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", - "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.56.0.tgz", + "integrity": "sha512-bof7fbIlvqsyv/DtaXSck4VYQ9lPtoWNFCB/JY4snlFuJREXfZnm+Ej6yaCHfQvofJDXLDMTVxWscVSuQvVWUQ==", "cpu": [ "arm64" ], @@ -2473,9 +2108,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", - "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.56.0.tgz", + "integrity": "sha512-KNa6lYHloW+7lTEkYGa37fpvPq+NKG/EHKM8+G/g9WDU7ls4sMqbVRV78J6LdNuVaeeK5WB9/9VAFbKxcbXKYg==", "cpu": [ "x64" ], @@ -2487,9 +2122,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", - "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.56.0.tgz", + "integrity": "sha512-E8jKK87uOvLrrLN28jnAAAChNq5LeCd2mGgZF+fGF5D507WlG/Noct3lP/QzQ6MrqJ5BCKNwI9ipADB6jyiq2A==", "cpu": [ "arm" ], @@ -2501,9 +2136,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", - "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.56.0.tgz", + "integrity": "sha512-jQosa5FMYF5Z6prEpTCCmzCXz6eKr/tCBssSmQGEeozA9tkRUty/5Vx06ibaOP9RCrW1Pvb8yp3gvZhHwTDsJw==", "cpu": [ "arm" ], @@ -2515,9 +2150,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", - "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.56.0.tgz", + "integrity": "sha512-uQVoKkrC1KGEV6udrdVahASIsaF8h7iLG0U0W+Xn14ucFwi6uS539PsAr24IEF9/FoDtzMeeJXJIBo5RkbNWvQ==", "cpu": [ "arm64" ], @@ -2529,9 +2164,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", - "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.56.0.tgz", + "integrity": "sha512-vLZ1yJKLxhQLFKTs42RwTwa6zkGln+bnXc8ueFGMYmBTLfNu58sl5/eXyxRa2RarTkJbXl8TKPgfS6V5ijNqEA==", "cpu": [ "arm64" ], @@ -2543,9 +2178,23 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", - "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.56.0.tgz", + "integrity": "sha512-FWfHOCub564kSE3xJQLLIC/hbKqHSVxy8vY75/YHHzWvbJL7aYJkdgwD/xGfUlL5UV2SB7otapLrcCj2xnF1dg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.56.0.tgz", + "integrity": "sha512-z1EkujxIh7nbrKL1lmIpqFTc/sr0u8Uk0zK/qIEFldbt6EDKWFk/pxFq3gYj4Bjn3aa9eEhYRlL3H8ZbPT1xvA==", "cpu": [ "loong64" ], @@ -2557,9 +2206,23 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", - "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.56.0.tgz", + "integrity": "sha512-iNFTluqgdoQC7AIE8Q34R3AuPrJGJirj5wMUErxj22deOcY7XwZRaqYmB6ZKFHoVGqRcRd0mqO+845jAibKCkw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.56.0.tgz", + "integrity": "sha512-MtMeFVlD2LIKjp2sE2xM2slq3Zxf9zwVuw0jemsxvh1QOpHSsSzfNOTH9uYW9i1MXFxUSMmLpeVeUzoNOKBaWg==", "cpu": [ "ppc64" ], @@ -2571,9 +2234,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", - "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.56.0.tgz", + "integrity": "sha512-in+v6wiHdzzVhYKXIk5U74dEZHdKN9KH0Q4ANHOTvyXPG41bajYRsy7a8TPKbYPl34hU7PP7hMVHRvv/5aCSew==", "cpu": [ "riscv64" ], @@ -2585,9 +2248,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", - "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.56.0.tgz", + "integrity": "sha512-yni2raKHB8m9NQpI9fPVwN754mn6dHQSbDTwxdr9SE0ks38DTjLMMBjrwvB5+mXrX+C0npX0CVeCUcvvvD8CNQ==", "cpu": [ "riscv64" ], @@ -2599,9 +2262,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", - "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.56.0.tgz", + "integrity": "sha512-zhLLJx9nQPu7wezbxt2ut+CI4YlXi68ndEve16tPc/iwoylWS9B3FxpLS2PkmfYgDQtosah07Mj9E0khc3Y+vQ==", "cpu": [ "s390x" ], @@ -2613,9 +2276,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", - "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.56.0.tgz", + "integrity": "sha512-MVC6UDp16ZSH7x4rtuJPAEoE1RwS8N4oK9DLHy3FTEdFoUTCFVzMfJl/BVJ330C+hx8FfprA5Wqx4FhZXkj2Kw==", "cpu": [ "x64" ], @@ -2627,9 +2290,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", - "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.56.0.tgz", + "integrity": "sha512-ZhGH1eA4Qv0lxaV00azCIS1ChedK0V32952Md3FtnxSqZTBTd6tgil4nZT5cU8B+SIw3PFYkvyR4FKo2oyZIHA==", "cpu": [ "x64" ], @@ -2640,10 +2303,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.56.0.tgz", + "integrity": "sha512-O16XcmyDeFI9879pEcmtWvD/2nyxR9mF7Gs44lf1vGGx8Vg2DRNx11aVXBEqOQhWb92WN4z7fW/q4+2NYzCbBA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", - "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.56.0.tgz", + "integrity": "sha512-LhN/Reh+7F3RCgQIRbgw8ZMwUwyqJM+8pXNT6IIJAqm2IdKkzpCh/V9EdgOMBKuebIrzswqy4ATlrDgiOwbRcQ==", "cpu": [ "arm64" ], @@ -2655,9 +2332,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", - "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.56.0.tgz", + "integrity": "sha512-kbFsOObXp3LBULg1d3JIUQMa9Kv4UitDmpS+k0tinPBz3watcUiV2/LUDMMucA6pZO3WGE27P7DsfaN54l9ing==", "cpu": [ "arm64" ], @@ -2669,9 +2346,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", - "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.56.0.tgz", + "integrity": "sha512-vSSgny54D6P4vf2izbtFm/TcWYedw7f8eBrOiGGecyHyQB9q4Kqentjaj8hToe+995nob/Wv48pDqL5a62EWtg==", "cpu": [ "ia32" ], @@ -2683,9 +2360,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", - "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.56.0.tgz", + "integrity": "sha512-FeCnkPCTHQJFbiGG49KjV5YGW/8b9rrXAM2Mz2kiIoktq2qsJxRD5giEMEOD2lPdgs72upzefaUvS+nc8E3UzQ==", "cpu": [ "x64" ], @@ -2697,9 +2374,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", - "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.56.0.tgz", + "integrity": "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g==", "cpu": [ "x64" ], @@ -2711,23 +2388,23 @@ ] }, "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, "license": "MIT" }, "node_modules/@storybook/addon-docs": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.13.tgz", - "integrity": "sha512-V1nCo7bfC3kQ5VNVq0VDcHsIhQf507m+BxMA5SIYiwdJHljH2BXpW2fL3FFn9gv9Wp57AEEzhm+wh4zANaJgkg==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.17.tgz", + "integrity": "sha512-yc4hlgkrwNi045qk210dRuIMijkgbLmo3ft6F4lOdpPRn4IUnPDj7FfZR8syGzUzKidxRfNtLx5m0yHIz83xtA==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/csf-plugin": "9.1.13", + "@storybook/csf-plugin": "9.1.17", "@storybook/icons": "^1.4.0", - "@storybook/react-dom-shim": "9.1.13", + "@storybook/react-dom-shim": "9.1.17", "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", "ts-dedent": "^2.0.0" @@ -2737,7 +2414,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.13" + "storybook": "^9.1.17" } }, "node_modules/@storybook/addon-svelte-csf": { @@ -2764,9 +2441,9 @@ } }, "node_modules/@storybook/addon-vitest": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/@storybook/addon-vitest/-/addon-vitest-9.1.13.tgz", - "integrity": "sha512-g/wkQ8i1GGlsoHEe6bjWic+ESokWhuMBxAa9FDLW9KDf0L1DMyQqFFJFnGoo99zCNRVJcSXgzZTFp6SCt3FKog==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@storybook/addon-vitest/-/addon-vitest-9.1.17.tgz", + "integrity": "sha512-2EIvZPz0N+mnIUnUHW3+GIgwJRIqjZrK5BFyHsi82NhOQ1LCh/1GqbcB+kNoaiXioRcAgOsHUDWbQZrvyx3GhQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2780,15 +2457,19 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "@vitest/browser": "^3.0.0", - "@vitest/runner": "^3.0.0", - "storybook": "^9.1.13", - "vitest": "^3.0.0" + "@vitest/browser": "^3.0.0 || ^4.0.0", + "@vitest/browser-playwright": "^4.0.0", + "@vitest/runner": "^3.0.0 || ^4.0.0", + "storybook": "^9.1.17", + "vitest": "^3.0.0 || ^4.0.0" }, "peerDependenciesMeta": { "@vitest/browser": { "optional": true }, + "@vitest/browser-playwright": { + "optional": true + }, "@vitest/runner": { "optional": true }, @@ -2798,13 +2479,13 @@ } }, "node_modules/@storybook/builder-vite": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.13.tgz", - "integrity": "sha512-pmtIjU02ASJOZKdL8DoxWXJgZnpTDgD5WmMnjKJh9FaWmc2YiCW2Y6VRxPox96OM655jYHQe5+UIbk3Cwtwb4A==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.17.tgz", + "integrity": "sha512-OQCYaFWoTBvovN2IJmkAW+7FgHMJiih1WA/xqgpKIx0ImZjB4z5FrKgzQeXsrYcLEsynyaj+xN3JFUKsz5bzGQ==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "9.1.13", + "@storybook/csf-plugin": "9.1.17", "ts-dedent": "^2.0.0" }, "funding": { @@ -2812,7 +2493,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.13", + "storybook": "^9.1.17", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, @@ -2827,9 +2508,9 @@ } }, "node_modules/@storybook/csf-plugin": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.13.tgz", - "integrity": "sha512-EMpzYuyt9FDcxxfBChWzfId50y8QMpdenviEQ8m+pa6c+ANx3pC5J6t7y0khD8TQu815sTy+nc6cc8PC45dPUA==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.17.tgz", + "integrity": "sha512-o+ebQDdSfZHDRDhu2hNDGhCLIazEB4vEAqJcHgz1VsURq+l++bgZUcKojPMCAbeblptSEz2bwS0eYAOvG7aSXg==", "dev": true, "license": "MIT", "dependencies": { @@ -2840,7 +2521,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.13" + "storybook": "^9.1.17" } }, "node_modules/@storybook/global": { @@ -2865,9 +2546,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.13.tgz", - "integrity": "sha512-/tMr9TmV3+98GEQO0S03k4gtKHGCpv9+k9Dmnv+TJK3TBz7QsaFEzMwe3gCgoTaebLACyVveDiZkWnCYAWB6NA==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.17.tgz", + "integrity": "sha512-Ss/lNvAy0Ziynu+KniQIByiNuyPz3dq7tD62hqSC/pHw190X+M7TKU3zcZvXhx2AQx1BYyxtdSHIZapb+P5mxQ==", "dev": true, "license": "MIT", "funding": { @@ -2877,13 +2558,13 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.13" + "storybook": "^9.1.17" } }, "node_modules/@storybook/svelte": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/@storybook/svelte/-/svelte-9.1.13.tgz", - "integrity": "sha512-BmV0nU3Ot1fHE1MTlmrmJpEdmQCXZJH+2zQx457ZrJLYFyozG7fyirx5zBXTnH6agyOF7CsjqtMHp2MhX8YVnw==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@storybook/svelte/-/svelte-9.1.17.tgz", + "integrity": "sha512-c14PaVYAw8yYIJbAAkLZqzPFbqX61Xd04gSzNO3w+0smYH5ieW0caC28rnqkOu1AIe1nZSuNhJ0/Bi2PAqijYA==", "dev": true, "license": "MIT", "dependencies": { @@ -2898,19 +2579,19 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.13", + "storybook": "^9.1.17", "svelte": "^5.0.0" } }, "node_modules/@storybook/svelte-vite": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/@storybook/svelte-vite/-/svelte-vite-9.1.13.tgz", - "integrity": "sha512-4D+WBrFMd8+3WVLQK9M8Uib6Sl/b8nf3Kz4NptE5C9fFDGM2qm2Iy95HMxYjg9HRsKRcceAwVu9I4VpDiBWbKw==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@storybook/svelte-vite/-/svelte-vite-9.1.17.tgz", + "integrity": "sha512-3hOjf6r4G2ROm3tdaEa1SNqmWGMqXbZL0DfRRK+XYPovYYYM3YuJBQUT3senXiOMGGB7NRSDKopr+ZecfGBCyw==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/builder-vite": "9.1.13", - "@storybook/svelte": "9.1.13", + "@storybook/builder-vite": "9.1.17", + "@storybook/svelte": "9.1.17", "magic-string": "^0.30.0", "svelte2tsx": "^0.7.35", "typescript": "^4.9.4 || ^5.0.0" @@ -2924,21 +2605,21 @@ }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", - "storybook": "^9.1.13", + "storybook": "^9.1.17", "svelte": "^5.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@storybook/sveltekit": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/@storybook/sveltekit/-/sveltekit-9.1.13.tgz", - "integrity": "sha512-jsCUue8NgVObga7bgf9p0OWR4gt+l8zCfUbE+IwDOQGXVMGsea9XVJl/iTzQWaCUzzTgI/PhjncaDsj8PPRe7w==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@storybook/sveltekit/-/sveltekit-9.1.17.tgz", + "integrity": "sha512-GvA++7uTokt6LJt1s4O/e650IrKI+TCdbe39MGrpfcTq07PW2Ah09EfEEojUdFIzoy8DJA9YjAkyrNbvmndnnQ==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/builder-vite": "9.1.13", - "@storybook/svelte": "9.1.13", - "@storybook/svelte-vite": "9.1.13" + "@storybook/builder-vite": "9.1.17", + "@storybook/svelte": "9.1.17", + "@storybook/svelte-vite": "9.1.17" }, "engines": { "node": ">=20.0.0" @@ -2948,7 +2629,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.13", + "storybook": "^9.1.17", "svelte": "^5.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } @@ -2963,9 +2644,10 @@ } }, "node_modules/@sveltejs/acorn-typescript": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.6.tgz", - "integrity": "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.8.tgz", + "integrity": "sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==", + "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^8.9.0" @@ -2982,9 +2664,9 @@ } }, "node_modules/@sveltejs/adapter-node": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.4.0.tgz", - "integrity": "sha512-NMsrwGVPEn+J73zH83Uhss/hYYZN6zT3u31R3IHAn3MiKC3h8fjmIAhLfTSOeNHr5wPYfjjMg8E+1gyFgyrEcQ==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.5.2.tgz", + "integrity": "sha512-L15Djwpr7HrSAPj/Z8PYfc0pa9A1tllrr18phKI0WJHJeoWw45yinPf0IGgVTmakqx1B3JQ+C/OFl9ZwmxHU1Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2998,9 +2680,9 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.49.5", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.49.5.tgz", - "integrity": "sha512-dCYqelr2RVnWUuxc+Dk/dB/SjV/8JBndp1UovCyCZdIQezd8TRwFLNZctYkzgHxRJtaNvseCSRsuuHPeUgIN/A==", + "version": "2.50.1", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.50.1.tgz", + "integrity": "sha512-XRHD2i3zC4ukhz2iCQzO4mbsts081PAZnnMAQ7LNpWeYgeBmwMsalf0FGSwhFXBbtr2XViPKnFJBDCckWqrsLw==", "dev": true, "license": "MIT", "dependencies": { @@ -3041,13 +2723,13 @@ } }, "node_modules/@sveltejs/package": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-2.5.4.tgz", - "integrity": "sha512-8+1hccAt0M3PPkHVPKH54Wc+cc1PNxRqCrICZiv/hEEto8KwbQVRghxNgTB4htIPyle+4CIB8RayTQH5zRQh9A==", + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-2.5.7.tgz", + "integrity": "sha512-qqD9xa9H7TDiGFrF6rz7AirOR8k15qDK/9i4MIE8te4vWsv5GEogPks61rrZcLy+yWph+aI6pIj2MdoK3YI8AQ==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^4.0.3", + "chokidar": "^5.0.0", "kleur": "^4.1.5", "sade": "^1.8.1", "semver": "^7.5.4", @@ -3063,6 +2745,36 @@ "svelte": "^3.44.0 || ^4.0.0 || ^5.0.0-next.1" } }, + "node_modules/@sveltejs/package/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sveltejs/package/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@sveltejs/vite-plugin-svelte": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", @@ -3286,26 +2998,15 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.23.tgz", - "integrity": "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ==", + "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, - "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "csstype": "^3.0.2" - } - }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -3358,22 +3059,31 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", - "integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", + "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/type-utils": "8.46.2", - "@typescript-eslint/utils": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/type-utils": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3383,7 +3093,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.46.2", + "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -3399,17 +3109,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", - "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", + "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3424,15 +3134,15 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", - "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", + "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.2", - "@typescript-eslint/types": "^8.46.2", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.54.0", + "@typescript-eslint/types": "^8.54.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3446,14 +3156,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", - "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", + "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3464,9 +3174,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", - "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", + "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", "dev": true, "license": "MIT", "engines": { @@ -3481,17 +3191,17 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", - "integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", + "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/utils": "8.46.2", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3506,9 +3216,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", - "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", "dev": true, "license": "MIT", "engines": { @@ -3520,22 +3230,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", - "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", + "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.46.2", - "@typescript-eslint/tsconfig-utils": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/project-service": "8.54.0", + "@typescript-eslint/tsconfig-utils": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3575,16 +3284,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", - "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", + "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3599,13 +3308,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", - "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", + "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -3730,6 +3439,16 @@ } } }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/@vitest/pretty-format": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", @@ -3870,6 +3589,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3899,16 +3619,17 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "name": "@redocly/ajv", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -3933,30 +3654,6 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3997,6 +3694,19 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4049,6 +3759,16 @@ "js-tokens": "^9.0.1" } }, + "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", @@ -4060,6 +3780,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -4221,9 +3942,9 @@ } }, "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", "dev": true, "license": "MIT", "engines": { @@ -4231,25 +3952,34 @@ } }, "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 8.10.0" }, "funding": { "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, "node_modules/chromatic": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-12.2.0.tgz", - "integrity": "sha512-GswmBW9ZptAoTns1BMyjbm55Z7EsIJnUvYKdQqXIBZIKbGErmpA+p4c0BYA+nzw5B0M+rb3Iqp1IaH8TFwIQew==", + "version": "13.3.5", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-13.3.5.tgz", + "integrity": "sha512-MzPhxpl838qJUo0A55osCF2ifwPbjcIPeElr1d4SHcjnHoIcg7l1syJDrAYK/a+PcCBrOGi06jPNpQAln5hWgw==", "dev": true, "license": "MIT", "bin": { @@ -4288,18 +4018,37 @@ } }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", + "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=12" + "node": ">=8" } }, "node_modules/cliui/node_modules/strip-ansi": { @@ -4337,6 +4086,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4424,19 +4174,6 @@ "node": ">= 0.6" } }, - "node_modules/core-js": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", - "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/crelt": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", @@ -4637,9 +4374,9 @@ "dev": true }, "node_modules/dedent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", + "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -4787,12 +4524,25 @@ } }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-module-lexer": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", @@ -4801,9 +4551,9 @@ "license": "MIT" }, "node_modules/es-toolkit": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.40.0.tgz", - "integrity": "sha512-8o6w0KFmU0CiIl0/Q/BCEOabF2IJaELM1T2PWj6e8KqzHv1gdx+7JtFnDwOx1kJH/isJ5NwlDG1nCr1HrRF94Q==", + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.44.0.tgz", + "integrity": "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==", "dev": true, "license": "MIT", "workspaces": [ @@ -4819,9 +4569,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", - "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4832,32 +4582,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.11", - "@esbuild/android-arm": "0.25.11", - "@esbuild/android-arm64": "0.25.11", - "@esbuild/android-x64": "0.25.11", - "@esbuild/darwin-arm64": "0.25.11", - "@esbuild/darwin-x64": "0.25.11", - "@esbuild/freebsd-arm64": "0.25.11", - "@esbuild/freebsd-x64": "0.25.11", - "@esbuild/linux-arm": "0.25.11", - "@esbuild/linux-arm64": "0.25.11", - "@esbuild/linux-ia32": "0.25.11", - "@esbuild/linux-loong64": "0.25.11", - "@esbuild/linux-mips64el": "0.25.11", - "@esbuild/linux-ppc64": "0.25.11", - "@esbuild/linux-riscv64": "0.25.11", - "@esbuild/linux-s390x": "0.25.11", - "@esbuild/linux-x64": "0.25.11", - "@esbuild/netbsd-arm64": "0.25.11", - "@esbuild/netbsd-x64": "0.25.11", - "@esbuild/openbsd-arm64": "0.25.11", - "@esbuild/openbsd-x64": "0.25.11", - "@esbuild/openharmony-arm64": "0.25.11", - "@esbuild/sunos-x64": "0.25.11", - "@esbuild/win32-arm64": "0.25.11", - "@esbuild/win32-ia32": "0.25.11", - "@esbuild/win32-x64": "0.25.11" + "@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" } }, "node_modules/esbuild-register": { @@ -4897,20 +4647,20 @@ } }, "node_modules/eslint": { - "version": "9.38.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", - "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.1", - "@eslint/core": "^0.16.0", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.38.0", - "@eslint/plugin-kit": "^0.4.0", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -4973,9 +4723,9 @@ } }, "node_modules/eslint-plugin-storybook": { - "version": "9.1.13", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-9.1.13.tgz", - "integrity": "sha512-kPuhbtGDiJLB5OLZuwFZAxgzWakNDw64sJtXUPN8g0+VAeXfHyZEmsE28qIIETHxtal71lPKVm8QNnERaJHPJQ==", + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-9.1.17.tgz", + "integrity": "sha512-7Qn3XxXdWLAt6arSH8Tt8Su/fAAqA+d5Oc51g7ubOE5Yfc5x0dMIgCfCG5RrIjt0RDRpwp4n194Mge+sAA3WMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4986,13 +4736,13 @@ }, "peerDependencies": { "eslint": ">=8", - "storybook": "^9.1.13" + "storybook": "^9.1.17" } }, "node_modules/eslint-plugin-svelte": { - "version": "3.12.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.12.5.tgz", - "integrity": "sha512-4KRG84eAHQfYd9OjZ1K7sCHy0nox+9KwT+s5WCCku3jTim5RV4tVENob274nCwIaApXsYPKAUAZFBxKZ3Wyfjw==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.14.0.tgz", + "integrity": "sha512-Isw0GvaMm0yHxAj71edAdGFh28ufYs+6rk2KlbbZphnqZAzrH3Se3t12IFh2H9+1F/jlDhBBL4oiOJmLqmYX0g==", "dev": true, "license": "MIT", "dependencies": { @@ -5053,10 +4803,48 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/esm-env": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "dev": true, "license": "MIT" }, "node_modules/espree": { @@ -5092,9 +4880,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5138,14 +4926,11 @@ } }, "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } + "license": "MIT" }, "node_modules/esutils": { "version": "2.0.3", @@ -5175,9 +4960,9 @@ "license": "MIT" }, "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5191,36 +4976,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -5278,14 +5033,22 @@ "fxparser": "src/cli/cli.js" } }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, "node_modules/fflate": { @@ -5394,9 +5157,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -5429,69 +5192,62 @@ } }, "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" }, + "engines": { + "node": "20 || >=22" + }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { - "is-glob": "^4.0.3" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "node": ">= 6" } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "license": "MIT", "engines": { @@ -5509,13 +5265,6 @@ "license": "ISC", "optional": true }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/graphql": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", @@ -5549,15 +5298,18 @@ } }, "node_modules/happy-dom": { - "version": "20.0.11", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.0.11.tgz", - "integrity": "sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==", + "version": "20.3.9", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.3.9.tgz", + "integrity": "sha512-OIoj0PcK2JaxQuANHxWkxFRSNXAuSgO1vCzCT66KItE0W/ieZLG+/iW8OetlxB+F9EaPB7DoFYKAubFG1f4Mvw==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "^20.0.0", + "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", - "whatwg-mimetype": "^3.0.0" + "@types/ws": "^8.18.1", + "entities": "^4.5.0", + "whatwg-mimetype": "^3.0.0", + "ws": "^8.18.3" }, "engines": { "node": ">=20.0.0" @@ -5785,12 +5537,13 @@ } }, "node_modules/is-reference": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.6" + "@types/estree": "*" } }, "node_modules/is-wsl": { @@ -5868,19 +5621,19 @@ } }, "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, + "engines": { + "node": "20 || >=22" + }, "funding": { "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" } }, "node_modules/js-levenshtein": { @@ -5946,9 +5699,9 @@ } }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, @@ -6057,6 +5810,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -6110,11 +5864,14 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", "dev": true, - "license": "ISC" + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, "node_modules/lunr": { "version": "2.3.9", @@ -6134,9 +5891,10 @@ } }, "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -6178,9 +5936,9 @@ "license": "MIT" }, "node_modules/marked": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.1.tgz", - "integrity": "sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg==", + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -6189,30 +5947,6 @@ "node": ">= 20" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -6391,6 +6125,21 @@ } } }, + "node_modules/msw/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/msw/node_modules/cookie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", @@ -6405,10 +6154,45 @@ "url": "https://opencollective.com/express" } }, + "node_modules/msw/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/msw/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/msw/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/msw/node_modules/type-fest": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.3.1.tgz", - "integrity": "sha512-VCn+LMHbd4t6sF3wfU/+HKT63C9OoyrSIf4b+vtWHpt2U7/4InZG467YDNMFMR70DdHjAdpPWmw2lzRdg0Xqqg==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.4.1.tgz", + "integrity": "sha512-xygQcmneDyzsEuKZrFbRMne5HDqMs++aFzefrJTgEIKjQ3rekM+RPfFCVq2Gp1VIDqddoYeppCj4Pcb+RZW0GQ==", "dev": true, "license": "(MIT OR CC0-1.0)", "dependencies": { @@ -6421,6 +6205,53 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/msw/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/msw/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/msw/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/mute-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", @@ -6509,9 +6340,9 @@ } }, "node_modules/nodemon": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", - "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", "dev": true, "license": "MIT", "dependencies": { @@ -6537,44 +6368,6 @@ "url": "https://opencollective.com/nodemon" } }, - "node_modules/nodemon/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/nodemon/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/nodemon/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -6585,19 +6378,6 @@ "node": ">=4" } }, - "node_modules/nodemon/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/nodemon/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -6852,9 +6632,9 @@ "license": "BlueOak-1.0.0" }, "node_modules/package-manager-detector": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.5.0.tgz", - "integrity": "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", "dev": true, "license": "MIT" }, @@ -6906,17 +6686,17 @@ "license": "MIT" }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6961,26 +6741,26 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/playwright": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", - "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "version": "1.58.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.0.tgz", + "integrity": "sha512-2SVA0sbPktiIY/MCOPX8e86ehA/e+tDNq+e5Y8qjKYti2Z/JG7xnronT/TXTIkKbYGWlCbuucZ6dziEgkoEjQQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.56.1" + "playwright-core": "1.58.0" }, "bin": { "playwright": "cli.js" @@ -6993,9 +6773,9 @@ } }, "node_modules/playwright-core": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", - "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "version": "1.58.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.0.tgz", + "integrity": "sha512-aaoB1RWrdNi3//rOeKuMiS65UCcgOVljU46At6eFcOFPFHWtd2weHRRow6z/n+Lec0Lvu0k9ZPKJSjPugikirw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -7005,6 +6785,21 @@ "node": ">=18" } }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -7152,9 +6947,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -7183,9 +6978,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -7199,9 +6994,9 @@ } }, "node_modules/prettier-plugin-svelte": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.4.0.tgz", - "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.4.1.tgz", + "integrity": "sha512-xL49LCloMoZRvSwa6IEdN2GV6cq2IqpYGstYtMT+5wmml1/dClEoI0MZR78MiVPpu6BdQFfN0/y73yO6+br5Pg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -7323,14 +7118,14 @@ "license": "MIT" }, "node_modules/publint": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/publint/-/publint-0.3.15.tgz", - "integrity": "sha512-xPbRAPW+vqdiaKy5sVVY0uFAu3LaviaPO3pZ9FaRx59l9+U/RKR1OEbLhkug87cwiVKxPXyB4txsv5cad67u+A==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/publint/-/publint-0.3.17.tgz", + "integrity": "sha512-Q3NLegA9XM6usW+dYQRG1g9uEHiYUzcCVBJDJ7yMcWRqVU9LYZUWdqbwMZfmTCFC5PZLQpLAmhvRcQRl3exqkw==", "dev": true, "license": "MIT", "dependencies": { - "@publint/pack": "^0.1.2", - "package-manager-detector": "^1.3.0", + "@publint/pack": "^0.1.3", + "package-manager-detector": "^1.6.0", "picocolors": "^1.1.1", "sade": "^1.8.1" }, @@ -7386,9 +7181,9 @@ } }, "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "dev": true, "license": "MIT", "engines": { @@ -7396,16 +7191,16 @@ } }, "node_modules/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "dev": true, "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.3" + "react": "^19.2.4" } }, "node_modules/react-is": { @@ -7445,17 +7240,29 @@ } }, "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">= 14.18.0" + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" }, "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/recast": { @@ -7663,21 +7470,10 @@ "dev": true, "license": "MIT" }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/rollup": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", - "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.56.0.tgz", + "integrity": "sha512-9FwVqlgUHzbXtDg9RCMgodF3Ua4Na6Gau+Sdt9vyCN4RhHfVKX2DCHy3BjMLTDd47ITDhYAnTwGulWTblJSDLg==", "dev": true, "license": "MIT", "dependencies": { @@ -7691,55 +7487,34 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.5", - "@rollup/rollup-android-arm64": "4.52.5", - "@rollup/rollup-darwin-arm64": "4.52.5", - "@rollup/rollup-darwin-x64": "4.52.5", - "@rollup/rollup-freebsd-arm64": "4.52.5", - "@rollup/rollup-freebsd-x64": "4.52.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", - "@rollup/rollup-linux-arm-musleabihf": "4.52.5", - "@rollup/rollup-linux-arm64-gnu": "4.52.5", - "@rollup/rollup-linux-arm64-musl": "4.52.5", - "@rollup/rollup-linux-loong64-gnu": "4.52.5", - "@rollup/rollup-linux-ppc64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-musl": "4.52.5", - "@rollup/rollup-linux-s390x-gnu": "4.52.5", - "@rollup/rollup-linux-x64-gnu": "4.52.5", - "@rollup/rollup-linux-x64-musl": "4.52.5", - "@rollup/rollup-openharmony-arm64": "4.52.5", - "@rollup/rollup-win32-arm64-msvc": "4.52.5", - "@rollup/rollup-win32-ia32-msvc": "4.52.5", - "@rollup/rollup-win32-x64-gnu": "4.52.5", - "@rollup/rollup-win32-x64-msvc": "4.52.5", + "@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" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -7802,9 +7577,9 @@ } }, "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "dev": true, "license": "MIT" }, @@ -8128,18 +7903,21 @@ } }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/string-width-cjs": { @@ -8158,20 +7936,14 @@ "node": ">=8" } }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/string-width/node_modules/strip-ansi": { + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -8389,9 +8161,10 @@ } }, "node_modules/svelte": { - "version": "5.41.3", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.41.3.tgz", - "integrity": "sha512-bkHg+whEnVVNcK3XP8Dy4NHujn5mU/+at9z09PXM5THKm+E73AwiKFoRMMTfyAzAj1yExKtudvGHq8UqOh8kMQ==", + "version": "5.48.3", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.48.3.tgz", + "integrity": "sha512-w7QZ398cdNherTdiQ/v3SYLLGOO4948Jgjh04PYqtTYVohmBvbmFwLmo7pp8gp4/1tceRWfSTjHgjtfpCVNJmQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", @@ -8402,8 +8175,9 @@ "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", + "devalue": "^5.6.2", "esm-env": "^1.2.1", - "esrap": "^2.1.0", + "esrap": "^2.2.1", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", @@ -8471,9 +8245,9 @@ "license": "MIT" }, "node_modules/svelte-check": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.3.tgz", - "integrity": "sha512-RYP0bEwenDXzfv0P1sKAwjZSlaRyqBn0Fz1TVni58lqyEiqgwztTpmodJrGzP6ZT2aHl4MbTvWP6gbmQ3FOnBg==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.5.tgz", + "integrity": "sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8494,43 +8268,40 @@ "typescript": ">=5.0.0" } }, - "node_modules/svelte-check/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/svelte-check/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12.0.0" + "dependencies": { + "readdirp": "^4.0.1" }, - "peerDependencies": { - "picomatch": "^3 || ^4" + "engines": { + "node": ">= 14.16.0" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/svelte-check/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/svelte-check/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { - "node": ">=12" + "node": ">= 14.18.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/svelte-eslint-parser": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.4.0.tgz", - "integrity": "sha512-fjPzOfipR5S7gQ/JvI9r2H8y9gMGXO3JtmrylHLLyahEMquXI0lrebcjT+9/hNgDej0H7abTyox5HpHmW1PSWA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.4.1.tgz", + "integrity": "sha512-1eqkfQ93goAhjAXxZiu1SaKI9+0/sxp4JIWQwUpsz7ybehRE5L8dNuz7Iry7K22R47p5/+s9EM+38nHV2OlgXA==", "dev": true, "license": "MIT", "dependencies": { @@ -8543,7 +8314,7 @@ }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0", - "pnpm": "10.18.3" + "pnpm": "10.24.0" }, "funding": { "url": "https://github.com/sponsors/ota-meshi" @@ -8573,24 +8344,36 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" } }, - "node_modules/svelte/node_modules/esrap": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.0.tgz", - "integrity": "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==", + "node_modules/svelte/node_modules/esrap": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.2.tgz", + "integrity": "sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/svelte/node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@types/estree": "^1.0.6" } }, "node_modules/svelte2tsx": { - "version": "0.7.45", - "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.45.tgz", - "integrity": "sha512-cSci+mYGygYBHIZLHlm/jYlEc1acjAHqaQaDFHdEBpUueM9kSTnPpvPtSl5VkJOU1qSJ7h1K+6F/LIUYiqC8VA==", + "version": "0.7.46", + "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.46.tgz", + "integrity": "sha512-S++Vw3w47a8rBuhbz4JK0fcGea8tOoX1boT53Aib8+oUO2EKeOG+geXprJVTDfBlvR+IJdf3jIpR2RGwT6paQA==", "dev": true, "license": "MIT", "dependencies": { @@ -8654,9 +8437,9 @@ } }, "node_modules/terser": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", - "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -8697,6 +8480,50 @@ "balanced-match": "^1.0.0" } }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/test-exclude/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -8713,6 +8540,23 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/through2": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", @@ -8761,37 +8605,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tinypool": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", @@ -8903,9 +8716,9 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { @@ -8973,16 +8786,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.2.tgz", - "integrity": "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz", + "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.46.2", - "@typescript-eslint/parser": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/utils": "8.46.2" + "@typescript-eslint/eslint-plugin": "8.54.0", + "@typescript-eslint/parser": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9242,52 +9055,6 @@ "vite": "^2.7.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/vitefu": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", @@ -9399,19 +9166,6 @@ "vitest": "^2.1.0 || ^3.0.0-0" } }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", @@ -9504,18 +9258,21 @@ "license": "MIT" }, "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrap-ansi-cjs": { @@ -9537,20 +9294,29 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -9563,10 +9329,23 @@ "node": ">=8" } }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { @@ -9596,18 +9375,19 @@ } }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", - "optional": true, - "peer": true, "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yaml-ast-parser": { @@ -9618,32 +9398,67 @@ "license": "Apache-2.0" }, "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", + "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^4.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^20.2.2" }, "engines": { "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "license": "ISC", "engines": { - "node": ">=12" + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/yocto-queue": { @@ -9676,6 +9491,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", + "dev": true, "license": "MIT" } } diff --git a/package.json b/package.json index 76c5c00..9596875 100644 --- a/package.json +++ b/package.json @@ -187,7 +187,8 @@ "vite": "^6.2.6", "vite-plugin-devtools-json": "^0.2.1", "vitest": "^3.2.3", - "vitest-browser-svelte": "^0.1.0" + "vitest-browser-svelte": "^0.1.0", + "yaml": "^2.8.2" }, "overrides": { "@sveltejs/kit": { diff --git a/src/lib/components/ConfigForm.svelte b/src/lib/components/ConfigForm.svelte index f6be5f7..7f46d32 100644 --- a/src/lib/components/ConfigForm.svelte +++ b/src/lib/components/ConfigForm.svelte @@ -35,6 +35,12 @@ type DynamicSchemaResult } from '$lib/services/dynamicSchemaService.js'; import { globalSaveWorkflow } from '$lib/services/globalSave.js'; + import { + fetchAllFieldOptions, + hasFieldsWithOptionsEndpoint, + mergeOptionsIntoSchema + } from '$lib/services/optionsService.js'; + import type { FieldOption } from '$lib/components/form/types.js'; interface Props { /** Optional workflow node (if provided, schema and values are derived from it) */ @@ -73,6 +79,14 @@ let dynamicSchemaError = $state(null); let fetchedDynamicSchema = $state(null); + /** + * State for field options loading + */ + let optionsLoading = $state(false); + // eslint-disable-next-line @typescript-eslint/no-unused-vars -- Reserved for future error display + let optionsErrors = $state>(new Map()); + let fetchedOptions = $state>(new Map()); + /** * Get the admin edit configuration for the node */ @@ -203,6 +217,26 @@ await loadDynamicSchema(); } + /** + * Load options for fields with optionsEndpoint + */ + async function loadFieldOptions(schema: ConfigSchema): Promise { + if (!node) return; + + optionsLoading = true; + optionsErrors = new Map(); + + try { + const result = await fetchAllFieldOptions(schema, node, workflowId); + fetchedOptions = result.options; + optionsErrors = result.errors; + } catch (err) { + console.error('Failed to load field options:', err); + } finally { + optionsLoading = false; + } + } + /** * Get the resolved external edit URL */ @@ -236,6 +270,31 @@ } }); + /** + * Load field options when schema is available and has fields with optionsEndpoint + */ + $effect(() => { + const schema = configSchema; + if ( + schema && + node && + hasFieldsWithOptionsEndpoint(schema) && + !optionsLoading && + fetchedOptions.size === 0 + ) { + loadFieldOptions(schema); + } + }); + + /** + * Schema with fetched options merged in for form rendering + */ + const enrichedSchema = $derived.by(() => { + if (!configSchema) return configSchema; + if (fetchedOptions.size === 0) return configSchema; + return mergeOptionsIntoSchema(configSchema, fetchedOptions); + }); + /** * Initialize config values when node/schema changes */ @@ -380,12 +439,16 @@ {/if} - -{#if dynamicSchemaLoading} + +{#if dynamicSchemaLoading || optionsLoading}

- {configEditOptions?.loadingMessage ?? 'Loading configuration options...'} + {#if dynamicSchemaLoading} + {configEditOptions?.loadingMessage ?? 'Loading configuration schema...'} + {:else} + Loading field options... + {/if}

{:else if dynamicSchemaError} @@ -421,7 +484,7 @@ -{:else if configSchema} +{:else if enrichedSchema}
{ @@ -458,9 +521,9 @@ {/if} - {#if configSchema.properties} + {#if enrichedSchema.properties}
- {#each Object.entries(configSchema.properties) as [key, field], index (key)} + {#each Object.entries(enrichedSchema.properties) as [key, field], index (key)} {@const fieldSchema = toFieldSchema(field as Record)} {@const required = isFieldRequired(key)} @@ -481,7 +544,7 @@ Debug - Config Schema
-
{JSON.stringify(configSchema, null, 2)}
+
{JSON.stringify(enrichedSchema, null, 2)}
{/if} diff --git a/src/lib/components/form/types.ts b/src/lib/components/form/types.ts index 5e744a1..9709eeb 100644 --- a/src/lib/components/form/types.ts +++ b/src/lib/components/form/types.ts @@ -6,6 +6,8 @@ * and support extensibility for complex field types like arrays and objects. */ +import type { OptionsEndpoint } from '$lib/types/index.js'; + /** * Supported field types for form rendering * Can be extended to support complex types like 'array' and 'object' @@ -253,6 +255,12 @@ export interface FieldSchema { properties?: Record; /** Required properties for object fields (future use) */ required?: string[]; + /** + * REST endpoint to fetch options dynamically at runtime. + * When specified, options are fetched from this endpoint and used + * instead of static `enum` or `options` values. + */ + optionsEndpoint?: OptionsEndpoint; /** Allow additional properties not defined by the schema */ [key: string]: unknown; } diff --git a/src/lib/core/index.ts b/src/lib/core/index.ts index 57b1241..5267bbd 100644 --- a/src/lib/core/index.ts +++ b/src/lib/core/index.ts @@ -53,6 +53,7 @@ export type { DynamicSchemaEndpoint, ExternalEditLink, ConfigEditOptions, + OptionsEndpoint, // Edge types EdgeCategory } from '../types/index.js'; diff --git a/src/lib/services/dynamicSchemaService.ts b/src/lib/services/dynamicSchemaService.ts index de8588d..08e9479 100644 --- a/src/lib/services/dynamicSchemaService.ts +++ b/src/lib/services/dynamicSchemaService.ts @@ -14,24 +14,7 @@ import type { WorkflowNode } from '../types/index.js'; import { getEndpointConfig } from './api.js'; - -/** - * Context object containing all available data for resolving template variables - */ -interface NodeContext { - /** Node instance ID */ - id: string; - /** Node type from xyflow */ - type: string; - /** Node metadata (id, name, type, category, etc.) */ - metadata: WorkflowNode['data']['metadata']; - /** Node configuration values */ - config: Record; - /** Node extensions */ - extensions?: WorkflowNode['data']['extensions']; - /** Current workflow ID (if available) */ - workflowId?: string; -} +import { resolveTemplate, buildNodeContext, type NodeContext } from '../utils/templateResolver.js'; /** * Result of a dynamic schema fetch operation @@ -70,97 +53,6 @@ const schemaCache = new Map(); */ const DEFAULT_CACHE_TTL = 5 * 60 * 1000; -/** - * Resolves a template variable path from the node context. - * Supports dot-notation paths like "metadata.id", "config.apiKey", "id" - * - * @param context - The node context containing all available data - * @param path - Dot-notation path to resolve (e.g., "metadata.id") - * @returns The resolved value as a string, or undefined if not found - * - * @example - * ```typescript - * const context = { id: "node-1", metadata: { id: "llm-node" } }; - * resolveVariablePath(context, "metadata.id"); // Returns "llm-node" - * resolveVariablePath(context, "id"); // Returns "node-1" - * ``` - */ -function resolveVariablePath(context: NodeContext, path: string): string | undefined { - const parts = path.split('.'); - let current: unknown = context; - - for (const part of parts) { - if (current === null || current === undefined) { - return undefined; - } - if (typeof current === 'object' && part in current) { - current = (current as Record)[part]; - } else { - return undefined; - } - } - - // Convert to string if not already - if (current === null || current === undefined) { - return undefined; - } - return String(current); -} - -/** - * Replaces template variables in a URL or string with values from the node context. - * Template variables use curly brace syntax: {variableName} - * - * @param template - The template string with variables - * @param parameterMapping - Maps variable names to context paths - * @param context - The node context containing all available data - * @returns The resolved string with all variables replaced - * - * @example - * ```typescript - * const url = "/api/nodes/{nodeTypeId}/schema?instance={instanceId}"; - * const mapping = { nodeTypeId: "metadata.id", instanceId: "id" }; - * const context = { id: "node-1", metadata: { id: "llm-node" } }; - * resolveTemplate(url, mapping, context); - * // Returns "/api/nodes/llm-node/schema?instance=node-1" - * ``` - */ -function resolveTemplate( - template: string, - parameterMapping: Record | undefined, - context: NodeContext -): string { - if (!parameterMapping) { - return template; - } - - let resolved = template; - - // Replace each mapped variable - for (const [variableName, contextPath] of Object.entries(parameterMapping)) { - const value = resolveVariablePath(context, contextPath); - if (value !== undefined) { - // Use global regex to replace all occurrences - const regex = new RegExp(`\\{${variableName}\\}`, 'g'); - resolved = resolved.replace(regex, encodeURIComponent(value)); - } - } - - // Also try to resolve any unmapped variables directly from context - const remainingVariables = resolved.match(/\{([^}]+)\}/g); - if (remainingVariables) { - for (const variable of remainingVariables) { - const variableName = variable.slice(1, -1); // Remove { and } - const value = resolveVariablePath(context, variableName); - if (value !== undefined) { - resolved = resolved.replace(variable, encodeURIComponent(value)); - } - } - } - - return resolved; -} - /** * Generates a cache key for a schema based on the node context and endpoint configuration. * @@ -212,14 +104,7 @@ export async function fetchDynamicSchema( workflowId?: string ): Promise { // Build the context from the node - const context: NodeContext = { - id: node.id, - type: node.type, - metadata: node.data.metadata, - config: node.data.config, - extensions: node.data.extensions, - workflowId - }; + const context = buildNodeContext(node, workflowId); // Generate cache key const cacheKey = generateCacheKey(endpoint, context); @@ -394,14 +279,7 @@ export function resolveExternalEditUrl( callbackUrl?: string ): string { // Build the context from the node - const context: NodeContext = { - id: node.id, - type: node.type, - metadata: node.data.metadata, - config: node.data.config, - extensions: node.data.extensions, - workflowId - }; + const context = buildNodeContext(node, workflowId); // Resolve the URL with template variables let url = resolveTemplate(link.url, link.parameterMapping, context); @@ -489,14 +367,7 @@ export function clearSchemaCache(pattern?: string): void { * @param endpoint - The dynamic schema endpoint configuration */ export function invalidateSchemaCache(node: WorkflowNode, endpoint: DynamicSchemaEndpoint): void { - const context: NodeContext = { - id: node.id, - type: node.type, - metadata: node.data.metadata, - config: node.data.config, - extensions: node.data.extensions - }; - + const context = buildNodeContext(node); const cacheKey = generateCacheKey(endpoint, context); schemaCache.delete(cacheKey); } diff --git a/src/lib/services/optionsService.ts b/src/lib/services/optionsService.ts new file mode 100644 index 0000000..b090b42 --- /dev/null +++ b/src/lib/services/optionsService.ts @@ -0,0 +1,385 @@ +/** + * Options Service + * + * Handles fetching select field options from REST endpoints at runtime. + * Provides caching, parallel fetching, and response normalization. + * + * @module services/optionsService + */ + +import type { FieldOption } from '../components/form/types.js'; +import type { + OptionsEndpoint, + ConfigSchema, + ConfigProperty, + WorkflowNode +} from '../types/index.js'; +import { resolveTemplate, buildNodeContext } from '../utils/templateResolver.js'; +import { getEndpointConfig } from './api.js'; + +/** + * Result of fetching options for a single field + */ +export interface OptionsResult { + /** Whether the fetch was successful */ + success: boolean; + /** The fetched options (if successful) */ + options?: FieldOption[]; + /** Error message (if failed) */ + error?: string; + /** Whether the result was loaded from cache */ + fromCache?: boolean; +} + +/** + * Result of fetching options for all fields + */ +export interface AllOptionsResult { + /** Map of field key to fetched options */ + options: Map; + /** Map of field key to error message */ + errors: Map; +} + +/** + * Cache entry for storing fetched options + */ +interface OptionsCacheEntry { + options: FieldOption[]; + cachedAt: number; + cacheKey: string; +} + +/** Options cache with TTL support */ +const optionsCache = new Map(); + +/** Default cache TTL: 5 minutes */ +const DEFAULT_CACHE_TTL = 5 * 60 * 1000; + +/** Default request timeout: 10 seconds */ +const DEFAULT_TIMEOUT = 10000; + +/** + * Checks if a cached entry is still valid + */ +function isCacheValid(entry: OptionsCacheEntry, ttl: number): boolean { + return Date.now() - entry.cachedAt < ttl; +} + +/** + * Generates a cache key based on resolved URL + */ +function generateCacheKey(resolvedUrl: string): string { + return `options:${resolvedUrl}`; +} + +/** + * Extracts a value from an object using a path + */ +function extractValue(obj: Record, path: string): unknown { + const parts = path.split('.'); + let current: unknown = obj; + + for (const part of parts) { + if (current === null || current === undefined) { + return undefined; + } + if (typeof current === 'object' && part in current) { + current = (current as Record)[part]; + } else { + return undefined; + } + } + + return current; +} + +/** + * Normalizes API response to FieldOption array + */ +function normalizeOptions( + data: unknown, + valuePath: string = 'value', + labelPath: string = 'label' +): FieldOption[] { + // Handle wrapped response: { options: [...] } or { data: [...] } + let items: unknown[]; + if (Array.isArray(data)) { + items = data; + } else if (typeof data === 'object' && data !== null) { + const obj = data as Record; + if (Array.isArray(obj.options)) { + items = obj.options; + } else if (Array.isArray(obj.data)) { + items = obj.data; + } else { + return []; + } + } else { + return []; + } + + return items + .map((item) => { + if (typeof item !== 'object' || item === null) { + return null; + } + const obj = item as Record; + const value = extractValue(obj, valuePath); + const label = extractValue(obj, labelPath); + + if (value === undefined) { + return null; + } + + return { + value: String(value), + label: String(label ?? value) + }; + }) + .filter((opt): opt is FieldOption => opt !== null); +} + +/** + * Fetches options for a single field from a REST endpoint. + * + * @param endpoint - The options endpoint configuration + * @param node - The workflow node instance + * @param workflowId - Optional workflow ID for context + * @returns A promise that resolves to the options result + */ +export async function fetchFieldOptions( + endpoint: OptionsEndpoint, + node: WorkflowNode, + workflowId?: string +): Promise { + const context = buildNodeContext(node, workflowId); + const cacheTtl = endpoint.cacheTtl ?? DEFAULT_CACHE_TTL; + const timeout = endpoint.timeout ?? DEFAULT_TIMEOUT; + + // Resolve URL with template variables + let url = resolveTemplate(endpoint.url, endpoint.parameterMapping, context); + + // Prepend base URL for relative URLs + if (url.startsWith('/')) { + const currentConfig = getEndpointConfig(); + if (currentConfig?.baseUrl) { + const baseUrl = currentConfig.baseUrl.replace(/\/$/, ''); + url = `${baseUrl}${url}`; + } + } + + // Check cache + const cacheKey = generateCacheKey(url); + const cached = optionsCache.get(cacheKey); + if (cached && isCacheValid(cached, cacheTtl)) { + return { + success: true, + options: cached.options, + fromCache: true + }; + } + + // Prepare request + const method = endpoint.method ?? 'GET'; + const headers: Record = { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...endpoint.headers + }; + + // Add auth headers from endpoint config + const currentConfig = getEndpointConfig(); + if (currentConfig?.auth) { + if (currentConfig.auth.type === 'bearer' && currentConfig.auth.token) { + headers['Authorization'] = `Bearer ${currentConfig.auth.token}`; + } else if (currentConfig.auth.type === 'api_key' && currentConfig.auth.apiKey) { + headers['X-API-Key'] = currentConfig.auth.apiKey; + } else if (currentConfig.auth.type === 'custom' && currentConfig.auth.headers) { + Object.assign(headers, currentConfig.auth.headers); + } + } + + const fetchOptions: RequestInit = { + method, + headers, + signal: AbortSignal.timeout(timeout) + }; + + try { + const response = await fetch(url, fetchOptions); + + if (!response.ok) { + const errorText = await response.text(); + return { + success: false, + error: `HTTP ${response.status}: ${errorText || response.statusText}` + }; + } + + const data = await response.json(); + const options = normalizeOptions(data, endpoint.valuePath, endpoint.labelPath); + + // Cache the result + optionsCache.set(cacheKey, { + options, + cachedAt: Date.now(), + cacheKey + }); + + return { + success: true, + options, + fromCache: false + }; + } catch (error) { + if (error instanceof Error) { + if (error.name === 'AbortError' || error.name === 'TimeoutError') { + return { + success: false, + error: `Request timed out after ${timeout}ms` + }; + } + return { + success: false, + error: error.message + }; + } + return { + success: false, + error: 'Unknown error occurred while fetching options' + }; + } +} + +/** + * Checks if a schema has any fields with optionsEndpoint configured. + * + * @param schema - The config schema to check + * @returns True if any field has optionsEndpoint + */ +export function hasFieldsWithOptionsEndpoint(schema: ConfigSchema): boolean { + if (!schema.properties) { + return false; + } + + return Object.values(schema.properties).some( + (prop) => typeof prop === 'object' && prop !== null && 'optionsEndpoint' in prop + ); +} + +/** + * Fetches options for all fields with optionsEndpoint in a schema. + * Fetches are performed in parallel for efficiency. + * + * @param schema - The config schema + * @param node - The workflow node instance + * @param workflowId - Optional workflow ID for context + * @returns A promise with options and errors maps + */ +export async function fetchAllFieldOptions( + schema: ConfigSchema, + node: WorkflowNode, + workflowId?: string +): Promise { + const options = new Map(); + const errors = new Map(); + + if (!schema.properties) { + return { options, errors }; + } + + // Collect all fields with optionsEndpoint + const fieldsToFetch: Array<{ key: string; endpoint: OptionsEndpoint }> = []; + for (const [key, prop] of Object.entries(schema.properties)) { + if (typeof prop === 'object' && prop !== null && 'optionsEndpoint' in prop) { + const endpoint = prop.optionsEndpoint as OptionsEndpoint; + if (endpoint) { + fieldsToFetch.push({ key, endpoint }); + } + } + } + + // Fetch all in parallel + const results = await Promise.all( + fieldsToFetch.map(async ({ key, endpoint }) => { + const result = await fetchFieldOptions(endpoint, node, workflowId); + return { key, result }; + }) + ); + + // Collect results + for (const { key, result } of results) { + if (result.success && result.options) { + options.set(key, result.options); + } else if (result.error) { + errors.set(key, result.error); + } + } + + return { options, errors }; +} + +/** + * Merges fetched options into a schema, returning a new schema. + * Options are added to the `options` property of each field. + * + * @param schema - The original config schema + * @param fetchedOptions - Map of field key to options + * @returns A new schema with options merged in + */ +export function mergeOptionsIntoSchema( + schema: ConfigSchema, + fetchedOptions: Map +): ConfigSchema { + if (!schema.properties || fetchedOptions.size === 0) { + return schema; + } + + const newProperties: Record = {}; + + for (const [key, prop] of Object.entries(schema.properties)) { + const options = fetchedOptions.get(key); + if (options) { + // Clone the property and add options + newProperties[key] = { + ...prop, + options + } as ConfigProperty; + } else { + newProperties[key] = prop; + } + } + + return { + ...schema, + properties: newProperties + }; +} + +/** + * Clears the options cache. + * + * @param pattern - Optional pattern to match cache keys + */ +export function clearOptionsCache(pattern?: string): void { + if (!pattern) { + optionsCache.clear(); + return; + } + + for (const key of optionsCache.keys()) { + if (key.includes(pattern)) { + optionsCache.delete(key); + } + } +} + +/** + * Invalidates cache for a specific URL pattern. + * + * @param urlPattern - URL pattern to invalidate + */ +export function invalidateOptionsCache(urlPattern: string): void { + clearOptionsCache(urlPattern); +} diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts index 210d23f..87982a6 100644 --- a/src/lib/types/index.ts +++ b/src/lib/types/index.ts @@ -259,6 +259,69 @@ export interface DynamicSchemaEndpoint { cacheSchema?: boolean; } +/** + * Options endpoint configuration for fetching select field options at runtime. + * Used when field options need to be populated dynamically from a REST API. + * + * @example + * ```typescript + * const optionsEndpoint: OptionsEndpoint = { + * url: "/api/flowdrop/secrets", + * valuePath: "name", + * labelPath: "label", + * cacheTtl: 300000 + * }; + * ``` + */ +export interface OptionsEndpoint { + /** + * URL to fetch options from. + * Supports template variables: {nodeTypeId}, {instanceId}, {workflowId} + */ + url: string; + + /** + * HTTP method for the request. + * @default "GET" + */ + method?: HttpMethod; + + /** + * Custom headers to include in the request. + */ + headers?: Record; + + /** + * Maps template variables to their source paths in node context. + * Keys are variable names, values are dot-notation paths. + */ + parameterMapping?: Record; + + /** + * JSON path to extract the option value from each item. + * @default "value" + */ + valuePath?: string; + + /** + * JSON path to extract the option label from each item. + * @default "label" + */ + labelPath?: string; + + /** + * Cache TTL in milliseconds. + * @default 300000 (5 minutes) + */ + cacheTtl?: number; + + /** + * Request timeout in milliseconds. + * @default 10000 + */ + timeout?: number; +} + /** * External edit link configuration * Used when the node configuration should be handled by an external 3rd party form diff --git a/src/lib/utils/templateResolver.ts b/src/lib/utils/templateResolver.ts new file mode 100644 index 0000000..d5955f7 --- /dev/null +++ b/src/lib/utils/templateResolver.ts @@ -0,0 +1,123 @@ +/** + * Template Resolver Utility + * + * Provides URL template resolution for dynamic endpoints. + * Extracted from dynamicSchemaService for reuse across services. + * + * @module utils/templateResolver + */ + +import type { WorkflowNode } from '../types/index.js'; + +/** + * Context object containing all available data for resolving template variables + */ +export interface NodeContext { + /** Node instance ID */ + id: string; + /** Node type from xyflow */ + type: string; + /** Node metadata (id, name, type, category, etc.) */ + metadata: WorkflowNode['data']['metadata']; + /** Node configuration values */ + config: Record; + /** Node extensions */ + extensions?: WorkflowNode['data']['extensions']; + /** Current workflow ID (if available) */ + workflowId?: string; +} + +/** + * Resolves a template variable path from the node context. + * Supports dot-notation paths like "metadata.id", "config.apiKey", "id" + * + * @param context - The node context containing all available data + * @param path - Dot-notation path to resolve (e.g., "metadata.id") + * @returns The resolved value as a string, or undefined if not found + */ +export function resolveVariablePath( + context: Record, + path: string +): string | undefined { + const parts = path.split('.'); + let current: unknown = context; + + for (const part of parts) { + if (current === null || current === undefined) { + return undefined; + } + if (typeof current === 'object' && part in current) { + current = (current as Record)[part]; + } else { + return undefined; + } + } + + if (current === null || current === undefined) { + return undefined; + } + return String(current); +} + +/** + * Replaces template variables in a URL or string with values from the node context. + * Template variables use curly brace syntax: {variableName} + * + * @param template - The template string with variables + * @param parameterMapping - Maps variable names to context paths + * @param context - The node context containing all available data + * @returns The resolved string with all variables replaced + */ +export function resolveTemplate( + template: string, + parameterMapping: Record | undefined, + context: NodeContext +): string { + let resolved = template; + + // Cast context to Record for path resolution + const contextRecord = context as unknown as Record; + + // Replace each mapped variable + if (parameterMapping) { + for (const [variableName, contextPath] of Object.entries(parameterMapping)) { + const value = resolveVariablePath(contextRecord, contextPath); + if (value !== undefined) { + const regex = new RegExp(`\\{${variableName}\\}`, 'g'); + resolved = resolved.replace(regex, encodeURIComponent(value)); + } + } + } + + // Also try to resolve any unmapped variables directly from context + const remainingVariables = resolved.match(/\{([^}]+)\}/g); + if (remainingVariables) { + for (const variable of remainingVariables) { + const variableName = variable.slice(1, -1); + const value = resolveVariablePath(contextRecord, variableName); + if (value !== undefined) { + resolved = resolved.replace(variable, encodeURIComponent(value)); + } + } + } + + return resolved; +} + +/** + * Builds a NodeContext from a WorkflowNode. + * + * @param node - The workflow node + * @param workflowId - Optional workflow ID + * @returns The node context for template resolution + */ +export function buildNodeContext(node: WorkflowNode, workflowId?: string): NodeContext { + return { + id: node.id, + type: node.type, + metadata: node.data.metadata, + config: node.data.config, + extensions: node.data.extensions, + workflowId + }; +} diff --git a/tests/integration/optionsEndpoint.test.ts b/tests/integration/optionsEndpoint.test.ts new file mode 100644 index 0000000..2621050 --- /dev/null +++ b/tests/integration/optionsEndpoint.test.ts @@ -0,0 +1,309 @@ +/** + * Integration Tests - Options Endpoint Feature + * + * Tests the end-to-end flow of fetching field options from a REST endpoint + * and merging them into a config schema for form rendering. + */ + +import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; +import { + fetchAllFieldOptions, + mergeOptionsIntoSchema, + clearOptionsCache, + hasFieldsWithOptionsEndpoint +} from '$lib/services/optionsService.js'; +import { createTestNode, mockFetchResponse, mockFetchError } from '../utils/index.js'; +import type { ConfigSchema } from '$lib/types/index.js'; + +describe('Options Endpoint Integration', () => { + beforeEach(() => { + vi.clearAllMocks(); + clearOptionsCache(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('Full workflow: fetch options and merge into schema', () => { + it('should fetch options and merge into schema for form rendering', async () => { + // Mock API response with custom value/label paths + global.fetch = vi.fn(() => + Promise.resolve( + mockFetchResponse([ + { name: 'OPENAI_KEY', label: 'OpenAI Production Key' }, + { name: 'ANTHROPIC_KEY', label: 'Anthropic Claude Key' } + ]) + ) + ); + + // Schema with optionsEndpoint using custom paths + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { + type: 'string', + title: 'API Key', + optionsEndpoint: { + url: '/api/secrets', + valuePath: 'name', + labelPath: 'label' + } + }, + temperature: { + type: 'number', + title: 'Temperature', + minimum: 0, + maximum: 2 + } + } + }; + + const node = createTestNode(); + + // Verify schema has fields with optionsEndpoint + expect(hasFieldsWithOptionsEndpoint(schema)).toBe(true); + + // Fetch options + const result = await fetchAllFieldOptions(schema, node); + + // Verify options were fetched + expect(result.options.has('api_key')).toBe(true); + expect(result.errors.size).toBe(0); + expect(result.options.get('api_key')).toEqual([ + { value: 'OPENAI_KEY', label: 'OpenAI Production Key' }, + { value: 'ANTHROPIC_KEY', label: 'Anthropic Claude Key' } + ]); + + // Merge into schema + const enrichedSchema = mergeOptionsIntoSchema(schema, result.options); + + // Verify merged schema has options + expect(enrichedSchema.properties?.api_key?.options).toEqual([ + { value: 'OPENAI_KEY', label: 'OpenAI Production Key' }, + { value: 'ANTHROPIC_KEY', label: 'Anthropic Claude Key' } + ]); + + // Verify non-options fields are unchanged + expect(enrichedSchema.properties?.temperature?.minimum).toBe(0); + expect(enrichedSchema.properties?.temperature?.maximum).toBe(2); + expect(enrichedSchema.properties?.temperature?.options).toBeUndefined(); + }); + + it('should handle multiple fields with optionsEndpoint in parallel', async () => { + global.fetch = vi.fn((url: string) => { + if ((url as string).includes('secrets')) { + return Promise.resolve( + mockFetchResponse([ + { value: 'secret1', label: 'Secret 1' }, + { value: 'secret2', label: 'Secret 2' } + ]) + ); + } + if ((url as string).includes('models')) { + return Promise.resolve( + mockFetchResponse([ + { value: 'gpt-4', label: 'GPT-4' }, + { value: 'gpt-3.5', label: 'GPT-3.5 Turbo' } + ]) + ); + } + return Promise.resolve(mockFetchError('Not found', 404)); + }); + + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { + type: 'string', + title: 'API Key', + optionsEndpoint: { url: '/api/secrets' } + }, + model: { + type: 'string', + title: 'Model', + optionsEndpoint: { url: '/api/models' } + }, + static_field: { + type: 'string', + title: 'Static Field', + enum: ['a', 'b', 'c'] + } + } + }; + + const node = createTestNode(); + const result = await fetchAllFieldOptions(schema, node); + + // Both fields should have options + expect(result.options.has('api_key')).toBe(true); + expect(result.options.has('model')).toBe(true); + expect(result.errors.size).toBe(0); + + // Merge and verify + const enrichedSchema = mergeOptionsIntoSchema(schema, result.options); + + expect(enrichedSchema.properties?.api_key?.options).toHaveLength(2); + expect(enrichedSchema.properties?.model?.options).toHaveLength(2); + // Static enum should be preserved + expect(enrichedSchema.properties?.static_field?.enum).toEqual(['a', 'b', 'c']); + }); + }); + + describe('Error handling and fallback', () => { + it('should fall back gracefully on fetch error', async () => { + global.fetch = vi.fn(() => Promise.reject(new Error('Network error'))); + + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { + type: 'string', + title: 'API Key', + enum: ['default-key'], // Static fallback + optionsEndpoint: { url: '/api/secrets' } + } + } + }; + + const node = createTestNode(); + const result = await fetchAllFieldOptions(schema, node); + + // Should have error, no options + expect(result.errors.has('api_key')).toBe(true); + expect(result.options.has('api_key')).toBe(false); + + // Merge returns original schema when no options fetched + const enrichedSchema = mergeOptionsIntoSchema(schema, result.options); + // Original enum should be preserved as fallback + expect(enrichedSchema.properties?.api_key?.enum).toEqual(['default-key']); + }); + + it('should handle partial failures gracefully', async () => { + global.fetch = vi.fn((url: string) => { + if ((url as string).includes('secrets')) { + return Promise.resolve(mockFetchResponse([{ value: 'secret1', label: 'Secret 1' }])); + } + // Models endpoint fails + return Promise.resolve(mockFetchError('Server error', 500)); + }); + + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { + type: 'string', + optionsEndpoint: { url: '/api/secrets' } + }, + model: { + type: 'string', + optionsEndpoint: { url: '/api/models' } + } + } + }; + + const node = createTestNode(); + const result = await fetchAllFieldOptions(schema, node); + + // api_key succeeded, model failed + expect(result.options.has('api_key')).toBe(true); + expect(result.errors.has('model')).toBe(true); + expect(result.errors.get('model')).toContain('500'); + + // Merge should include successful options + const enrichedSchema = mergeOptionsIntoSchema(schema, result.options); + expect(enrichedSchema.properties?.api_key?.options).toBeDefined(); + expect(enrichedSchema.properties?.model?.options).toBeUndefined(); + }); + }); + + describe('Schema without optionsEndpoint', () => { + it('should skip fetching when no fields have optionsEndpoint', async () => { + global.fetch = vi.fn(); + + const schema: ConfigSchema = { + type: 'object', + properties: { + name: { type: 'string', title: 'Name' }, + count: { type: 'number', title: 'Count' }, + type: { + type: 'string', + title: 'Type', + enum: ['a', 'b', 'c'] + } + } + }; + + expect(hasFieldsWithOptionsEndpoint(schema)).toBe(false); + + const node = createTestNode(); + const result = await fetchAllFieldOptions(schema, node); + + // No fetches should occur + expect(global.fetch).not.toHaveBeenCalled(); + expect(result.options.size).toBe(0); + expect(result.errors.size).toBe(0); + + // Merge should return original schema unchanged + const enrichedSchema = mergeOptionsIntoSchema(schema, result.options); + expect(enrichedSchema).toEqual(schema); + }); + }); + + describe('Caching behavior', () => { + it('should use cached options on subsequent calls', async () => { + const mockData = [{ value: 'cached', label: 'Cached Option' }]; + global.fetch = vi.fn(() => Promise.resolve(mockFetchResponse(mockData))); + + const schema: ConfigSchema = { + type: 'object', + properties: { + field: { + type: 'string', + optionsEndpoint: { url: '/api/options' } + } + } + }; + + const node = createTestNode(); + + // First call + await fetchAllFieldOptions(schema, node); + expect(global.fetch).toHaveBeenCalledTimes(1); + + // Second call should use cache + const result = await fetchAllFieldOptions(schema, node); + expect(global.fetch).toHaveBeenCalledTimes(1); // Still 1 + + expect(result.options.get('field')).toEqual([{ value: 'cached', label: 'Cached Option' }]); + }); + + it('should refresh after cache is cleared', async () => { + const mockData = [{ value: 'fresh', label: 'Fresh Option' }]; + global.fetch = vi.fn(() => Promise.resolve(mockFetchResponse(mockData))); + + const schema: ConfigSchema = { + type: 'object', + properties: { + field: { + type: 'string', + optionsEndpoint: { url: '/api/options' } + } + } + }; + + const node = createTestNode(); + + // First call + await fetchAllFieldOptions(schema, node); + expect(global.fetch).toHaveBeenCalledTimes(1); + + // Clear cache + clearOptionsCache(); + + // Second call should fetch again + await fetchAllFieldOptions(schema, node); + expect(global.fetch).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/tests/unit/services/optionsService.test.ts b/tests/unit/services/optionsService.test.ts new file mode 100644 index 0000000..22e6359 --- /dev/null +++ b/tests/unit/services/optionsService.test.ts @@ -0,0 +1,417 @@ +/** + * Unit Tests - Options Service + */ + +import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; +import { + fetchFieldOptions, + fetchAllFieldOptions, + hasFieldsWithOptionsEndpoint, + mergeOptionsIntoSchema, + clearOptionsCache +} from '$lib/services/optionsService.js'; +import { createTestNode } from '../../utils/index.js'; +import type { ConfigSchema, OptionsEndpoint } from '$lib/types/index.js'; + +describe('optionsService', () => { + beforeEach(() => { + vi.clearAllMocks(); + clearOptionsCache(); + global.fetch = vi.fn(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('fetchFieldOptions', () => { + it('should fetch and normalize options with default paths', async () => { + const mockData = [ + { value: 'opt1', label: 'Option 1' }, + { value: 'opt2', label: 'Option 2' } + ]; + global.fetch = vi.fn(() => + Promise.resolve({ + ok: true, + status: 200, + json: async () => mockData, + text: async () => JSON.stringify(mockData) + } as Response) + ); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(true); + expect(result.options).toEqual([ + { value: 'opt1', label: 'Option 1' }, + { value: 'opt2', label: 'Option 2' } + ]); + }); + + it('should normalize options with custom valuePath and labelPath', async () => { + const mockData = [ + { name: 'KEY_1', description: 'First Key' }, + { name: 'KEY_2', description: 'Second Key' } + ]; + global.fetch = vi.fn(() => + Promise.resolve({ + ok: true, + status: 200, + json: async () => mockData, + text: async () => JSON.stringify(mockData) + } as Response) + ); + + const endpoint: OptionsEndpoint = { + url: '/api/secrets', + valuePath: 'name', + labelPath: 'description' + }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(true); + expect(result.options).toEqual([ + { value: 'KEY_1', label: 'First Key' }, + { value: 'KEY_2', label: 'Second Key' } + ]); + }); + + it('should handle wrapped response format with options key', async () => { + const mockData = { + options: [ + { value: 'a', label: 'A' }, + { value: 'b', label: 'B' } + ] + }; + global.fetch = vi.fn(() => + Promise.resolve({ + ok: true, + status: 200, + json: async () => mockData, + text: async () => JSON.stringify(mockData) + } as Response) + ); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(true); + expect(result.options).toHaveLength(2); + expect(result.options).toEqual([ + { value: 'a', label: 'A' }, + { value: 'b', label: 'B' } + ]); + }); + + it('should handle wrapped response format with data key', async () => { + const mockData = { + data: [ + { value: 'x', label: 'X' }, + { value: 'y', label: 'Y' } + ] + }; + global.fetch = vi.fn(() => + Promise.resolve({ + ok: true, + status: 200, + json: async () => mockData, + text: async () => JSON.stringify(mockData) + } as Response) + ); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(true); + expect(result.options).toHaveLength(2); + }); + + it('should return error on fetch failure', async () => { + global.fetch = vi.fn(() => + Promise.resolve({ + ok: false, + status: 404, + statusText: 'Not Found', + text: async () => 'Not found', + json: async () => ({ error: 'Not found' }) + } as Response) + ); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(false); + expect(result.error).toContain('404'); + }); + + it('should cache results', async () => { + const mockData = [{ value: 'cached', label: 'Cached' }]; + global.fetch = vi.fn(() => + Promise.resolve({ + ok: true, + status: 200, + json: async () => mockData, + text: async () => JSON.stringify(mockData) + } as Response) + ); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + // First call + await fetchFieldOptions(endpoint, node); + // Second call + const result = await fetchFieldOptions(endpoint, node); + + expect(global.fetch).toHaveBeenCalledTimes(1); + expect(result.fromCache).toBe(true); + }); + + it('should use label as value when label is undefined', async () => { + const mockData = [{ value: 'only-value' }]; + global.fetch = vi.fn(() => + Promise.resolve({ + ok: true, + status: 200, + json: async () => mockData, + text: async () => JSON.stringify(mockData) + } as Response) + ); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + const result = await fetchFieldOptions(endpoint, node); + + expect(result.success).toBe(true); + expect(result.options).toEqual([{ value: 'only-value', label: 'only-value' }]); + }); + }); + + describe('hasFieldsWithOptionsEndpoint', () => { + it('should return true when schema has fields with optionsEndpoint', () => { + const schema: ConfigSchema = { + type: 'object', + properties: { + field1: { type: 'string' }, + field2: { type: 'string', optionsEndpoint: { url: '/api/options' } } + } + }; + + expect(hasFieldsWithOptionsEndpoint(schema)).toBe(true); + }); + + it('should return false when no fields have optionsEndpoint', () => { + const schema: ConfigSchema = { + type: 'object', + properties: { + field1: { type: 'string' }, + field2: { type: 'string', enum: ['a', 'b'] } + } + }; + + expect(hasFieldsWithOptionsEndpoint(schema)).toBe(false); + }); + + it('should return false when schema has no properties', () => { + const schema: ConfigSchema = { + type: 'object' + }; + + expect(hasFieldsWithOptionsEndpoint(schema)).toBe(false); + }); + }); + + describe('mergeOptionsIntoSchema', () => { + it('should merge fetched options into schema fields', () => { + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { + type: 'string', + title: 'API Key', + optionsEndpoint: { url: '/api/secrets' } + }, + model: { + type: 'string', + enum: ['gpt-4', 'gpt-3.5'] + } + } + }; + + const options = new Map([ + [ + 'api_key', + [ + { value: 'KEY_1', label: 'Key 1' }, + { value: 'KEY_2', label: 'Key 2' } + ] + ] + ]); + + const result = mergeOptionsIntoSchema(schema, options); + + expect(result.properties?.api_key?.options).toEqual([ + { value: 'KEY_1', label: 'Key 1' }, + { value: 'KEY_2', label: 'Key 2' } + ]); + // Original enum should be unchanged + expect(result.properties?.model?.enum).toEqual(['gpt-4', 'gpt-3.5']); + }); + + it('should return original schema when no options to merge', () => { + const schema: ConfigSchema = { + type: 'object', + properties: { + field1: { type: 'string' } + } + }; + + const options = new Map(); + + const result = mergeOptionsIntoSchema(schema, options); + + expect(result).toBe(schema); + }); + + it('should return original schema when no properties', () => { + const schema: ConfigSchema = { + type: 'object' + }; + + const options = new Map([['field1', [{ value: 'a', label: 'A' }]]]); + + const result = mergeOptionsIntoSchema(schema, options); + + expect(result).toBe(schema); + }); + }); + + describe('fetchAllFieldOptions', () => { + it('should fetch options for all fields in parallel', async () => { + global.fetch = vi.fn((url: string) => { + if (url.includes('secrets')) { + return Promise.resolve({ + ok: true, + status: 200, + json: async () => [{ value: 'secret1', label: 'Secret 1' }], + text: async () => JSON.stringify([{ value: 'secret1', label: 'Secret 1' }]) + } as Response); + } + if (url.includes('models')) { + return Promise.resolve({ + ok: true, + status: 200, + json: async () => [{ value: 'gpt-4', label: 'GPT-4' }], + text: async () => JSON.stringify([{ value: 'gpt-4', label: 'GPT-4' }]) + } as Response); + } + return Promise.resolve({ + ok: false, + status: 404, + statusText: 'Not Found', + text: async () => 'Not found' + } as Response); + }); + + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { type: 'string', optionsEndpoint: { url: '/api/secrets' } }, + model: { type: 'string', optionsEndpoint: { url: '/api/models' } } + } + }; + const node = createTestNode(); + + const result = await fetchAllFieldOptions(schema, node); + + expect(result.options.get('api_key')).toEqual([{ value: 'secret1', label: 'Secret 1' }]); + expect(result.options.get('model')).toEqual([{ value: 'gpt-4', label: 'GPT-4' }]); + expect(result.errors.size).toBe(0); + }); + + it('should collect errors for failed fetches', async () => { + global.fetch = vi.fn((url: string) => { + if (url.includes('secrets')) { + return Promise.resolve({ + ok: true, + status: 200, + json: async () => [{ value: 'secret1', label: 'Secret 1' }], + text: async () => JSON.stringify([{ value: 'secret1', label: 'Secret 1' }]) + } as Response); + } + return Promise.resolve({ + ok: false, + status: 500, + statusText: 'Server Error', + text: async () => 'Server error' + } as Response); + }); + + const schema: ConfigSchema = { + type: 'object', + properties: { + api_key: { type: 'string', optionsEndpoint: { url: '/api/secrets' } }, + model: { type: 'string', optionsEndpoint: { url: '/api/models' } } + } + }; + const node = createTestNode(); + + const result = await fetchAllFieldOptions(schema, node); + + expect(result.options.get('api_key')).toBeDefined(); + expect(result.errors.get('model')).toContain('500'); + }); + + it('should return empty maps when schema has no properties', async () => { + const schema: ConfigSchema = { + type: 'object' + }; + const node = createTestNode(); + + const result = await fetchAllFieldOptions(schema, node); + + expect(result.options.size).toBe(0); + expect(result.errors.size).toBe(0); + }); + }); + + describe('clearOptionsCache', () => { + it('should clear all cache when no pattern provided', async () => { + const mockData = [{ value: 'test', label: 'Test' }]; + global.fetch = vi.fn(() => + Promise.resolve({ + ok: true, + status: 200, + json: async () => mockData, + text: async () => JSON.stringify(mockData) + } as Response) + ); + + const endpoint: OptionsEndpoint = { url: '/api/options' }; + const node = createTestNode(); + + // Populate cache + await fetchFieldOptions(endpoint, node); + expect(global.fetch).toHaveBeenCalledTimes(1); + + // Clear cache + clearOptionsCache(); + + // Should fetch again + await fetchFieldOptions(endpoint, node); + expect(global.fetch).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/tests/unit/utils/templateResolver.test.ts b/tests/unit/utils/templateResolver.test.ts new file mode 100644 index 0000000..5264c7a --- /dev/null +++ b/tests/unit/utils/templateResolver.test.ts @@ -0,0 +1,162 @@ +/** + * Unit Tests - Template Resolver Utility + */ + +import { describe, it, expect } from 'vitest'; +import { + resolveVariablePath, + resolveTemplate, + buildNodeContext +} from '$lib/utils/templateResolver.js'; +import { createTestNode } from '../../utils/index.js'; + +describe('templateResolver', () => { + describe('resolveVariablePath', () => { + it('should resolve top-level properties', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node', name: 'LLM' }, + config: {} + }; + + expect(resolveVariablePath(context, 'id')).toBe('node-123'); + expect(resolveVariablePath(context, 'type')).toBe('default'); + }); + + it('should resolve nested properties with dot notation', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node', name: 'LLM Node' }, + config: { apiKey: 'secret-key' } + }; + + expect(resolveVariablePath(context, 'metadata.id')).toBe('llm-node'); + expect(resolveVariablePath(context, 'metadata.name')).toBe('LLM Node'); + expect(resolveVariablePath(context, 'config.apiKey')).toBe('secret-key'); + }); + + it('should return undefined for non-existent paths', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node' }, + config: {} + }; + + expect(resolveVariablePath(context, 'nonexistent')).toBeUndefined(); + expect(resolveVariablePath(context, 'metadata.nonexistent')).toBeUndefined(); + }); + + it('should handle null values in path', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: null, + config: {} + }; + + expect(resolveVariablePath(context, 'metadata.id')).toBeUndefined(); + }); + }); + + describe('resolveTemplate', () => { + it('should replace variables with mapped values', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node', name: 'LLM', description: 'test', category: 'ai', version: '1.0', inputs: [], outputs: [] }, + config: {} + }; + const mapping = { nodeTypeId: 'metadata.id', instanceId: 'id' }; + + const result = resolveTemplate( + '/api/nodes/{nodeTypeId}/options/{instanceId}', + mapping, + context + ); + + expect(result).toBe('/api/nodes/llm-node/options/node-123'); + }); + + it('should URL-encode values', () => { + const context = { + id: 'node with spaces', + type: 'default', + metadata: { id: 'special/chars', name: 'test', description: 'test', category: 'ai', version: '1.0', inputs: [], outputs: [] }, + config: {} + }; + + const result = resolveTemplate('/api/{id}', { id: 'id' }, context); + + expect(result).toBe('/api/node%20with%20spaces'); + }); + + it('should resolve unmapped variables directly from context', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node', name: 'test', description: 'test', category: 'ai', version: '1.0', inputs: [], outputs: [] }, + config: {}, + workflowId: 'workflow-456' + }; + + const result = resolveTemplate('/api/{workflowId}/nodes', undefined, context); + + expect(result).toBe('/api/workflow-456/nodes'); + }); + + it('should leave unresolved variables in place', () => { + const context = { + id: 'node-123', + type: 'default', + metadata: { id: 'llm-node', name: 'test', description: 'test', category: 'ai', version: '1.0', inputs: [], outputs: [] }, + config: {} + }; + + const result = resolveTemplate('/api/{unknown}/nodes', undefined, context); + + expect(result).toBe('/api/{unknown}/nodes'); + }); + }); + + describe('buildNodeContext', () => { + it('should build context from WorkflowNode', () => { + const node = createTestNode({ + id: 'test-node-1', + type: 'simple', + data: { + label: 'Test', + config: { setting: 'value' }, + metadata: { + id: 'test_node', + name: 'Test Node', + description: 'A test node', + category: 'processing', + version: '1.0.0', + inputs: [], + outputs: [] + } + } + }); + + const context = buildNodeContext(node, 'workflow-123'); + + expect(context.id).toBe('test-node-1'); + expect(context.type).toBe('simple'); + expect(context.metadata.id).toBe('test_node'); + expect(context.config.setting).toBe('value'); + expect(context.workflowId).toBe('workflow-123'); + }); + + it('should work without workflowId', () => { + const node = createTestNode({ id: 'node-1' }); + + const context = buildNodeContext(node); + + expect(context.id).toBe('node-1'); + expect(context.workflowId).toBeUndefined(); + }); + }); +});